Implement PIP-12, Time Based StateSync Confirmations Delay (#864)

* updated Indore HF related changes by adding stateSyncConfirmationDelay

* converted StateSyncConfirmationDelay to map[string]uint64 and cleanup

* calculate last state ID from incoming state object with eth call (#883)

* removed IndoreBlock from configs

* fix

* remove code duplication and refactor

---------

Co-authored-by: Manav Darji <manavdarji.india@gmail.com>
This commit is contained in:
Pratik Patil 2023-06-06 20:40:46 +05:30 committed by GitHub
parent 3d30c341c4
commit 47f8e8682a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 152 additions and 61 deletions

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -11,4 +12,5 @@ import (
//go:generate mockgen -destination=./caller_mock.go -package=api . Caller //go:generate mockgen -destination=./caller_mock.go -package=api . Caller
type Caller interface { type Caller interface {
Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (hexutil.Bytes, error) Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (hexutil.Bytes, error)
CallWithState(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, state *state.StateDB, overrides *ethapi.StateOverride) (hexutil.Bytes, error)
} }

View file

@ -9,6 +9,7 @@ import (
reflect "reflect" reflect "reflect"
hexutil "github.com/ethereum/go-ethereum/common/hexutil" hexutil "github.com/ethereum/go-ethereum/common/hexutil"
state "github.com/ethereum/go-ethereum/core/state"
ethapi "github.com/ethereum/go-ethereum/internal/ethapi" ethapi "github.com/ethereum/go-ethereum/internal/ethapi"
rpc "github.com/ethereum/go-ethereum/rpc" rpc "github.com/ethereum/go-ethereum/rpc"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
@ -51,3 +52,18 @@ func (mr *MockCallerMockRecorder) Call(arg0, arg1, arg2, arg3 interface{}) *gomo
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), arg0, arg1, arg2, arg3) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), arg0, arg1, arg2, arg3)
} }
// CallWithState mocks base method.
func (m *MockCaller) CallWithState(arg0 context.Context, arg1 ethapi.TransactionArgs, arg2 rpc.BlockNumberOrHash, arg3 *state.StateDB, arg4 *ethapi.StateOverride) (hexutil.Bytes, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CallWithState", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(hexutil.Bytes)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CallWithState indicates an expected call of CallWithState.
func (mr *MockCallerMockRecorder) CallWithState(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallWithState", reflect.TypeOf((*MockCaller)(nil).CallWithState), arg0, arg1, arg2, arg3, arg4)
}

View file

@ -1184,22 +1184,42 @@ func (c *Bor) CommitStates(
fetchStart := time.Now() fetchStart := time.Now()
number := header.Number.Uint64() number := header.Number.Uint64()
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1) var (
lastStateIDBig *big.Int
from uint64
to time.Time
err error
)
if c.config.IsIndore(header.Number) {
// Fetch the LastStateId from contract via current state instance
lastStateIDBig, err = c.GenesisContractsClient.LastStateId(state.Copy(), number-1, header.ParentHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.CalculateSprint(number)).Time), 0) stateSyncDelay := c.config.CalculateStateSyncDelay(number)
lastStateID := _lastStateID.Uint64() to = time.Unix(int64(header.Time-stateSyncDelay), 0)
} else {
lastStateIDBig, err = c.GenesisContractsClient.LastStateId(nil, number-1, header.ParentHash)
if err != nil {
return nil, err
}
to = time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.CalculateSprint(number)).Time), 0)
}
lastStateID := lastStateIDBig.Uint64()
from = lastStateID + 1
log.Info( log.Info(
"Fetching state updates from Heimdall", "Fetching state updates from Heimdall",
"fromID", lastStateID+1, "fromID", from,
"to", to.Format(time.RFC3339)) "to", to.Format(time.RFC3339))
eventRecords, err := c.HeimdallClient.StateSyncEvents(ctx, lastStateID+1, to.Unix()) eventRecords, err := c.HeimdallClient.StateSyncEvents(ctx, from, to.Unix())
if err != nil { if err != nil {
log.Error("Error occurred when fetching state sync events", "stateID", lastStateID+1, "error", err) log.Error("Error occurred when fetching state sync events", "fromID", from, "to", to.Unix(), "err", err)
} }
if c.config.OverrideStateSyncRecords != nil { if c.config.OverrideStateSyncRecords != nil {
@ -1222,7 +1242,7 @@ func (c *Bor) CommitStates(
} }
if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error()) log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID+1, "error", err.Error())
break break
} }

View file

@ -100,8 +100,8 @@ func (gc *GenesisContractsClient) CommitState(
return gasUsed, nil return gasUsed, nil
} }
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { func (gc *GenesisContractsClient) LastStateId(state *state.StateDB, number uint64, hash common.Hash) (*big.Int, error) {
blockNr := rpc.BlockNumber(snapshotNumber) blockNr := rpc.BlockNumber(number)
const method = "lastStateId" const method = "lastStateId"
@ -116,11 +116,13 @@ func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int,
toAddress := common.HexToAddress(gc.StateReceiverContract) toAddress := common.HexToAddress(gc.StateReceiverContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
result, err := gc.ethAPI.Call(context.Background(), ethapi.TransactionArgs{ // Do a call with state so that we can fetch the last state ID from a given (incoming)
// state instead of local(canonical) chain.
result, err := gc.ethAPI.CallWithState(context.Background(), ethapi.TransactionArgs{
Gas: &gas, Gas: &gas,
To: &toAddress, To: &toAddress,
Data: &msgData, Data: &msgData,
}, rpc.BlockNumberOrHash{BlockNumber: &blockNr}, nil) }, rpc.BlockNumberOrHash{BlockNumber: &blockNr, BlockHash: &hash}, state, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -3,6 +3,7 @@ package bor
import ( import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/bor/clerk" "github.com/ethereum/go-ethereum/consensus/bor/clerk"
"github.com/ethereum/go-ethereum/consensus/bor/statefull" "github.com/ethereum/go-ethereum/consensus/bor/statefull"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -12,5 +13,5 @@ import (
//go:generate mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract //go:generate mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract
type GenesisContract interface { type GenesisContract interface {
CommitState(event *clerk.EventRecordWithTime, state *state.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error) CommitState(event *clerk.EventRecordWithTime, state *state.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error)
LastStateId(snapshotNumber uint64) (*big.Int, error) LastStateId(state *state.StateDB, number uint64, hash common.Hash) (*big.Int, error)
} }

View file

@ -8,6 +8,7 @@ import (
big "math/big" big "math/big"
reflect "reflect" reflect "reflect"
common "github.com/ethereum/go-ethereum/common"
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk" clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
statefull "github.com/ethereum/go-ethereum/consensus/bor/statefull" statefull "github.com/ethereum/go-ethereum/consensus/bor/statefull"
state "github.com/ethereum/go-ethereum/core/state" state "github.com/ethereum/go-ethereum/core/state"
@ -54,16 +55,16 @@ func (mr *MockGenesisContractMockRecorder) CommitState(arg0, arg1, arg2, arg3 in
} }
// LastStateId mocks base method. // LastStateId mocks base method.
func (m *MockGenesisContract) LastStateId(arg0 uint64) (*big.Int, error) { func (m *MockGenesisContract) LastStateId(arg0 *state.StateDB, arg1 uint64, arg2 common.Hash) (*big.Int, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LastStateId", arg0) ret := m.ctrl.Call(m, "LastStateId", arg0, arg1, arg2)
ret0, _ := ret[0].(*big.Int) ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LastStateId indicates an expected call of LastStateId. // LastStateId indicates an expected call of LastStateId.
func (mr *MockGenesisContractMockRecorder) LastStateId(arg0 interface{}) *gomock.Call { func (mr *MockGenesisContractMockRecorder) LastStateId(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0, arg1, arg2)
} }

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: consensus/bor/span.go // Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: Spanner)
// Package bor is a generated GoMock package. // Package bor is a generated GoMock package.
package bor package bor
@ -42,60 +42,60 @@ func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder {
} }
// CommitSpan mocks base method. // CommitSpan mocks base method.
func (m *MockSpanner) CommitSpan(ctx context.Context, heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error { func (m *MockSpanner) CommitSpan(arg0 context.Context, arg1 span.HeimdallSpan, arg2 *state.StateDB, arg3 *types.Header, arg4 core.ChainContext) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CommitSpan", ctx, heimdallSpan, state, header, chainContext) ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// CommitSpan indicates an expected call of CommitSpan. // CommitSpan indicates an expected call of CommitSpan.
func (mr *MockSpannerMockRecorder) CommitSpan(ctx, heimdallSpan, state, header, chainContext interface{}) *gomock.Call { func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), ctx, heimdallSpan, state, header, chainContext) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3, arg4)
} }
// GetCurrentSpan mocks base method. // GetCurrentSpan mocks base method.
func (m *MockSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*span.Span, error) { func (m *MockSpanner) GetCurrentSpan(arg0 context.Context, arg1 common.Hash) (*span.Span, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCurrentSpan", ctx, headerHash) ret := m.ctrl.Call(m, "GetCurrentSpan", arg0, arg1)
ret0, _ := ret[0].(*span.Span) ret0, _ := ret[0].(*span.Span)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// GetCurrentSpan indicates an expected call of GetCurrentSpan. // GetCurrentSpan indicates an expected call of GetCurrentSpan.
func (mr *MockSpannerMockRecorder) GetCurrentSpan(ctx, headerHash interface{}) *gomock.Call { func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), ctx, headerHash) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0, arg1)
} }
// GetCurrentValidatorsByBlockNrOrHash mocks base method. // GetCurrentValidatorsByBlockNrOrHash mocks base method.
func (m *MockSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) { func (m *MockSpanner) GetCurrentValidatorsByBlockNrOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash, arg2 uint64) ([]*valset.Validator, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCurrentValidatorsByBlockNrOrHash", ctx, blockNrOrHash, blockNumber) ret := m.ctrl.Call(m, "GetCurrentValidatorsByBlockNrOrHash", arg0, arg1, arg2)
ret0, _ := ret[0].([]*valset.Validator) ret0, _ := ret[0].([]*valset.Validator)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// GetCurrentValidatorsByBlockNrOrHash indicates an expected call of GetCurrentValidatorsByBlockNrOrHash. // GetCurrentValidatorsByBlockNrOrHash indicates an expected call of GetCurrentValidatorsByBlockNrOrHash.
func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByBlockNrOrHash(ctx, blockNrOrHash, blockNumber interface{}) *gomock.Call { func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByBlockNrOrHash(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByBlockNrOrHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByBlockNrOrHash), ctx, blockNrOrHash, blockNumber) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByBlockNrOrHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByBlockNrOrHash), arg0, arg1, arg2)
} }
// GetCurrentValidatorsByHash mocks base method. // GetCurrentValidatorsByHash mocks base method.
func (m *MockSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { func (m *MockSpanner) GetCurrentValidatorsByHash(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([]*valset.Validator, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCurrentValidatorsByHash", ctx, headerHash, blockNumber) ret := m.ctrl.Call(m, "GetCurrentValidatorsByHash", arg0, arg1, arg2)
ret0, _ := ret[0].([]*valset.Validator) ret0, _ := ret[0].([]*valset.Validator)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// GetCurrentValidatorsByHash indicates an expected call of GetCurrentValidatorsByHash. // GetCurrentValidatorsByHash indicates an expected call of GetCurrentValidatorsByHash.
func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByHash(ctx, headerHash, blockNumber interface{}) *gomock.Call { func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByHash(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByHash), ctx, headerHash, blockNumber) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByHash), arg0, arg1, arg2)
} }

View file

@ -1006,7 +1006,8 @@ func (b *Block) Call(ctx context.Context, args struct {
return nil, err return nil, err
} }
} }
result, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, b.backend.RPCEVMTimeout(), b.backend.RPCGasCap())
result, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, nil, b.backend.RPCEVMTimeout(), b.backend.RPCGasCap())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1076,7 +1077,7 @@ func (p *Pending) Call(ctx context.Context, args struct {
Data ethapi.TransactionArgs Data ethapi.TransactionArgs
}) (*CallResult, error) { }) (*CallResult, error) {
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
result, err := ethapi.DoCall(ctx, p.backend, args.Data, pendingBlockNr, nil, p.backend.RPCEVMTimeout(), p.backend.RPCGasCap()) result, err := ethapi.DoCall(ctx, p.backend, args.Data, pendingBlockNr, nil, nil, p.backend.RPCEVMTimeout(), p.backend.RPCGasCap())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -987,16 +987,40 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
return nil return nil
} }
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, state *state.StateDB, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) var (
header *types.Header
err error
)
// Fetch the state and header from blockNumberOrHash if it's coming from normal eth_call path.
if state == nil {
state, header, err = b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
} else {
// Fetch the header from the given blockNumberOrHash. Note that this path is only taken
// when we're doing a call from bor consensus to fetch data from genesis contracts. It's
// necessary to fetch header using header hash as we might be experiencing a reorg and there
// can be multiple headers with same number.
header, err = b.HeaderByHash(ctx, *blockNrOrHash.BlockHash)
if header == nil || err != nil {
log.Warn("Error fetching header on CallWithState", "err", err)
return nil, err
}
}
if err := overrides.Apply(state); err != nil { if err := overrides.Apply(state); err != nil {
return nil, err return nil, err
} }
return doCallWithState(ctx, b, args, header, state, timeout, globalGasCap)
}
func doCallWithState(ctx context.Context, b Backend, args TransactionArgs, header *types.Header, state *state.StateDB, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
// Setup context so it may be cancelled the call has completed // Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout. // or, in case of unmetered gas, setup a context with a timeout.
var cancel context.CancelFunc var cancel context.CancelFunc
@ -1080,7 +1104,20 @@ func (e *revertError) ErrorData() interface{} {
// Note, this function doesn't make and changes in the state/blockchain and is // Note, this function doesn't make and changes in the state/blockchain and is
// useful to execute and retrieve values. // useful to execute and retrieve values.
func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) return s.CallWithState(ctx, args, blockNrOrHash, nil, overrides)
}
// CallWithState executes the given transaction on the given state for
// the given block number. Note that as it does an EVM call, fields in
// the underlying state will change. Make sure to handle it outside of
// this function (ideally by sending a copy of state).
//
// Additionally, the caller can specify a batch of contract for fields overriding.
//
// Note, this function doesn't make and changes in the state/blockchain and is
// useful to execute and retrieve values.
func (s *PublicBlockChainAPI) CallWithState(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, state *state.StateDB, overrides *StateOverride) (hexutil.Bytes, error) {
result, err := DoCall(ctx, s.b, args, blockNrOrHash, state, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1093,6 +1130,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
if len(result.Revert()) > 0 { if len(result.Revert()) > 0 {
return nil, newRevertError(result) return nil, newRevertError(result)
} }
return result.Return(), result.Err return result.Return(), result.Err
} }
@ -1170,7 +1208,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
executable := func(gas uint64) (bool, *core.ExecutionResult, error) { executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
args.Gas = (*hexutil.Uint64)(&gas) args.Gas = (*hexutil.Uint64)(&gas)
result, err := DoCall(ctx, b, args, blockNrOrHash, nil, 0, gasCap) result, err := DoCall(ctx, b, args, blockNrOrHash, nil, nil, 0, gasCap)
if err != nil { if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) { if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit return true, nil, nil // Special case, raise gas limit

View file

@ -406,8 +406,8 @@ var (
LondonBlock: big.NewInt(23850000), LondonBlock: big.NewInt(23850000),
Bor: &BorConfig{ Bor: &BorConfig{
JaipurBlock: big.NewInt(23850000), JaipurBlock: big.NewInt(23850000),
ParallelUniverseBlock: big.NewInt(0),
DelhiBlock: big.NewInt(38189056), DelhiBlock: big.NewInt(38189056),
ParallelUniverseBlock: big.NewInt(0),
Period: map[string]uint64{ Period: map[string]uint64{
"0": 2, "0": 2,
}, },
@ -590,6 +590,8 @@ type BorConfig struct {
JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur) JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur)
DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi) DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi)
ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes) ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes)
IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on indore)
StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to`
} }
// String implements the stringer interface, returning the consensus engine details. // String implements the stringer interface, returning the consensus engine details.
@ -598,11 +600,11 @@ func (b *BorConfig) String() string {
} }
func (c *BorConfig) CalculateProducerDelay(number uint64) uint64 { func (c *BorConfig) CalculateProducerDelay(number uint64) uint64 {
return c.calculateSprintSizeHelper(c.ProducerDelay, number) return borKeyValueConfigHelper(c.ProducerDelay, number)
} }
func (c *BorConfig) CalculateSprint(number uint64) uint64 { func (c *BorConfig) CalculateSprint(number uint64) uint64 {
return c.calculateSprintSizeHelper(c.Sprint, number) return borKeyValueConfigHelper(c.Sprint, number)
} }
func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 { func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 {
@ -621,6 +623,14 @@ func (c *BorConfig) IsDelhi(number *big.Int) bool {
return isForked(c.DelhiBlock, number) return isForked(c.DelhiBlock, number)
} }
func (c *BorConfig) IsIndore(number *big.Int) bool {
return isForked(c.IndoreBlock, number)
}
func (c *BorConfig) CalculateStateSyncDelay(number uint64) uint64 {
return borKeyValueConfigHelper(c.StateSyncConfirmationDelay, number)
}
// TODO: modify this function once the block number is finalized // TODO: modify this function once the block number is finalized
func (c *BorConfig) IsParallelUniverse(number *big.Int) bool { func (c *BorConfig) IsParallelUniverse(number *big.Int) bool {
if c.ParallelUniverseBlock == big.NewInt(0) { if c.ParallelUniverseBlock == big.NewInt(0) {
@ -654,7 +664,7 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin
return field[keys[len(keys)-1]] return field[keys[len(keys)-1]]
} }
func (c *BorConfig) calculateSprintSizeHelper(field map[string]uint64, number uint64) uint64 { func borKeyValueConfigHelper(field map[string]uint64, number uint64) uint64 {
keys := make([]string, 0, len(field)) keys := make([]string, 0, len(field))
for k := range field { for k := range field {
keys = append(keys, k) keys = append(keys, k)

View file

@ -544,7 +544,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
insertNewBlock(t, chain, block) insertNewBlock(t, chain, block)
} }
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize) lastStateID, _ := _bor.GenesisContractsClient.LastStateId(nil, sprintSize, block.Hash())
// state 6 was not written // state 6 was not written
require.Equal(t, uint64(4), lastStateID.Uint64()) require.Equal(t, uint64(4), lastStateID.Uint64())
@ -573,7 +573,7 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
insertNewBlock(t, chain, block) insertNewBlock(t, chain, block)
} }
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize) lastStateID, _ = _bor.GenesisContractsClient.LastStateId(nil, spanSize, block.Hash())
require.Equal(t, uint64(6), lastStateID.Uint64()) require.Equal(t, uint64(6), lastStateID.Uint64())
} }