move timestamp sanitization

This commit is contained in:
Sina Mahmoodi 2024-08-19 12:59:26 +02:00
parent 5f0fafd8e6
commit 73ff7e51f6
3 changed files with 86 additions and 46 deletions

View file

@ -1095,7 +1095,7 @@ func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
// MakeHeader returns a new header object with the overridden
// fields.
// Note: MakeHeader ignores blobGasPrice if set. That's because
// Note: MakeHeader ignores BlobBaseFee if set. That's because
// header has no such field.
func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header {
if o == nil {

View file

@ -42,6 +42,9 @@ const (
// maxSimulateBlocks is the maximum number of blocks that can be simulated
// in a single request.
maxSimulateBlocks = 256
// timestampIncrement is the default increment between block timestamps.
timestampIncrement = 1
)
// simBlock is a batch of calls to be simulated sequentially.
@ -106,7 +109,7 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str
defer cancel()
var err error
blocks, err = sim.sanitizeBlockOrder(blocks)
blocks, err = sim.sanitizeChain(blocks)
if err != nil {
return nil, err
}
@ -287,14 +290,16 @@ func (sim *simulator) activePrecompiles(ctx context.Context, base *types.Header)
return vm.ActivePrecompiledContracts(rules).Copy()
}
// 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) {
// sanitizeChain checks the chain integrity. Specifically it checks that
// block numbers and timestamp are strictly increasing, setting default values
// when necessary. Gaps in block numbers are filled with empty blocks.
// Note: It modifies the block's override object.
func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
var (
res = make([]simBlock, 0, len(blocks))
base = sim.base
prevNumber = base.Number
res = make([]simBlock, 0, len(blocks))
base = sim.base
prevNumber = base.Number
prevTimestamp = base.Time
)
for _, block := range blocks {
if block.BlockOverrides == nil {
@ -317,12 +322,25 @@ func (sim *simulator) sanitizeBlockOrder(blocks []simBlock) ([]simBlock, error)
// 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)}}
t := prevTimestamp + timestampIncrement
b := simBlock{BlockOverrides: &BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}}
prevTimestamp = t
res = append(res, b)
}
}
// Only append block after filling a potential gap.
prevNumber = block.BlockOverrides.Number.ToInt()
var t uint64
if block.BlockOverrides.Time == nil {
t = prevTimestamp + timestampIncrement
block.BlockOverrides.Time = (*hexutil.Uint64)(&t)
} else {
t = uint64(*block.BlockOverrides.Time)
if t <= prevTimestamp {
return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", t, prevTimestamp)}
}
}
prevTimestamp = t
res = append(res, block)
}
return res, nil
@ -333,23 +351,15 @@ func (sim *simulator) sanitizeBlockOrder(blocks []simBlock) ([]simBlock, error)
// It assumes blocks are in order and numbers have been validated.
func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
var (
res = make([]*types.Header, len(blocks))
base = sim.base
prevTimestamp = base.Time
header = base
res = make([]*types.Header, len(blocks))
base = sim.base
header = base
)
for bi, block := range blocks {
if block.BlockOverrides == nil || block.BlockOverrides.Number == nil {
return nil, errors.New("empty block number")
}
overrides := block.BlockOverrides
if overrides.Time == nil {
t := prevTimestamp + 1
overrides.Time = (*hexutil.Uint64)(&t)
} else if time := (*uint64)(overrides.Time); *time <= prevTimestamp {
return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", *time, prevTimestamp)}
}
prevTimestamp = uint64(*overrides.Time)
var withdrawalsHash *common.Hash
if sim.chainConfig.IsShanghai(overrides.Number.ToInt(), (uint64)(*overrides.Time)) {

View file

@ -1,7 +1,6 @@
package ethapi
import (
"fmt"
"math/big"
"testing"
@ -10,35 +9,62 @@ import (
)
func TestSimulateSanitizeBlockOrder(t *testing.T) {
type result struct {
number uint64
timestamp uint64
}
for i, tc := range []struct {
baseNumber int
blocks []simBlock
expectedLen int
err string
baseNumber int
baseTimestamp uint64
blocks []simBlock
expected []result
err string
}{
{
baseNumber: 10,
blocks: []simBlock{{}, {}, {}},
expectedLen: 3,
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{}, {}, {}},
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}},
},
{
baseNumber: 10,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {}},
expectedLen: 4,
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}},
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}},
},
{
baseNumber: 10,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}},
expectedLen: 5,
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}},
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}},
},
{
baseNumber: 10,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}},
err: "block numbers must be in order: 12 <= 13",
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}},
err: "block numbers must be in order: 12 <= 13",
},
{
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(52)}}},
err: "block timestamps must be in order: 52 <= 52",
},
{
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12), Time: newUint64(55)}}},
err: "block timestamps must be in order: 55 <= 60",
},
{
baseNumber: 10,
baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(61)}}},
err: "block timestamps must be in order: 61 <= 61",
},
} {
sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber))}}
res, err := sim.sanitizeBlockOrder(tc.blocks)
sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}}
res, err := sim.sanitizeChain(tc.blocks)
if err != nil {
if err.Error() == tc.err {
continue
@ -49,9 +75,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
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))
if len(res) != len(tc.expected) {
t.Errorf("testcase %d: mismatch number of blocks. Want %d, have %d", i, len(tc.expected), len(res))
}
for bi, b := range res {
if b.BlockOverrides == nil {
@ -60,10 +85,15 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
if b.BlockOverrides.Number == nil {
t.Fatalf("testcase %d: block number not set", i)
}
want := tc.baseNumber + bi + 1
if b.BlockOverrides.Time == nil {
t.Fatalf("testcase %d: block time not set", i)
}
if (uint64)(*b.BlockOverrides.Time) != tc.expected[bi].timestamp {
t.Errorf("testcase %d: block timestamp mismatch. Want %d, have %d", i, tc.expected[bi].timestamp, (uint64)(*b.BlockOverrides.Time))
}
have := b.BlockOverrides.Number.ToInt().Uint64()
if uint64(want) != have {
t.Errorf("testcase %d: block number mismatch. Want %d, have %d", i, want, have)
if have != tc.expected[bi].number {
t.Errorf("testcase %d: block number mismatch. Want %d, have %d", i, tc.expected[bi].number, have)
}
}
}