Skip to content

Commit 5349178

Browse files
authored
Merge pull request #7 from bttcprotocol/feat-update-code
update contract
2 parents d8f8a11 + de7157e commit 5349178

4 files changed

Lines changed: 149 additions & 2 deletions

File tree

consensus/bor/bor.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ func New(
267267
WithoutHeimdall: withoutHeimdall,
268268
}
269269

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

@@ -675,6 +682,11 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
675682
}
676683
}
677684

685+
if err = c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
686+
log.Error("Error changing contract code", "error", err)
687+
return
688+
}
689+
678690
// No block rewards in PoA, so the state remains as is and uncles are dropped
679691
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
680692
header.UncleHash = types.CalcUncleHash(nil)
@@ -684,6 +696,34 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
684696
bc.SetStateSync(stateSyncData)
685697
}
686698

699+
func decodeGenesisAlloc(i interface{}) (core.GenesisAlloc, error) {
700+
var alloc core.GenesisAlloc
701+
b, err := json.Marshal(i)
702+
if err != nil {
703+
return nil, err
704+
}
705+
if err := json.Unmarshal(b, &alloc); err != nil {
706+
return nil, err
707+
}
708+
return alloc, nil
709+
}
710+
711+
func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.StateDB) error {
712+
for blockNumber, genesisAlloc := range c.config.BlockAlloc {
713+
if blockNumber == strconv.FormatUint(headerNumber, 10) {
714+
allocs, err := decodeGenesisAlloc(genesisAlloc)
715+
if err != nil {
716+
return fmt.Errorf("failed to decode genesis alloc: %v", err)
717+
}
718+
for addr, account := range allocs {
719+
log.Info("change contract code", "address", addr)
720+
state.SetCode(addr, account.Code)
721+
}
722+
}
723+
}
724+
return nil
725+
}
726+
687727
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
688728
// nor block rewards given, and returns the final block.
689729
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) {
@@ -710,6 +750,11 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
710750
}
711751
}
712752

753+
if err := c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
754+
log.Error("Error changing contract code", "error", err)
755+
return nil, err
756+
}
757+
713758
// No block rewards in PoA, so the state remains as is and uncles are dropped
714759
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
715760
header.UncleHash = types.CalcUncleHash(nil)

consensus/bor/bor_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package bor
2+
3+
import (
4+
"math/big"
5+
"testing"
6+
7+
"github.com/ethereum/go-ethereum/common"
8+
"github.com/ethereum/go-ethereum/common/hexutil"
9+
"github.com/ethereum/go-ethereum/core"
10+
"github.com/ethereum/go-ethereum/core/rawdb"
11+
"github.com/ethereum/go-ethereum/core/state"
12+
"github.com/ethereum/go-ethereum/core/types"
13+
"github.com/ethereum/go-ethereum/core/vm"
14+
"github.com/ethereum/go-ethereum/params"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestGenesisContractChange(t *testing.T) {
19+
addr0 := common.Address{0x1}
20+
21+
b := &Bor{
22+
config: &params.BorConfig{
23+
Sprint: 10, // skip sprint transactions in sprint
24+
BlockAlloc: map[string]interface{}{
25+
// write as interface since that is how it is decoded in genesis
26+
"2": map[string]interface{}{
27+
addr0.Hex(): map[string]interface{}{
28+
"code": hexutil.Bytes{0x1, 0x2},
29+
"balance": "0",
30+
},
31+
},
32+
"4": map[string]interface{}{
33+
addr0.Hex(): map[string]interface{}{
34+
"code": hexutil.Bytes{0x1, 0x3},
35+
"balance": "0x1000",
36+
},
37+
},
38+
},
39+
},
40+
}
41+
42+
genspec := &core.Genesis{
43+
Alloc: map[common.Address]core.GenesisAccount{
44+
addr0: {
45+
Balance: big.NewInt(0),
46+
Code: []byte{0x1, 0x1},
47+
},
48+
},
49+
}
50+
51+
db := rawdb.NewMemoryDatabase()
52+
genesis := genspec.MustCommit(db)
53+
54+
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
55+
assert.NoError(t, err)
56+
57+
config := params.ChainConfig{}
58+
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil)
59+
assert.NoError(t, err)
60+
61+
addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
62+
h := &types.Header{
63+
ParentHash: root,
64+
Number: big.NewInt(num),
65+
}
66+
b.Finalize(chain, h, statedb, nil, nil)
67+
68+
// write state to database
69+
root, err := statedb.Commit(false)
70+
assert.NoError(t, err)
71+
assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
72+
73+
statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
74+
assert.NoError(t, err)
75+
76+
return root, statedb
77+
}
78+
79+
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
80+
81+
root := genesis.Root()
82+
83+
// code does not change
84+
root, statedb = addBlock(root, 1)
85+
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
86+
87+
// code changes 1st time
88+
root, statedb = addBlock(root, 2)
89+
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
90+
91+
// code same as 1st change
92+
root, statedb = addBlock(root, 3)
93+
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
94+
95+
// code changes 2nd time
96+
_, statedb = addBlock(root, 4)
97+
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})
98+
99+
// make sure balance change DOES NOT take effect
100+
assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
101+
}

params/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ type BorConfig struct {
350350
ValidatorContract string `json:"validatorContract"` // Validator set contract
351351
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
352352

353-
OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
353+
OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
354+
BlockAlloc map[string]interface{} `json:"blockAlloc"`
354355
}
355356

356357
// String implements the stringer interface, returning the consensus engine details.

params/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
const (
2424
VersionMajor = 1 // Major version component of the current release
2525
VersionMinor = 0 // Minor version component of the current release
26-
VersionPatch = 0 // Patch version component of the current release
26+
VersionPatch = 1 // Patch version component of the current release
2727
VersionMeta = "stable" // Version metadata to append to the version string
2828
)
2929

0 commit comments

Comments
 (0)