mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 10:20:44 +00:00
parent
50210d90e3
commit
cc2109342c
11 changed files with 323 additions and 8 deletions
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import "math/big"
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
// Common big integers often used
|
// Common big integers often used
|
||||||
var (
|
var (
|
||||||
|
|
@ -27,4 +31,6 @@ var (
|
||||||
Big32 = big.NewInt(32)
|
Big32 = big.NewInt(32)
|
||||||
Big256 = big.NewInt(256)
|
Big256 = big.NewInt(256)
|
||||||
Big257 = big.NewInt(257)
|
Big257 = big.NewInt(257)
|
||||||
|
|
||||||
|
U2560 = uint256.NewInt(0)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
if b.header.Time <= b.parent.Header().Time {
|
if b.header.Time <= b.parent.Header().Time {
|
||||||
panic("block time out of range")
|
panic("block time out of range")
|
||||||
}
|
}
|
||||||
chainReader := &fakeChainReader{config: b.config}
|
chainReader := &fakeChainReader{config: b.config, engine: b.engine}
|
||||||
b.header.Difficulty = b.engine.CalcDifficulty(chainReader, b.header.Time, b.parent.Header())
|
b.header.Difficulty = b.engine.CalcDifficulty(chainReader, b.header.Time, b.parent.Header())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +214,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
config = params.TestChainConfig
|
config = params.TestChainConfig
|
||||||
}
|
}
|
||||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
chainReader := &fakeChainReader{config: config}
|
chainReader := &fakeChainReader{config: config, engine: engine}
|
||||||
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||||
b := &BlockGen{i: i, parent: parent, chain: blocks, statedb: statedb, config: config, engine: engine}
|
b := &BlockGen{i: i, parent: parent, chain: blocks, statedb: statedb, config: config, engine: engine}
|
||||||
b.header = makeHeader(chainReader, parent, statedb, b.engine)
|
b.header = makeHeader(chainReader, parent, statedb, b.engine)
|
||||||
|
|
@ -231,10 +231,19 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
||||||
misc.ApplyDAOHardFork(statedb)
|
misc.ApplyDAOHardFork(statedb)
|
||||||
}
|
}
|
||||||
// Execute any user modifications to the block and finalize it
|
|
||||||
|
if config.IsPrague(b.header.Number) {
|
||||||
|
// EIP-2935
|
||||||
|
blockContext := NewEVMBlockContext(b.header, chainReader, &b.header.Coinbase)
|
||||||
|
evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, config, vm.Config{})
|
||||||
|
ProcessParentBlockHash(b.header.ParentHash, evm, statedb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute any user modifications to the block
|
||||||
if gen != nil {
|
if gen != nil {
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.engine != nil {
|
if b.engine != nil {
|
||||||
// Finalize and seal the block
|
// Finalize and seal the block
|
||||||
block, _ := b.engine.Finalize(chainReader, b.header, statedb, statedb.Copy(), b.txs, b.uncles, b.receipts)
|
block, _ := b.engine.Finalize(chainReader, b.header, statedb, statedb.Copy(), b.txs, b.uncles, b.receipts)
|
||||||
|
|
@ -323,6 +332,7 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd
|
||||||
|
|
||||||
type fakeChainReader struct {
|
type fakeChainReader struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
|
engine consensus.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config returns the chain configuration.
|
// Config returns the chain configuration.
|
||||||
|
|
@ -330,6 +340,7 @@ func (cr *fakeChainReader) Config() *params.ChainConfig {
|
||||||
return cr.config
|
return cr.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cr *fakeChainReader) Engine() consensus.Engine { return cr.engine }
|
||||||
func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil }
|
func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil }
|
||||||
func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil }
|
func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil }
|
||||||
func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil }
|
func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil }
|
||||||
|
|
|
||||||
|
|
@ -465,8 +465,7 @@ func DefaultDevnetGenesisBlock() *Genesis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must
|
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
|
||||||
// be seeded with the
|
|
||||||
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||||
// Override the default period to the user requested one
|
// Override the default period to the user requested one
|
||||||
config := *params.AllXDPoSProtocolChanges
|
config := *params.AllXDPoSProtocolChanges
|
||||||
|
|
@ -489,6 +488,8 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||||
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
|
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
|
||||||
|
// Pre-deploy system contracts
|
||||||
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -100,6 +102,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
|
||||||
signer := types.MakeSigner(p.config, blockNumber)
|
signer := types.MakeSigner(p.config, blockNumber)
|
||||||
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
|
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
|
||||||
|
|
||||||
|
if p.config.IsPrague(block.Number()) {
|
||||||
|
ProcessParentBlockHash(block.ParentHash(), vmenv, tracingStateDB)
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// check denylist txs after hf
|
// check denylist txs after hf
|
||||||
|
|
@ -203,6 +209,10 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
|
||||||
signer := types.MakeSigner(p.config, blockNumber)
|
signer := types.MakeSigner(p.config, blockNumber)
|
||||||
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
|
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
|
||||||
|
|
||||||
|
if p.config.IsPrague(block.Number()) {
|
||||||
|
ProcessParentBlockHash(block.ParentHash(), vmenv, tracingStateDB)
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
receipts = make([]*types.Receipt, block.Transactions().Len())
|
receipts = make([]*types.Receipt, block.Transactions().Len())
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
|
@ -639,3 +649,95 @@ func InitSignerInTransactions(config *params.ChainConfig, header *types.Header,
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessParentBlockHash writes the parent hash to the EIP-2935 history contract
|
||||||
|
// and enforces the expected code, with a one-time Prague backfill if missing.
|
||||||
|
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.StateDB) {
|
||||||
|
// Verify history contract code matches the expected bytecode
|
||||||
|
code := statedb.GetCode(params.HistoryStorageAddress)
|
||||||
|
if len(code) > 0 && !bytes.Equal(code, params.HistoryStorageCode) {
|
||||||
|
log.Error("History storage code mismatch",
|
||||||
|
"have", crypto.Keccak256Hash(code),
|
||||||
|
"want", crypto.Keccak256Hash(params.HistoryStorageCode),
|
||||||
|
)
|
||||||
|
panic("history storage code mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
|
blockNumber := vmenv.Context.BlockNumber
|
||||||
|
if blockNumber == nil || !vmenv.ChainConfig().IsPrague(blockNumber) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
forkBlock := vmenv.ChainConfig().PragueBlock
|
||||||
|
if forkBlock == nil {
|
||||||
|
forkBlock = common.PragueBlock
|
||||||
|
}
|
||||||
|
if forkBlock == nil || blockNumber.Cmp(forkBlock) < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only deploy and backfill if the contract is missing at/after Prague activation.
|
||||||
|
if len(code) == 0 {
|
||||||
|
if !statedb.Exist(params.HistoryStorageAddress) {
|
||||||
|
statedb.CreateAccount(params.HistoryStorageAddress)
|
||||||
|
}
|
||||||
|
if statedb.GetNonce(params.HistoryStorageAddress) == 0 {
|
||||||
|
statedb.SetNonce(params.HistoryStorageAddress, 1)
|
||||||
|
}
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
|
||||||
|
|
||||||
|
if blockNumber.Sign() > 0 {
|
||||||
|
end := blockNumber.Uint64() - 1
|
||||||
|
start := end
|
||||||
|
if end+1 > params.HistoryServeWindow {
|
||||||
|
start = end + 1 - params.HistoryServeWindow
|
||||||
|
}
|
||||||
|
if forkBlock.Sign() > 0 {
|
||||||
|
forkStart := forkBlock.Uint64() - 1
|
||||||
|
if forkStart > start {
|
||||||
|
start = forkStart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for n := start; n <= end; n++ {
|
||||||
|
hash := vmenv.Context.GetHash(n)
|
||||||
|
if hash == (common.Hash{}) {
|
||||||
|
log.Debug("History backfill missing hash", "number", n)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
statedb.SetState(params.HistoryStorageAddress, historyStorageKey(n), hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
|
if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &Message{
|
||||||
|
From: params.SystemAddress,
|
||||||
|
GasLimit: 30_000_000,
|
||||||
|
GasPrice: common.Big0,
|
||||||
|
GasFeeCap: common.Big0,
|
||||||
|
GasTipCap: common.Big0,
|
||||||
|
To: ¶ms.HistoryStorageAddress,
|
||||||
|
Data: prevHash.Bytes(),
|
||||||
|
}
|
||||||
|
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||||
|
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
|
||||||
|
_, _, err := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
statedb.Finalise(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func historyStorageKey(number uint64) common.Hash {
|
||||||
|
ringIndex := number % params.HistoryServeWindow
|
||||||
|
var key common.Hash
|
||||||
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"encoding/binary"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -26,10 +27,12 @@ import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/tracing"
|
"github.com/XinFinOrg/XDPoSChain/core/tracing"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
"github.com/XinFinOrg/XDPoSChain/trie"
|
"github.com/XinFinOrg/XDPoSChain/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -318,7 +321,7 @@ func GenerateBadBlock(t *testing.T, parent *types.Block, engine consensus.Engine
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{
|
Difficulty: engine.CalcDifficulty(&fakeChainReader{config: config, engine: engine}, parent.Time()+10, &types.Header{
|
||||||
Number: parent.Number(),
|
Number: parent.Number(),
|
||||||
Time: parent.Time(),
|
Time: parent.Time(),
|
||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
|
|
@ -489,3 +492,146 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHash(t *testing.T) {
|
||||||
|
var (
|
||||||
|
chainConfig = params.MergedTestChainConfig
|
||||||
|
hashA = common.Hash{0x01}
|
||||||
|
hashB = common.Hash{0x02}
|
||||||
|
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
|
||||||
|
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
|
||||||
|
coinbase = common.Address{}
|
||||||
|
)
|
||||||
|
test := func(statedb *state.StateDB) {
|
||||||
|
statedb.SetNonce(params.HistoryStorageAddress, 1)
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
|
||||||
|
statedb.IntermediateRoot(true)
|
||||||
|
|
||||||
|
vmContext := NewEVMBlockContext(header, nil, &coinbase)
|
||||||
|
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(header.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
vmContext = NewEVMBlockContext(parent, nil, &coinbase)
|
||||||
|
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
// make sure that the state is correct
|
||||||
|
if have := getParentBlockHash(statedb, 1); have != hashA {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashA, have)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 0); have != hashB {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashB, have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Run("MPT", func(t *testing.T) {
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())))
|
||||||
|
test(statedb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHashPragueGuard(t *testing.T) {
|
||||||
|
config := *params.MergedTestChainConfig
|
||||||
|
config.PragueBlock = big.NewInt(10)
|
||||||
|
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())))
|
||||||
|
blockNumber := big.NewInt(5)
|
||||||
|
random := common.Hash{}
|
||||||
|
blockContext := vm.BlockContext{
|
||||||
|
CanTransfer: CanTransfer,
|
||||||
|
Transfer: Transfer,
|
||||||
|
GetHash: func(uint64) common.Hash { return common.Hash{} },
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
Time: 0,
|
||||||
|
Difficulty: big.NewInt(0),
|
||||||
|
GasLimit: 0,
|
||||||
|
BaseFee: nil,
|
||||||
|
Random: &random,
|
||||||
|
}
|
||||||
|
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{})
|
||||||
|
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb)
|
||||||
|
|
||||||
|
if code := statedb.GetCode(params.HistoryStorageAddress); len(code) != 0 {
|
||||||
|
t.Fatalf("unexpected history contract code predeploy: %x", code)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 0); have != (common.Hash{}) {
|
||||||
|
t.Fatalf("expected empty history slot, have %v", have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHashBackfillMissingHistory(t *testing.T) {
|
||||||
|
config := *params.MergedTestChainConfig
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())))
|
||||||
|
blockNumber := big.NewInt(int64(params.HistoryServeWindow + 1))
|
||||||
|
available := map[uint64]common.Hash{
|
||||||
|
1: {0x11},
|
||||||
|
100: {0x22},
|
||||||
|
}
|
||||||
|
|
||||||
|
random := common.Hash{}
|
||||||
|
blockContext := vm.BlockContext{
|
||||||
|
CanTransfer: CanTransfer,
|
||||||
|
Transfer: Transfer,
|
||||||
|
GetHash: func(n uint64) common.Hash {
|
||||||
|
if hash, ok := available[n]; ok {
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
return common.Hash{}
|
||||||
|
},
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
Time: 0,
|
||||||
|
Difficulty: big.NewInt(0),
|
||||||
|
GasLimit: 0,
|
||||||
|
BaseFee: nil,
|
||||||
|
Random: &random,
|
||||||
|
}
|
||||||
|
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{})
|
||||||
|
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb)
|
||||||
|
|
||||||
|
if have := getParentBlockHash(statedb, 1); have != available[1] {
|
||||||
|
t.Fatalf("expected hash at slot 1, have %v", have)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 100); have != available[100] {
|
||||||
|
t.Fatalf("expected hash at slot 100, have %v", have)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 2); have != (common.Hash{}) {
|
||||||
|
t.Fatalf("expected empty history slot, have %v", have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHashCodeMismatchPanics(t *testing.T) {
|
||||||
|
config := *params.MergedTestChainConfig
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())))
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, []byte{0x01})
|
||||||
|
|
||||||
|
blockNumber := big.NewInt(1)
|
||||||
|
random := common.Hash{}
|
||||||
|
blockContext := vm.BlockContext{
|
||||||
|
CanTransfer: CanTransfer,
|
||||||
|
Transfer: Transfer,
|
||||||
|
GetHash: func(uint64) common.Hash { return common.Hash{} },
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
Time: 0,
|
||||||
|
Difficulty: big.NewInt(0),
|
||||||
|
GasLimit: 0,
|
||||||
|
BaseFee: nil,
|
||||||
|
Random: &random,
|
||||||
|
}
|
||||||
|
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{})
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
t.Fatal("expected panic on history storage code mismatch")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
|
||||||
|
ringIndex := number % params.HistoryServeWindow
|
||||||
|
var key common.Hash
|
||||||
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
|
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
- [Validator Contract](xdc/validator.md)
|
- [Validator Contract](xdc/validator.md)
|
||||||
- [Development environment](develop.md)
|
- [Development environment](develop.md)
|
||||||
- [Solidity](solidity.md)
|
- [Solidity](solidity.md)
|
||||||
|
- [Upgrade notes](upgrade.md)
|
||||||
|
|
|
||||||
8
docs/upgrade.md
Normal file
8
docs/upgrade.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Upgrade Notes
|
||||||
|
|
||||||
|
## Prague / EIP-2935
|
||||||
|
|
||||||
|
- The history storage contract is predeployed only in the developer genesis.
|
||||||
|
- For other networks, the contract is deployed at Prague activation by the system call during block processing and state access.
|
||||||
|
- Nodes upgrading after Prague will perform a one-time backfill of recent parent hashes into the ring buffer. If historical headers are pruned or unavailable, missing slots are skipped and only available hashes are filled.
|
||||||
|
- If you maintain a custom genesis and want predeployment, add an account entry for `HistoryStorageAddress` with `Nonce: 1` and `Code: HistoryStorageCode`.
|
||||||
|
|
@ -206,6 +206,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, err
|
return nil, vm.BlockContext{}, nil, nil, err
|
||||||
}
|
}
|
||||||
|
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
|
||||||
|
if eth.blockchain.Config().IsPrague(block.Number()) {
|
||||||
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, nil, eth.blockchain.Config(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||||
return nil, vm.BlockContext{}, statedb, release, nil
|
return nil, vm.BlockContext{}, statedb, release, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// Insert parent hash in history contract.
|
||||||
|
if api.backend.ChainConfig().IsPrague(next.Number()) {
|
||||||
|
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, nil, api.backend.ChainConfig(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
// Clean out any pending release functions of trace state. Note this
|
// Clean out any pending release functions of trace state. Note this
|
||||||
// step must be done after constructing tracing state, because the
|
// step must be done after constructing tracing state, because the
|
||||||
// tracing state of block next depends on the parent state and construction
|
// tracing state of block next depends on the parent state and construction
|
||||||
|
|
@ -513,6 +519,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
|
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
|
||||||
)
|
)
|
||||||
|
if chainConfig.IsPrague(block.Number()) {
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{}), statedb)
|
||||||
|
}
|
||||||
feeCapacity := statedb.GetTRC21FeeCapacityFromState()
|
feeCapacity := statedb.GetTRC21FeeCapacityFromState()
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
|
|
@ -593,6 +602,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||||
results = make([]*txTraceResult, len(txs))
|
results = make([]*txTraceResult, len(txs))
|
||||||
)
|
)
|
||||||
|
if api.backend.ChainConfig().IsPrague(block.Number()) {
|
||||||
|
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, nil, api.backend.ChainConfig(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
feeCapacity := statedb.GetTRC21FeeCapacityFromState()
|
feeCapacity := statedb.GetTRC21FeeCapacityFromState()
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
var balance *big.Int
|
var balance *big.Int
|
||||||
|
|
|
||||||
|
|
@ -787,6 +787,11 @@ func (w *worker) commitNewWork() {
|
||||||
if common.TIPSigning.Cmp(header.Number) == 0 {
|
if common.TIPSigning.Cmp(header.Number) == 0 {
|
||||||
work.state.DeleteAddress(common.BlockSignersBinary)
|
work.state.DeleteAddress(common.BlockSignersBinary)
|
||||||
}
|
}
|
||||||
|
if w.config.IsPrague(header.Number) {
|
||||||
|
context := core.NewEVMBlockContext(header, w.chain, nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, w.current.state, nil, w.config, vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(header.ParentHash, vmenv, w.current.state)
|
||||||
|
}
|
||||||
// won't grasp txs at checkpoint
|
// won't grasp txs at checkpoint
|
||||||
var (
|
var (
|
||||||
txs *transactionsByPriceAndNonce
|
txs *transactionsByPriceAndNonce
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import "math/big"
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
|
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
|
||||||
|
|
@ -160,6 +164,8 @@ const (
|
||||||
Bn256PairingBaseGasIstanbul uint64 = 45000 // Base price for an elliptic curve pairing check
|
Bn256PairingBaseGasIstanbul uint64 = 45000 // Base price for an elliptic curve pairing check
|
||||||
Bn256PairingPerPointGasByzantium uint64 = 80000 // Byzantium per-point price for an elliptic curve pairing check
|
Bn256PairingPerPointGasByzantium uint64 = 80000 // Byzantium per-point price for an elliptic curve pairing check
|
||||||
Bn256PairingPerPointGasIstanbul uint64 = 34000 // Per-point price for an elliptic curve pairing check
|
Bn256PairingPerPointGasIstanbul uint64 = 34000 // Per-point price for an elliptic curve pairing check
|
||||||
|
|
||||||
|
HistoryServeWindow = 8191 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -170,3 +176,13 @@ var (
|
||||||
|
|
||||||
TargetGasLimit uint64 = XDCGenesisGasLimit // The artificial target
|
TargetGasLimit uint64 = XDCGenesisGasLimit // The artificial target
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// System contracts.
|
||||||
|
var (
|
||||||
|
// SystemAddress is where the system-transaction is sent from as per EIP-2935
|
||||||
|
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
||||||
|
|
||||||
|
// EIP-2935 - Serve historical block hashes from state
|
||||||
|
HistoryStorageAddress = common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935")
|
||||||
|
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500")
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue