mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
generate empty blocks for gaps
This commit is contained in:
parent
8698221fae
commit
48ca188157
2 changed files with 131 additions and 16 deletions
|
|
@ -34,7 +34,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
@ -147,7 +146,13 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]simBloc
|
||||||
// Make sure the context is cancelled when the call has completed
|
// Make sure the context is cancelled when the call has completed
|
||||||
// this makes sure resources are cleaned up.
|
// this makes sure resources are cleaned up.
|
||||||
defer cancel()
|
defer cancel()
|
||||||
headers, err := makeHeaders(sim.b.ChainConfig(), blocks, sim.base)
|
|
||||||
|
var err error
|
||||||
|
blocks, err = sim.sanitizeBlockOrder(blocks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headers, err := sim.makeHeaders(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -392,27 +397,63 @@ func (sim *simulator) activePrecompiles(ctx context.Context, base *types.Header)
|
||||||
return vm.ActivePrecompiledContracts(rules).Copy()
|
return vm.ActivePrecompiledContracts(rules).Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeaders(config *params.ChainConfig, blocks []simBlock, base *types.Header) ([]*types.Header, error) {
|
// sanitizeBlockOrder iterates the blocks checking that block numbers
|
||||||
|
// are strictly increasing. When necessary it will generate empty blocks.
|
||||||
|
// It modifies the block's override object.
|
||||||
|
func (sim *simulator) sanitizeBlockOrder(blocks []simBlock) ([]simBlock, error) {
|
||||||
|
var (
|
||||||
|
res = make([]simBlock, 0, len(blocks))
|
||||||
|
base = sim.base
|
||||||
|
prevNumber = base.Number
|
||||||
|
)
|
||||||
|
for _, block := range blocks {
|
||||||
|
if block.BlockOverrides == nil {
|
||||||
|
block.BlockOverrides = new(BlockOverrides)
|
||||||
|
}
|
||||||
|
if block.BlockOverrides.Number == nil {
|
||||||
|
n := new(big.Int).Add(prevNumber, big.NewInt(1))
|
||||||
|
block.BlockOverrides.Number = (*hexutil.Big)(n)
|
||||||
|
}
|
||||||
|
diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber)
|
||||||
|
if diff.Cmp(common.Big0) <= 0 {
|
||||||
|
return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)}
|
||||||
|
}
|
||||||
|
if total := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), base.Number); total.Cmp(big.NewInt(maxSimulateBlocks)) > 0 {
|
||||||
|
return nil, &clientLimitExceededError{message: "too many blocks"}
|
||||||
|
}
|
||||||
|
if diff.Cmp(big.NewInt(1)) > 0 {
|
||||||
|
// Fill the gap with empty blocks.
|
||||||
|
gap := new(big.Int).Sub(diff, big.NewInt(1))
|
||||||
|
// Assign block number to the empty blocks.
|
||||||
|
for i := uint64(0); i < gap.Uint64(); i++ {
|
||||||
|
n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1)))
|
||||||
|
b := simBlock{BlockOverrides: &BlockOverrides{Number: (*hexutil.Big)(n)}}
|
||||||
|
res = append(res, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only append block after filling a potential gap.
|
||||||
|
prevNumber = block.BlockOverrides.Number.ToInt()
|
||||||
|
res = append(res, block)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeHeaders makes header object with preliminary fields based on a simulated block.
|
||||||
|
// Some fields have to be filled post-execution.
|
||||||
|
// It assumes blocks are in order and numbers have been validated.
|
||||||
|
func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
|
||||||
res := make([]*types.Header, len(blocks))
|
res := make([]*types.Header, len(blocks))
|
||||||
var (
|
var (
|
||||||
prevNumber = base.Number.Uint64()
|
config = sim.b.ChainConfig()
|
||||||
|
base = sim.base
|
||||||
prevTimestamp = base.Time
|
prevTimestamp = base.Time
|
||||||
header = base
|
header = base
|
||||||
)
|
)
|
||||||
for bi, block := range blocks {
|
for bi, block := range blocks {
|
||||||
overrides := new(BlockOverrides)
|
if block.BlockOverrides == nil || block.BlockOverrides.Number == nil {
|
||||||
if block.BlockOverrides != nil {
|
return nil, errors.New("empty block number")
|
||||||
overrides = block.BlockOverrides
|
|
||||||
}
|
}
|
||||||
// Sanitize block number and timestamp
|
overrides := block.BlockOverrides
|
||||||
if overrides.Number == nil {
|
|
||||||
n := new(big.Int).Add(big.NewInt(int64(prevNumber)), big.NewInt(1))
|
|
||||||
overrides.Number = (*hexutil.Big)(n)
|
|
||||||
} else if overrides.Number.ToInt().Uint64() <= prevNumber {
|
|
||||||
return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", overrides.Number.ToInt().Uint64(), prevNumber)}
|
|
||||||
}
|
|
||||||
prevNumber = overrides.Number.ToInt().Uint64()
|
|
||||||
|
|
||||||
if overrides.Time == nil {
|
if overrides.Time == nil {
|
||||||
t := prevTimestamp + 12
|
t := prevTimestamp + 12
|
||||||
overrides.Time = (*hexutil.Uint64)(&t)
|
overrides.Time = (*hexutil.Uint64)(&t)
|
||||||
|
|
|
||||||
74
internal/ethapi/simulate_test.go
Normal file
74
internal/ethapi/simulate_test.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package ethapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSimulateSanitizeBlockOrder(t *testing.T) {
|
||||||
|
for i, tc := range []struct {
|
||||||
|
baseNumber int
|
||||||
|
blocks []simBlock
|
||||||
|
expectedLen int
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
baseNumber: 10,
|
||||||
|
blocks: []simBlock{{}, {}, {}},
|
||||||
|
expectedLen: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
baseNumber: 10,
|
||||||
|
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {}},
|
||||||
|
expectedLen: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
baseNumber: 10,
|
||||||
|
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}},
|
||||||
|
expectedLen: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
baseNumber: 10,
|
||||||
|
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}},
|
||||||
|
err: "block numbers must be in order: 12 <= 13",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber))}}
|
||||||
|
res, err := sim.sanitizeBlockOrder(tc.blocks)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == tc.err {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
t.Fatalf("testcase %d: error mismatch. Want '%s', have '%s'", i, tc.err, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil && tc.err != "" {
|
||||||
|
t.Fatalf("testcase %d: expected err", i)
|
||||||
|
}
|
||||||
|
if len(res) != tc.expectedLen {
|
||||||
|
fmt.Printf("res: %v\n", res)
|
||||||
|
t.Errorf("testcase %d: mismatch number of blocks. Want %d, have %d", i, tc.expectedLen, len(res))
|
||||||
|
}
|
||||||
|
for bi, b := range res {
|
||||||
|
if b.BlockOverrides == nil {
|
||||||
|
t.Fatalf("testcase %d: block overrides nil", i)
|
||||||
|
}
|
||||||
|
if b.BlockOverrides.Number == nil {
|
||||||
|
t.Fatalf("testcase %d: block number not set", i)
|
||||||
|
}
|
||||||
|
want := tc.baseNumber + bi + 1
|
||||||
|
have := b.BlockOverrides.Number.ToInt().Uint64()
|
||||||
|
if uint64(want) != have {
|
||||||
|
t.Errorf("testcase %d: block number mismatch. Want %d, have %d", i, want, have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInt(n int64) *hexutil.Big {
|
||||||
|
return (*hexutil.Big)(big.NewInt(n))
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue