Skip to content

Commit

Permalink
Merge pull request #7 from bttcprotocol/feat-update-code
Browse files Browse the repository at this point in the history
update contract
  • Loading branch information
zhang0125 authored Dec 30, 2021
2 parents d8f8a11 + de7157e commit 5349178
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 2 deletions.
45 changes: 45 additions & 0 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,13 @@ func New(
WithoutHeimdall: withoutHeimdall,
}

// make sure we can decode all the GenesisAlloc in the BorConfig.
for key, genesisAlloc := range c.config.BlockAlloc {
if _, err := decodeGenesisAlloc(genesisAlloc); err != nil {
panic(fmt.Sprintf("BUG: Block alloc '%s' in genesis is not correct: %v", key, err))
}
}

return c
}

Expand Down Expand Up @@ -675,6 +682,11 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
}
}

if err = c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
log.Error("Error changing contract code", "error", err)
return
}

// No block rewards in PoA, so the state remains as is and uncles are dropped
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
header.UncleHash = types.CalcUncleHash(nil)
Expand All @@ -684,6 +696,34 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
bc.SetStateSync(stateSyncData)
}

func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
var alloc core.GenesisAlloc
b, err := json.Marshal(i)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &alloc); err != nil {
return nil, err
}
return alloc, nil
}

func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.StateDB) error {
for blockNumber, genesisAlloc := range c.config.BlockAlloc {
if blockNumber == strconv.FormatUint(headerNumber, 10) {
allocs, err := decodeGenesisAlloc(genesisAlloc)
if err != nil {
return fmt.Errorf("failed to decode genesis alloc: %v", err)
}
for addr, account := range allocs {
log.Info("change contract code", "address", addr)
state.SetCode(addr, account.Code)
}
}
}
return nil
}

// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block.
func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
Expand All @@ -710,6 +750,11 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
}
}

if err := c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
log.Error("Error changing contract code", "error", err)
return nil, err
}

// No block rewards in PoA, so the state remains as is and uncles are dropped
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
header.UncleHash = types.CalcUncleHash(nil)
Expand Down
101 changes: 101 additions & 0 deletions consensus/bor/bor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package bor

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/assert"
)

func TestGenesisContractChange(t *testing.T) {
addr0 := common.Address{0x1}

b := &Bor{
config: &params.BorConfig{
Sprint: 10, // skip sprint transactions in sprint
BlockAlloc: map[string]interface{}{
// write as interface since that is how it is decoded in genesis
"2": map[string]interface{}{
addr0.Hex(): map[string]interface{}{
"code": hexutil.Bytes{0x1, 0x2},
"balance": "0",
},
},
"4": map[string]interface{}{
addr0.Hex(): map[string]interface{}{
"code": hexutil.Bytes{0x1, 0x3},
"balance": "0x1000",
},
},
},
},
}

genspec := &core.Genesis{
Alloc: map[common.Address]core.GenesisAccount{
addr0: {
Balance: big.NewInt(0),
Code: []byte{0x1, 0x1},
},
},
}

db := rawdb.NewMemoryDatabase()
genesis := genspec.MustCommit(db)

statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
assert.NoError(t, err)

config := params.ChainConfig{}
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil)
assert.NoError(t, err)

addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
h := &types.Header{
ParentHash: root,
Number: big.NewInt(num),
}
b.Finalize(chain, h, statedb, nil, nil)

// write state to database
root, err := statedb.Commit(false)
assert.NoError(t, err)
assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))

statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
assert.NoError(t, err)

return root, statedb
}

assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})

root := genesis.Root()

// code does not change
root, statedb = addBlock(root, 1)
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})

// code changes 1st time
root, statedb = addBlock(root, 2)
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})

// code same as 1st change
root, statedb = addBlock(root, 3)
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})

// code changes 2nd time
_, statedb = addBlock(root, 4)
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})

// make sure balance change DOES NOT take effect
assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
}
3 changes: 2 additions & 1 deletion params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ type BorConfig struct {
ValidatorContract string `json:"validatorContract"` // Validator set contract
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract

OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
BlockAlloc map[string]interface{} `json:"blockAlloc"`
}

// String implements the stringer interface, returning the consensus engine details.
Expand Down
2 changes: 1 addition & 1 deletion params/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 0 // Minor version component of the current release
VersionPatch = 0 // Patch version component of the current release
VersionPatch = 1 // Patch version component of the current release
VersionMeta = "stable" // Version metadata to append to the version string
)

Expand Down

0 comments on commit 5349178

Please sign in to comment.