V0.2.12 candidate (#261)

* Fix ancient receipts

* bumped version to 0.2.11

* Genesis change fix (#252)

* read from genesis file

* add: set code in finalize and assemble

* new: storing data in bor config

* chg: remove unwanted code

* chg: refactor

* minor change

* add error states

* Fix small things

* Add test

* Add more coverage in genesis finalize test

* Ensure balance is not changed

* Add decode safe check

* Change bor config block alloc field name

* Remove block alloc values in blocks

* Add genesis alloc code change info logging

Co-authored-by: Ferran Borreguero <ferranbt@protonmail.com>

* add block alloc

* change block alloc

* remove byte array

* mainnet upgrade

Co-authored-by: Ferran Borreguero <ferranbt@protonmail.com>
Co-authored-by: Sandeep Sreenath <sandeep.sreenath@gmail.com>
Co-authored-by: Jaynti Kanani <jdkanani@gmail.com>
This commit is contained in:
Arpit Temani 2021-12-07 19:58:31 +05:30 committed by GitHub
parent b633382707
commit 39116e6cc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 171 additions and 2 deletions

View file

@ -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
}
@ -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)
@ -684,12 +696,41 @@ 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) {
stateSyncData := []*types.StateSyncData{}
headerNumber := header.Number.Uint64()
if headerNumber%c.config.Sprint == 0 {
cx := chainContext{Chain: chain, Bor: c}
@ -710,6 +751,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)

101
consensus/bor/bor_test.go Normal file
View file

@ -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))
}

View file

@ -214,6 +214,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override
if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, common.Hash{}, err
}
storedcfg := rawdb.ReadChainConfig(db, stored)
if storedcfg == nil {
log.Warn("Found genesis block without chain config")
@ -236,6 +237,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override
if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 {
return newcfg, stored, compatErr
}
rawdb.WriteChainConfig(db, stored, newcfg)
return newcfg, stored, nil
}
@ -279,6 +281,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
statedb.SetState(addr, key, value)
}
}
root := statedb.IntermediateRoot(false)
head := &types.Header{
Number: new(big.Int).SetUint64(g.Number),

File diff suppressed because one or more lines are too long

View file

@ -23,7 +23,7 @@ import (
const (
VersionMajor = 0 // Major version component of the current release
VersionMinor = 2 // Minor version component of the current release
VersionPatch = 10 // Patch version component of the current release
VersionPatch = 12 // Patch version component of the current release
VersionMeta = "stable" // Version metadata to append to the version string
)