diff --git a/api/api_test.go b/api/api_test.go
index f159b8818..66eeee5ea 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -67,9 +67,9 @@ func (f TransactionEmitterFunc) Emit(tx *types.Transaction) error {
return f(tx)
}
-func newRPCBalance(balance *big.Int) **hexutil.Big {
+func newRPCBalance(balance *big.Int) *hexutil.Big {
rpcBalance := (*hexutil.Big)(balance)
- return &rpcBalance
+ return rpcBalance
}
func hex2Bytes(str string) *hexutil.Bytes {
diff --git a/api/error.go b/api/error.go
index 3aab4e19e..7337a7f46 100644
--- a/api/error.go
+++ b/api/error.go
@@ -106,6 +106,23 @@ var (
)
+const (
+ errCodeNonceTooHigh = -38011
+ errCodeNonceTooLow = -38010
+ errCodeIntrinsicGas = -38013
+ errCodeInsufficientFunds = -38014
+ errCodeBlockGasLimitReached = -38015
+ errCodeBlockNumberInvalid = -38020
+ errCodeBlockTimestampInvalid = -38021
+ errCodeSenderIsNotEOA = -38024
+ errCodeMaxInitCodeSizeExceeded = -38025
+ errCodeClientLimitExceeded = -38026
+ errCodeInternalError = -32603
+ errCodeInvalidParams = -32602
+ errCodeReverted = -32000
+ errCodeVMError = -32015
+)
+
// EIP-7702 state transition errors.
// Note these are just informational, and do not cause tx execution abort.
@@ -115,4 +132,32 @@ var (
ErrAuthorizationInvalidSignature = errors.New("EIP-7702 authorization has invalid signature")
ErrAuthorizationDestinationHasCode = errors.New("EIP-7702 authorization destination is a contract")
ErrAuthorizationNonceMismatch = errors.New("EIP-7702 authorization nonce does not match current account nonce")
-)
\ No newline at end of file
+)
+
+type callError struct {
+ Message string `json:"message"`
+ Code int `json:"code"`
+ Data string `json:"data,omitempty"`
+}
+
+type invalidParamsError struct{ message string }
+
+func (e *invalidParamsError) Error() string { return e.message }
+func (e *invalidParamsError) ErrorCode() int { return errCodeInvalidParams }
+
+type clientLimitExceededError struct{ message string }
+
+type invalidBlockNumberError struct{ message string }
+func (e *invalidBlockNumberError) Error() string { return e.message }
+func (e *invalidBlockNumberError) ErrorCode() int { return errCodeBlockNumberInvalid }
+
+type invalidBlockTimestampError struct{ message string }
+func (e *invalidBlockTimestampError) Error() string { return e.message }
+
+func (e *clientLimitExceededError) Error() string { return e.message }
+func (e *clientLimitExceededError) ErrorCode() int { return errCodeClientLimitExceeded }
+
+type blockGasLimitReachedError struct{ message string }
+
+func (e *blockGasLimitReachedError) Error() string { return e.message }
+func (e *blockGasLimitReachedError) ErrorCode() int { return errCodeBlockGasLimitReached }
diff --git a/api/eth.go b/api/eth.go
index 9af4e95ee..043bcf8f3 100644
--- a/api/eth.go
+++ b/api/eth.go
@@ -133,7 +133,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx *rpc.CallContext, address common.
type OverrideAccount struct {
Nonce *hexutil.Uint64 `json:"nonce"`
Code *hexutil.Bytes `json:"code"`
- Balance **hexutil.Big `json:"balance"`
+ Balance *hexutil.Big `json:"balance"`
State *map[ctypes.Hash]ctypes.Hash `json:"state"`
StateDiff *map[ctypes.Hash]ctypes.Hash `json:"stateDiff"`
}
@@ -176,7 +176,7 @@ func (diff *StateOverride) Apply(state state.StateDB) error {
}
// Override account balance.
if account.Balance != nil {
- state.SetBalance(addr, (*big.Int)(*account.Balance))
+ state.SetBalance(addr, (*big.Int)(account.Balance))
}
if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
@@ -192,9 +192,35 @@ func (diff *StateOverride) Apply(state state.StateDB) error {
}
}
}
+
+ // Now finalize the changes. Finalize is normally performed between transactions.
+ // By using finalize, the overrides are semantically behaving as
+ // if they were created in a transaction just before the tracing occur.
+ state.Finalise()
return nil
}
+func applyMessageWithEVM(ctx *rpc.CallContext, evm *vm.EVM, msg *Msg, timeout time.Duration, gp *GasPool) (*ExecutionResult, error) {
+ // Wait for the context to be done and cancel the evm. Even if the
+ // EVM has finished, cancelling may be done (repeatedly)
+ go func() {
+ <-ctx.Context().Done()
+ evm.Cancel()
+ }()
+
+ // Execute the message.
+ result, err := ApplyMessage(evm, msg, gp)
+
+ // If the timer caused an abort, return an appropriate error message
+ if evm.Cancelled() {
+ return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
+ }
+ if err != nil {
+ return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.gasLimit)
+ }
+ return result, nil
+}
+
func DoCall(cctx *rpc.CallContext, getEVM func(state.StateDB, *vm.Config, common.Address, *big.Int) *vm.EVM, args TransactionArgs, prevState *PreviousState, blockNrOrHash vm.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*ExecutionResult, *PreviousState, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
if prevState == nil || prevState.header == nil || prevState.state == nil {
@@ -340,6 +366,61 @@ func (s *PublicBlockChainAPI) Call(ctx *rpc.CallContext, args TransactionArgs, b
return res, err
}
+// SimulateV1 executes series of transactions on top of a base state.
+// The transactions are packed into blocks. For each block, block header
+// fields can be overridden. The state can also be overridden prior to
+// execution of each block.
+//
+// Note, this function doesn't make any changes in the state/blockchain and is
+// useful to execute and retrieve values.
+func (s *PublicBlockChainAPI) SimulateV1(ctx *rpc.CallContext, opts simOpts, blockNrOrHash *vm.BlockNumberOrHash) ([]*simBlockResult, error) {
+ if len(opts.BlockStateCalls) == 0 {
+ return nil, &invalidParamsError{message: "empty input"}
+ } else if len(opts.BlockStateCalls) > maxSimulateBlocks {
+ return nil, &clientLimitExceededError{message: "too many blocks"}
+ }
+
+ bNrOrHash := vm.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
+ if blockNrOrHash != nil {
+ bNrOrHash = *blockNrOrHash
+ }
+
+ var results []*simBlockResult
+
+ err := s.evmmgr.View(bNrOrHash, &vm.Config{NoBaseFee: !opts.Validation}, ctx, func(statedb state.StateDB, baseHeader *types.Header, evmFn func(state.StateDB, *vm.Config, common.Address, *big.Int) *vm.EVM, chaincfg *params.ChainConfig) error {
+ gasCap := s.gasLimit(baseHeader)
+ if gasCap == 0 {
+ gasCap = math.MaxUint64
+ }
+
+ sim := &simulator{
+ timeout: 30 * time.Second,
+ state: statedb.Copy(),
+ base: types.CopyHeader(baseHeader),
+ chainConfig: chaincfg,
+ // Each tx and all the series of txes shouldn't consume more gas than cap
+ gp: new(GasPool).AddGas(gasCap),
+ traceTransfers: opts.TraceTransfers,
+ validate: opts.Validation,
+ fullTx: opts.ReturnFullTransactions,
+ evmFn: evmFn,
+ }
+ var err error
+ results, err = sim.execute(ctx, opts.BlockStateCalls)
+ return err
+ })
+
+ if err != nil {
+ switch err.(type) {
+ case codedError:
+ default:
+ err = evmError{err}
+ }
+ return nil, err
+ }
+ return results, nil
+}
+
//
type estimateGasError struct {
error string // Concrete error type if it's failed to estimate gas usage
diff --git a/api/logtracer.go b/api/logtracer.go
new file mode 100644
index 000000000..dee1cae38
--- /dev/null
+++ b/api/logtracer.go
@@ -0,0 +1,87 @@
+package api
+
+import (
+ "math/big"
+ "time"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/types"
+ "github.com/openrelayxyz/cardinal-evm/vm"
+ ctypes "github.com/openrelayxyz/cardinal-types"
+)
+
+var (
+ // keccak256("Transfer(address,address,uint256)")
+ transferTopic = ctypes.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
+ // ERC-7528
+ transferAddress = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
+)
+
+
+type tracer struct {
+ // logs keeps logs for all open call frames.
+ // This lets us clear logs for failed calls.
+ logs []*types.Log
+ count int
+ traceTransfers bool
+ blockNumber uint64
+ blockTimestamp uint64
+ blockHash ctypes.Hash
+ txHash ctypes.Hash
+ txIdx uint
+}
+
+func newTracer(traceTransfers bool, blockNumber uint64, blockTimestamp uint64, blockHash, txHash ctypes.Hash, txIndex uint) *tracer {
+ return &tracer{
+ logs: make([]*types.Log, 0),
+ traceTransfers: traceTransfers,
+ blockNumber: blockNumber,
+ blockHash: blockHash,
+ txHash: txHash,
+ txIdx: txIndex,
+ blockTimestamp: blockTimestamp,
+ }
+}
+
+func (t *tracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {}
+
+func (t *tracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int){
+ if !t.traceTransfers {
+ return
+ }
+ // Capture the initial transaction value transfer
+ if !create && value != nil && value.Sign() > 0 {
+ topics := []ctypes.Hash{
+ transferTopic,
+ ctypes.BytesToHash(from.Bytes()),
+ ctypes.BytesToHash(to.Bytes()),
+ }
+ t.logs = append(t.logs, &types.Log{
+ Address: transferAddress,
+ Topics: topics,
+ Data: ctypes.BigToHash(value).Bytes(),
+ BlockNumber: t.blockNumber,
+ BlockHash: t.blockHash,
+ TxHash: t.txHash,
+ TxIndex: t.txIdx,
+ Index: uint(t.count),
+ BlockTimestamp: t.blockTimestamp,
+ })
+ t.count++
+ }
+}
+func (t *tracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error){}
+func (t *tracer) CaptureExit(output []byte, gasUsed uint64, err error){}
+func (t *tracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error){}
+func (t *tracer) CaptureEnd(output []byte, gasUsed uint64, time time.Duration, err error){}
+
+// reset prepares the tracer for the next transaction.
+func (t *tracer) reset(txHash ctypes.Hash, txIdx uint) {
+ t.logs = make([]*types.Log, 0)
+ t.txHash = txHash
+ t.txIdx = txIdx
+}
+
+func (t *tracer) Logs() []*types.Log {
+ return t.logs
+}
\ No newline at end of file
diff --git a/api/simulate.go b/api/simulate.go
new file mode 100644
index 000000000..1a867a6a5
--- /dev/null
+++ b/api/simulate.go
@@ -0,0 +1,451 @@
+package api
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/crypto"
+ "github.com/openrelayxyz/cardinal-evm/eips/eip1559"
+ "github.com/openrelayxyz/cardinal-evm/eips/eip4844"
+ "github.com/openrelayxyz/cardinal-evm/params"
+ "github.com/openrelayxyz/cardinal-evm/state"
+ "github.com/openrelayxyz/cardinal-evm/trie"
+ "github.com/openrelayxyz/cardinal-evm/types"
+ "github.com/openrelayxyz/cardinal-evm/vm"
+ rpc "github.com/openrelayxyz/cardinal-rpc"
+ ctypes "github.com/openrelayxyz/cardinal-types"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
+ // log "github.com/inconshreveable/log15"
+)
+
+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 = 12
+)
+
+// BlockOverrides is a set of header fields to override.
+type BlockOverrides struct {
+ Number *hexutil.Big
+ Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
+ Time *hexutil.Uint64
+ GasLimit *hexutil.Uint64
+ FeeRecipient *common.Address
+ PrevRandao *ctypes.Hash
+ BaseFeePerGas *hexutil.Big
+ BlobBaseFee *hexutil.Big
+ BeaconRoot *ctypes.Hash
+ Withdrawals *types.Withdrawals
+}
+
+// simOpts are the inputs to eth_simulateV1.
+type simOpts struct {
+ BlockStateCalls []simBlock
+ TraceTransfers bool
+ Validation bool
+ ReturnFullTransactions bool
+}
+
+// simBlock is a batch of calls to be simulated sequentially.
+type simBlock struct {
+ BlockOverrides *BlockOverrides
+ StateOverrides *StateOverride
+ Calls []TransactionArgs
+}
+
+// simulator is a stateful object that simulates a series of blocks.
+// it is not safe for concurrent use.
+type simulator struct {
+ timeout time.Duration
+ state state.StateDB
+ base *types.Header
+ chainConfig *params.ChainConfig
+ gp *GasPool
+ traceTransfers bool
+ validate bool
+ fullTx bool
+ evmFn func(state.StateDB, *vm.Config, common.Address, *big.Int) *vm.EVM
+}
+
+// simCallResult is the result of a simulated call.
+type simCallResult struct {
+ ReturnValue hexutil.Bytes `json:"returnData"`
+ Logs []*types.Log `json:"logs"`
+ GasUsed hexutil.Uint64 `json:"gasUsed"`
+ Status hexutil.Uint64 `json:"status"`
+ Error *callError `json:"error,omitempty"`
+}
+
+func (r *simCallResult) MarshalJSON() ([]byte, error) {
+ type callResultAlias simCallResult
+ // Marshal logs to be an empty array instead of nil when empty
+ if r.Logs == nil {
+ r.Logs = []*types.Log{}
+ }
+ return json.Marshal((*callResultAlias)(r))
+}
+
+type simBlockResult struct {
+ fullTx bool
+ chainConfig *params.ChainConfig
+ Block *types.Block
+ Calls []simCallResult
+ // senders is a map of transaction hashes to their senders.
+ senders map[ctypes.Hash]common.Address
+}
+
+func (r *simBlockResult) MarshalJSON() ([]byte, error) {
+ blockData := types.RPCMarshalBlock(r.Block, true, r.fullTx, r.chainConfig)
+ blockData["calls"] = r.Calls
+ // Set tx sender if user requested full tx objects.
+ if r.fullTx {
+ if raw, ok := blockData["transactions"].([]any); ok {
+ for _, tx := range raw {
+ if tx, ok := tx.(*types.RPCTransaction); ok {
+ tx.From = r.senders[tx.Hash]
+ } else {
+ return nil, errors.New("simulated transaction result has invalid type")
+ }
+ }
+ }
+ }
+ return json.Marshal(blockData)
+}
+
+func (s *simulator) execute(ctx *rpc.CallContext, blocks []simBlock) ([]*simBlockResult, error) {
+ if err := ctx.Context().Err(); err != nil {
+ return nil, err
+ }
+
+ var cancel context.CancelFunc
+ var execCtx context.Context
+ if s.timeout > 0 {
+ execCtx, cancel = context.WithTimeout(ctx.Context(), s.timeout)
+ } else {
+ execCtx, cancel = context.WithCancel(ctx.Context())
+ }
+ defer cancel()
+
+ var (
+ results = make([]*simBlockResult, len(blocks))
+ headers = make([]*types.Header, 0, len(blocks))
+ parent = s.base
+ )
+
+ var err error
+ blocks, err = s.sanitizeChain(blocks)
+ if err != nil {
+ return nil, err
+ }
+
+ for bi, block := range blocks {
+ header := types.CopyHeader(s.base)
+ header.Number = new(big.Int).Add(s.base.Number, big.NewInt(int64(bi+1)))
+ header.ParentHash = parent.Hash()
+ header.Extra = []byte{}
+ header.BaseFee = nil
+
+ override := *block.BlockOverrides
+ if override.Number != nil {header.Number = override.Number.ToInt()}
+ if override.Difficulty != nil {header.Difficulty = override.Difficulty.ToInt()}
+ if override.Time != nil {header.Time = uint64(*override.Time)}
+ if override.GasLimit != nil {header.GasLimit = uint64(*override.GasLimit)}
+ if override.FeeRecipient != nil {header.Coinbase = *override.FeeRecipient}
+ if override.PrevRandao != nil {header.MixDigest = *override.PrevRandao} else{
+ header.MixDigest = ctypes.Hash{}
+ }
+ if override.BaseFeePerGas != nil {header.BaseFee = override.BaseFeePerGas.ToInt()}
+ if override.BlobBaseFee != nil {
+ val := *override.BlobBaseFee.ToInt()
+ ptr := val.Uint64()
+ header.ExcessBlobGas = &ptr
+ }
+
+ var parentBeaconRoot *ctypes.Hash
+ if s.chainConfig.IsCancun(override.Number.ToInt(), big.NewInt(int64(*override.Time))) {
+ parentBeaconRoot = &ctypes.Hash{}
+ if override.BeaconRoot != nil {
+ parentBeaconRoot = override.BeaconRoot
+ }
+ }
+ header.ParentBeaconRoot = parentBeaconRoot
+
+ s.gp = new(GasPool).AddGas(header.GasLimit)
+
+ if err := execCtx.Err(); err != nil {
+ return nil, err
+ }
+ result, callResults, senders, err := s.processBlock(ctx, &block, header, parent, headers, s.timeout)
+ if err != nil {
+ return nil, err
+ }
+ results[bi] = &simBlockResult{fullTx: s.fullTx, chainConfig: s.chainConfig, Block: result, Calls: callResults, senders: senders}
+ headers = append(headers, result.Header())
+ parent = result.Header()
+
+ s.state.Finalise()
+ }
+
+ return results, nil
+}
+
+func (s *simulator) processBlock(ctx *rpc.CallContext, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, map[ctypes.Hash]common.Address, error) {
+ // Set header fields that depend only on parent block.
+ // Parent hash is needed for evm.GetHashFn to work.
+ header.ParentHash = parent.Hash()
+ if s.chainConfig.IsLondon(header.Number) {
+ if header.BaseFee == nil {
+ if s.validate {
+ header.BaseFee = eip1559.CalcBaseFee(s.chainConfig, parent)
+ } else {
+ header.BaseFee = big.NewInt(0)
+ }
+ }
+ }
+ if s.chainConfig.IsCancun(header.Number, new(big.Int).SetUint64(header.Time)) {
+ var excess uint64
+ if s.chainConfig.IsCancun(parent.Number, new(big.Int).SetUint64(parent.Time)) {
+ excess = eip4844.CalcExcessBlobGas(s.chainConfig, parent, header.Time)
+ }
+ header.ExcessBlobGas = &excess
+ }
+
+ // State overrides are applied prior to execution of a block
+ if block.StateOverrides != nil {
+ if err := block.StateOverrides.Apply(s.state); err != nil {
+ return nil, nil, nil, err
+ }
+ }
+
+ var (
+ blobGasUsed uint64
+ gasUsed uint64
+ txes = make([]*types.Transaction, len(block.Calls))
+ callResults = make([]simCallResult, len(block.Calls))
+ receipts = make([]*types.Receipt, len(block.Calls))
+ senders = make(map[ctypes.Hash]common.Address)
+ tracer = newTracer(s.traceTransfers, header.Number.Uint64(), header.Time, header.Hash(), ctypes.Hash{}, 0)
+ )
+
+ getHashFn := func(n uint64) ctypes.Hash {
+ for _, h := range headers {
+ if h.Number.Uint64() == n {
+ return h.Hash()
+ }
+ }
+ if parent.Number.Uint64() == n {
+ return parent.Hash()
+ }
+ return ctypes.Hash{}
+ }
+
+ for i, call := range block.Calls {
+ if err := ctx.Context().Err(); err != nil {
+ return nil, nil, nil, err
+ }
+ // Let the call run wild unless explicitly specified.
+ if call.Gas == nil {
+ remaining := header.GasLimit - gasUsed
+ call.Gas = (*hexutil.Uint64)(&remaining)
+ }
+
+ // Cap at gas pool
+ gasCap := s.gp.Gas()
+ if gasCap > 0 && gasCap < uint64(*call.Gas) {
+ call.Gas = (*hexutil.Uint64)(&gasCap)
+ }
+
+ if gasUsed+uint64(*call.Gas) > header.GasLimit {
+ return nil,nil,nil, &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, header.GasLimit)}
+ }
+ if call.ChainID == nil {
+ call.ChainID = (*hexutil.Big)(s.chainConfig.ChainID)
+ }
+ if err := call.setDefaults(ctx, s.chainConfig, s.evmFn, s.state, header, vm.BlockNumberOrHashWithHash(header.Hash(), false)); err != nil {
+ return nil, nil, nil, err
+ }
+
+ evm := s.evmFn(s.state, &vm.Config{
+ NoBaseFee: !s.validate, Tracer: tracer, Debug: s.traceTransfers,
+ }, call.from(), call.GasPrice.ToInt())
+
+ tx := call.ToTransaction(types.DynamicFeeTxType)
+ txes[i] = tx
+ senders[tx.Hash()] = call.from()
+
+ //update tracer with real tx hash
+ tracer.reset(tx.Hash(), uint(i))
+
+ s.state.SetTxContext(tx.Hash(), i)
+
+ evm.Context.BaseFee = header.BaseFee
+ if evm.Context.GetHash == nil {
+ evm.Context.GetHash = getHashFn
+ }
+
+ msg, err := call.ToMessage(s.gp.Gas(), header.BaseFee)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ result, err := applyMessageWithEVM(ctx, evm, &msg, timeout, s.gp)
+ if err != nil {
+ return nil, nil, nil, fmt.Errorf("transaction execution failed: %v", err)
+ }
+
+ var root []byte
+ if s.chainConfig.IsByzantium(header.Number) {
+ s.state.Finalise()
+ } else {
+ root = nil
+ }
+ gasUsed += result.UsedGas
+ // header.Root = s.base.Root
+
+ receipt := &types.Receipt{
+ Type: tx.Type(),
+ PostState: root,
+ Status: types.ReceiptStatusSuccessful,
+ CumulativeGasUsed: gasUsed,
+ TxHash: tx.Hash(),
+ GasUsed: result.UsedGas,
+ TransactionIndex: uint(i),
+ }
+ receipt.Logs = s.state.GetLogs(tx.Hash(), header.Number.Uint64(), header.Hash())
+ receipt.Bloom = types.CreateBloom([]*types.Receipt{receipt})
+ if tx.To() == nil {
+ receipt.ContractAddress = crypto.CreateAddress(*call.From, tx.Nonce())
+ }
+ if result.Failed() {
+ receipt.Status = types.ReceiptStatusFailed
+ }
+
+ // Handle blob gas for Cancun
+ if s.chainConfig.IsCancun(header.Number, new(big.Int).SetUint64(header.Time)) {
+ if tx.Type() == types.BlobTxType {
+ receipt.BlobGasUsed = tx.BlobGas()
+ blobGasUsed += receipt.BlobGasUsed
+ }
+ }
+
+ receipts[i] = receipt
+
+ callRes := simCallResult{
+ GasUsed: hexutil.Uint64(result.UsedGas),
+ ReturnValue: result.ReturnData,
+ Logs: receipt.Logs,
+ }
+ if s.traceTransfers && tracer != nil{
+ callRes.Logs = append(callRes.Logs, tracer.Logs()...)
+ }
+ if result.Failed() {
+ callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed)
+ if errors.Is(result.Err, vm.ErrExecutionReverted) {
+ // If the result contains a revert reason, try to unpack it.
+ revertErr := newRevertError(result)
+ callRes.Error = &callError{Message: revertErr.Error(), Code: errCodeReverted, Data: revertErr.ErrorData().(string)}
+ } else {
+ callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeVMError}
+ }
+ } else {
+ callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful)
+ }
+ callResults[i] = callRes
+ }
+
+ header.GasUsed = gasUsed
+ if s.chainConfig.IsCancun(header.Number, new(big.Int).SetUint64(header.Time)) {
+ header.BlobGasUsed = &blobGasUsed
+ }
+ header.Bloom = types.CreateBloom(receipts)
+
+ reqHash := types.CalcRequestsHash([][]byte{})
+ header.RequestsHash = &reqHash
+
+ blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals}
+ blck := types.NewBlock(header, blockBody, receipts, trie.NewStackTrie(nil))
+
+ return blck, callResults, senders, nil
+}
+
+// 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 (s *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
+ var (
+ res = make([]simBlock, 0, len(blocks))
+ base = s.base
+ prevNumber = base.Number
+ prevTimestamp = base.Time
+ )
+ 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)
+ }
+ if block.BlockOverrides.Withdrawals == nil {
+ block.BlockOverrides.Withdrawals = &types.Withdrawals{}
+ }
+ 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)))
+ t := prevTimestamp + timestampIncrement
+ b := simBlock{
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(n),
+ Time: (*hexutil.Uint64)(&t),
+ Withdrawals: &types.Withdrawals{},
+ },
+ }
+ 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
+}
+
+// there is a virtual log being returned by geth on any eth transfer. It is present in geth and we need to figure out how to implement it in EVM.
+// aparently geth removes the extra data field from the block which we ran the call against, while evm includes it.
+// look into how the block hash is being produced -- Probably not worth trying to do.
+// evm includes mix hash where geth does not.
+// look into parent beacon block root and why it appears to be left off from geth.
+// receipt root should be achievable (maybe geth is including the virtual log in the receipts)
+// geth returns a size value where evm appears not to.
+// research why evm is producing a different tx hash
+// evm is not including withdrawals and withdrawals hash in what we return but should.
diff --git a/api/state_transition.go b/api/state_transition.go
index 2ec572ad2..3ac36cf57 100644
--- a/api/state_transition.go
+++ b/api/state_transition.go
@@ -262,7 +262,7 @@ func (st *StateTransition) preCheck() error {
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) && st.evm.Context.BaseFee != nil {
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
- if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
+ if !st.evm.Config.NoBaseFee && st.gasFeeCap.BitLen() == 0 && st.gasTipCap.BitLen() == 0 {
if l := st.gasFeeCap.BitLen(); l > 256 {
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
st.msg.From().Hex(), l)
diff --git a/api/transaction_args.go b/api/transaction_args.go
index 924ca18b4..3a036b128 100644
--- a/api/transaction_args.go
+++ b/api/transaction_args.go
@@ -25,10 +25,13 @@ import (
"github.com/openrelayxyz/cardinal-evm/common/math"
"github.com/openrelayxyz/cardinal-evm/params"
"github.com/openrelayxyz/cardinal-evm/state"
+ "github.com/openrelayxyz/cardinal-evm/crypto/kzg4844"
"github.com/openrelayxyz/cardinal-evm/types"
"github.com/openrelayxyz/cardinal-evm/vm"
"github.com/openrelayxyz/cardinal-rpc"
"github.com/openrelayxyz/cardinal-types/hexutil"
+ "github.com/holiman/uint256"
+ ctypes "github.com/openrelayxyz/cardinal-types"
)
// TransactionArgs represents the arguments to construct a new transaction
@@ -53,9 +56,31 @@ type TransactionArgs struct {
AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
+ // For BlobTxType
+ BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas"`
+ BlobHashes []ctypes.Hash `json:"blobVersionedHashes,omitempty"`
+
+ // For BlobTxType transactions with blob sidecar
+ Blobs []kzg4844.Blob `json:"blobs"`
+ Commitments []kzg4844.Commitment `json:"commitments"`
+ Proofs []kzg4844.Proof `json:"proofs"`
+
AuthList []types.Authorization `json:"authorizationList,omitempty"`
}
+// this utility is being added to confrom to eip1559 protocol which set ups a mutually exclusive condition for args.GasPrice and args.MaxFeePerGas or args.MaxPriorityFeePerGas
+func (args *TransactionArgs) normalize() {
+ if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
+ // 1559 style: drop legacy field
+ args.GasPrice = nil
+ } else if args.GasPrice != nil {
+ // Legacy style: drop 1559 fields
+ args.MaxFeePerGas = nil
+ args.MaxPriorityFeePerGas = nil
+ }
+}
+
+
// from retrieves the transaction sender address.
func (arg *TransactionArgs) from() common.Address {
if arg.From == nil {
@@ -79,6 +104,7 @@ func (arg *TransactionArgs) data() []byte {
// core evm. This method is used in calls and traces that do not require a real
// live transaction.
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (Msg, error) {
+ args.normalize()
// Reject invalid combinations of pre- and post-1559 fee styles
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return Msg{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
@@ -156,12 +182,6 @@ func (args *TransactionArgs) setDefaults(ctx *rpc.CallContext, chainConfig *para
// if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
// return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
// }
- // if args.MaxFeePerGas == nil {
- // args.MaxFeePerGas = (*hexutil.Big)(header.BaseFee)
- // }
- if args.GasPrice == nil {
- args.GasPrice = (*hexutil.Big)(header.BaseFee)
- }
if args.Value == nil {
args.Value = new(hexutil.Big)
}
@@ -169,6 +189,18 @@ func (args *TransactionArgs) setDefaults(ctx *rpc.CallContext, chainConfig *para
nonce := db.GetNonce(*args.From)
args.Nonce = (*hexutil.Uint64)(&nonce)
}
+ if header.BaseFee == nil {
+ if args.GasPrice == nil {
+ args.GasPrice = new(hexutil.Big)
+ }
+ } else {
+ if args.MaxFeePerGas == nil {
+ args.MaxFeePerGas = (*hexutil.Big)(header.BaseFee)
+ }
+ if args.MaxPriorityFeePerGas == nil {
+ args.MaxPriorityFeePerGas = new(hexutil.Big)
+ }
+ }
if args.Gas == nil {
gas, _, err := DoEstimateGas(ctx, getEVM, *args, &PreviousState{db.ALCalcCopy(), header}, blockNrOrHash, header.GasLimit, true, chainConfig)
if err != nil {
@@ -179,6 +211,109 @@ func (args *TransactionArgs) setDefaults(ctx *rpc.CallContext, chainConfig *para
return nil
}
+// ToTransaction converts the arguments to a transaction.
+// This assumes that setDefaults has been called.
+func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
+ usedType := types.LegacyTxType
+ switch {
+ case args.AuthList != nil || defaultType == types.SetCodeTxType:
+ usedType = types.SetCodeTxType
+ case args.BlobHashes != nil || defaultType == types.BlobTxType:
+ usedType = types.BlobTxType
+ case args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType:
+ usedType = types.DynamicFeeTxType
+ case args.AccessList != nil || defaultType == types.AccessListTxType:
+ usedType = types.AccessListTxType
+ }
+ // Make it possible to default to newer tx, but use legacy if gasprice is provided
+ if args.GasPrice != nil {
+ usedType = types.LegacyTxType
+ }
+ var data types.TxData
+ switch usedType {
+ case types.SetCodeTxType:
+ al := types.AccessList{}
+ if args.AccessList != nil {
+ al = *args.AccessList
+ }
+ authList := []types.Authorization{}
+ if args.AuthList != nil {
+ authList = args.AuthList
+ }
+ data = &types.SetCodeTx{
+ To: *args.To,
+ ChainID: uint256.MustFromBig(args.ChainID.ToInt()),
+ Nonce: uint64(*args.Nonce),
+ Gas: uint64(*args.Gas),
+ GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
+ GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
+ Value: uint256.MustFromBig((*big.Int)(args.Value)),
+ Data: args.data(),
+ AccessList: al,
+ AuthList: authList,
+ }
+
+ case types.BlobTxType:
+ al := types.AccessList{}
+ if args.AccessList != nil {
+ al = *args.AccessList
+ }
+ data = &types.BlobTx{
+ To: *args.To,
+ ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)),
+ Nonce: uint64(*args.Nonce),
+ Gas: uint64(*args.Gas),
+ GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
+ GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
+ Value: uint256.MustFromBig((*big.Int)(args.Value)),
+ Data: args.data(),
+ AccessList: al,
+ BlobHashes: args.BlobHashes,
+ BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)),
+ }
+
+ case types.DynamicFeeTxType:
+ al := types.AccessList{}
+ if args.AccessList != nil {
+ al = *args.AccessList
+ }
+ data = &types.DynamicFeeTx{
+ To: args.To,
+ ChainID: (*big.Int)(args.ChainID),
+ Nonce: uint64(*args.Nonce),
+ Gas: uint64(*args.Gas),
+ GasFeeCap: (*big.Int)(args.MaxFeePerGas),
+ GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
+ Value: (*big.Int)(args.Value),
+ Data: args.data(),
+ AccessList: al,
+ }
+
+ case types.AccessListTxType:
+ data = &types.AccessListTx{
+ To: args.To,
+ ChainID: (*big.Int)(args.ChainID),
+ Nonce: uint64(*args.Nonce),
+ Gas: uint64(*args.Gas),
+ GasPrice: (*big.Int)(args.GasPrice),
+ Value: (*big.Int)(args.Value),
+ Data: args.data(),
+ AccessList: *args.AccessList,
+ }
+
+ default:
+ data = &types.LegacyTx{
+ To: args.To,
+ Nonce: uint64(*args.Nonce),
+ Gas: uint64(*args.Gas),
+ GasPrice: (*big.Int)(args.GasPrice),
+ Value: (*big.Int)(args.Value),
+ Data: args.data(),
+ }
+ }
+ return types.NewTx(data)
+}
+
//
// // setDefaults fills in default values for unspecified tx fields.
// func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
diff --git a/cmd/cardinal-evm-rpc/genesisinit.go b/cmd/cardinal-evm-rpc/genesisinit.go
index 0a2f8a201..85f532b19 100644
--- a/cmd/cardinal-evm-rpc/genesisinit.go
+++ b/cmd/cardinal-evm-rpc/genesisinit.go
@@ -9,7 +9,8 @@ import (
"errors"
"github.com/openrelayxyz/cardinal-storage/resolver"
- "github.com/openrelayxyz/cardinal-types"
+ ctypes "github.com/openrelayxyz/cardinal-types"
+ "github.com/openrelayxyz/cardinal-evm/types"
"github.com/openrelayxyz/cardinal-types/hexutil"
"github.com/openrelayxyz/cardinal-evm/common"
"github.com/openrelayxyz/cardinal-evm/crypto"
@@ -21,11 +22,15 @@ import (
type genesisBlock struct {
// init.SetBlockData(r.Hash, r.ParentHash, r.Number, r.Weight.ToInt())
Config params.ChainConfig `json:"config"`
- Hash types.Hash `json:"hash"`
- ParentHash types.Hash `json:"parentHash"`
+ Hash ctypes.Hash `json:"hash"`
+ ParentHash ctypes.Hash `json:"parentHash"`
Number hexutil.Uint64 `json:"number"`
Weight hexutil.Uint64 `json:"difficulty"`
Alloc GenesisAlloc `json:"alloc"`
+ GasLimit hexutil.Uint64 `json:"gasLimit"`
+ Timestamp uint64 `json:"timestamp"`
+ ExtraData hexutil.Bytes `json:"extraData"`
+ MixHash ctypes.Hash `json:"mixhash"`
}
type GenesisAlloc map[string]GenesisAccount
@@ -33,14 +38,15 @@ type GenesisAlloc map[string]GenesisAccount
// GenesisAccount is an account in the state of the genesis block.
type GenesisAccount struct {
Code hexutil.Bytes `json:"code,omitempty"`
- Storage map[types.Hash]types.Hash `json:"storage,omitempty"`
+ Storage map[ctypes.Hash]ctypes.Hash `json:"storage,omitempty"`
Balance *hexutil.Big `json:"balance"`
Nonce hexutil.Uint64 `json:"nonce,omitempty"`
}
func genesisInit(dbpath, genesispath string, archival bool) error {
- gfile, err := os.Open(genesispath)
+ gfile, err := os.Open(genesispath)
+ if err != nil {return err}
decoder := json.NewDecoder(gfile)
var gb genesisBlock
if err := decoder.Decode(&gb); err != nil {
@@ -49,11 +55,24 @@ func genesisInit(dbpath, genesispath string, archival bool) error {
gfile.Close()
init, err := resolver.ResolveInitializer(dbpath, archival)
if err != nil { return err }
- if gb.Hash == (types.Hash{}) {
+ if gb.Hash == (ctypes.Hash{}) {
return errors.New("hash must be set in genesis file")
}
var emptyAccount *state.Account
init.SetBlockData(gb.Hash, gb.ParentHash, uint64(gb.Number), new(big.Int).SetInt64(int64(gb.Weight)))
+ header:= &types.Header{
+ Number: big.NewInt(int64(gb.Number)),
+ ParentHash: ctypes.Hash(gb.ParentHash),
+ Difficulty: big.NewInt(int64(gb.Weight)),
+ GasLimit: uint64(gb.GasLimit),
+ Time: uint64(gb.Timestamp),
+ Extra: gb.ExtraData,
+ MixDigest: ctypes.Hash(gb.MixHash),
+ }
+ rawHeader,_ := rlp.EncodeToBytes(header)
+ headerKey := fmt.Sprintf("c/%x/b/%x/h", gb.Config.ChainID, gb.Hash.Bytes())
+ init.AddData([]byte(headerKey), rawHeader)
+
for addrString, alloc := range gb.Alloc {
addr := common.HexToAddress(addrString)
if len(alloc.Code) != 0 {
diff --git a/eips/eip1559/eip.go b/eips/eip1559/eip.go
new file mode 100644
index 000000000..f81901dcc
--- /dev/null
+++ b/eips/eip1559/eip.go
@@ -0,0 +1,71 @@
+// Copyright 2021 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package eip1559
+
+import (
+ "math/big"
+
+ "github.com/openrelayxyz/cardinal-evm/types"
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/params"
+)
+
+
+// CalcBaseFee calculates the basefee of the header.
+func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
+ // If the current block is the first EIP-1559 block, return the InitialBaseFee.
+ if !config.IsLondon(parent.Number) {
+ return new(big.Int).SetUint64(params.InitialBaseFee)
+ }
+
+ parentGasTarget := parent.GasLimit / config.ElasticityMultiplier()
+ // If the parent gasUsed is the same as the target, the baseFee remains unchanged.
+ if parent.GasUsed == parentGasTarget {
+ return new(big.Int).Set(parent.BaseFee)
+ }
+
+ var (
+ num = new(big.Int)
+ denom = new(big.Int)
+ )
+
+ if parent.GasUsed > parentGasTarget {
+ // If the parent block used more gas than its target, the baseFee should increase.
+ // max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
+ num.SetUint64(parent.GasUsed - parentGasTarget)
+ num.Mul(num, parent.BaseFee)
+ num.Div(num, denom.SetUint64(parentGasTarget))
+ num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
+ if num.Cmp(common.Big1) < 0 {
+ return num.Add(parent.BaseFee, common.Big1)
+ }
+ return num.Add(parent.BaseFee, num)
+ } else {
+ // Otherwise if the parent block used less gas than its target, the baseFee should decrease.
+ // max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
+ num.SetUint64(parentGasTarget - parent.GasUsed)
+ num.Mul(num, parent.BaseFee)
+ num.Div(num, denom.SetUint64(parentGasTarget))
+ num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
+
+ baseFee := num.Sub(parent.BaseFee, num)
+ if baseFee.Cmp(common.Big0) < 0 {
+ baseFee = common.Big0
+ }
+ return baseFee
+ }
+}
diff --git a/go.mod b/go.mod
index 1bc4e2c37..1c49ca9ff 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,8 @@
module github.com/openrelayxyz/cardinal-evm
-go 1.19
+go 1.22
+
+toolchain go1.22.2
require (
github.com/Shopify/sarama v1.28.0
@@ -9,6 +11,7 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0
github.com/davecgh/go-spew v1.1.1
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4
+ github.com/ethereum/go-verkle v0.2.2
github.com/google/gofuzz v1.2.0
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/holiman/uint256 v1.2.4
@@ -37,6 +40,7 @@ require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
+ github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgraph-io/badger/v3 v3.2103.1 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
diff --git a/go.sum b/go.sum
index 5600275f0..e3b51ecae 100644
--- a/go.sum
+++ b/go.sum
@@ -37,6 +37,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I=
+github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -61,6 +63,8 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 h1:B2mpK+MNqgPqk2/KNi1LbqwtZDy5F7iy0mynQiBr8VA=
github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4/go.mod h1:y4GA2JbAUama1S4QwYjC2hefgGLU8Ul0GMtL/ADMF1c=
+github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
+github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
diff --git a/hardfork-tests/.gitignore b/hardfork-tests/.gitignore
new file mode 100644
index 000000000..070a48326
--- /dev/null
+++ b/hardfork-tests/.gitignore
@@ -0,0 +1,4 @@
+data/
+.venv
+venv
+__pycache__
\ No newline at end of file
diff --git a/hardfork-tests/collect.py b/hardfork-tests/collect.py
new file mode 100644
index 000000000..62eb60d91
--- /dev/null
+++ b/hardfork-tests/collect.py
@@ -0,0 +1,255 @@
+import argparse
+import requests,json, gzip
+
+Payloads = [
+ {
+ # Simple transfer
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [{
+ "blockOverrides": {"baseFeePerGas": "0x9"},
+ "stateOverrides": {
+ "0xc000000000000000000000000000000000000000": {"balance": "0x4a817c800"}
+ },
+ "calls": [
+ {
+ "from": "0xc000000000000000000000000000000000000000",
+ "to": "0xc000000000000000000000000000000000000001",
+ "maxFeePerGas": "0xf",
+ "value": "0x1",
+ "gas": "0x5208"
+ },
+ {
+ "from": "0xc000000000000000000000000000000000000000",
+ "to": "0xc000000000000000000000000000000000000002",
+ "maxFeePerGas": "0xf",
+ "value": "0x1",
+ "gas": "0x5208"
+ }
+ ]
+ }],
+ "validation": True,
+ "traceTransfers": True
+ }],
+ },
+ # complete test payload
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [{
+ "blockOverrides": {"baseFeePerGas": "0x9", "gasLimit": "0x1c9c380"},
+ "stateOverrides": {
+ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045": {"balance": "0x4a817c420"}
+ },
+ "calls": [{
+ "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
+ "to": "0x014d023e954bAae7F21E56ed8a5d81b12902684D",
+ "gas": "0x5208",
+ "maxFeePerGas": "0xf",
+ "value": "0x1"
+ }]
+ }],
+ "validation": True,
+ "traceTransfers": True
+ }]
+ },
+ # precompile ecrecover
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [{
+ "stateOverrides": {
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {"balance": "0x56bc75e2d63100000"}
+ },
+ "calls": [{
+ "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "to": "0x0000000000000000000000000000000000000001",
+ "data": "0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3000000000000000000000000000000000000000000000000000000000000001c9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608f90e5c4da9e4c60030b6d02a2ae8c5be86f0088b8c5ccbb82ba1e2e3f0c3ab5c4b",
+ "gas": "0x10000"
+ }]
+ }]
+ }]
+ },
+ # contact creation
+ # Contract creation - deploy simple contract
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [{
+ "blockOverrides": {"baseFeePerGas": "0x9"},
+ "stateOverrides": {
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {"balance": "0x56bc75e2d63100000"}
+ },
+ "calls": [{
+ "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "data": "0x608060405234801561000f575f80fd5b50603e80601b5f395ff3fe60806040525f80fdfea2646970667358221220",
+ "gas": "0x186a0",
+ "maxFeePerGas": "0x3b9aca00"
+ }]
+ }],
+ "validation": True
+ }]
+ },
+ # trace multi calls
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [{
+ "stateOverrides": {
+ "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": {"balance": "0x56bc75e2d630e00000"}
+ },
+ "calls": [
+ {
+ "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
+ "to": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
+ "value": "0xde0b6b3a7640000"
+ },
+ {
+ "from": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
+ "to": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
+ "value": "0x6f05b59d3b20000"
+ }
+ ]
+ }],
+ "traceTransfers": True
+ }]
+ },
+ # comprehensive mult block state calls, storage and code overrides
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "eth_simulateV1",
+ "params": [{
+ "blockStateCalls": [
+ {
+ "blockOverrides": {
+ "baseFeePerGas": "0xa",
+ "gasLimit": "0x1c9c380"
+ },
+ "stateOverrides": {
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {
+ "balance": "0x56BC75E2D63100000"
+ },
+ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045": {
+ "balance": "0xDE0B6B3A7640000",
+ "code": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006001905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b92915050565b56fea264697066735822122042",
+ "storage": {
+ "0x0": "0x2a",
+ "0x1": "0x539"
+ }
+ }
+ },
+ "calls": [
+ {
+ "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
+ "data": "0xc2985578",
+ "gas": "0x30000",
+ "maxFeePerGas": "0x10",
+ "value": "0x0"
+ }
+ ]
+ },
+ {
+ "blockOverrides": {
+ "baseFeePerGas": "0xb",
+ "gasLimit": "0x1c9c380"
+ },
+ "stateOverrides": {
+ "0xc000000000000000000000000000000000000000": {
+ "balance": "0x56BC75E2D63100000",
+ "storage": {
+ "0x0": "0x100",
+ "0x5": "0xdeadbeef"
+ }
+ },
+ "0x70997970c51812dc3a010c7d01b50e0d17dc79c8": {
+ "balance": "0x1BC16D674EC80000"
+ }
+ },
+ "calls": [
+ {
+ "from": "0xc000000000000000000000000000000000000000",
+ "to": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
+ "value": "0xDE0B6B3A7640000",
+ "gas": "0x5208",
+ "maxFeePerGas": "0x12"
+ }
+ ]
+ },
+ {
+ "blockOverrides": {
+ "baseFeePerGas": "0xc",
+ "gasLimit": "0x1c9c380"
+ },
+ "stateOverrides": {
+ "0x014d023e954bAae7F21E56ed8a5d81b12902684D": {
+ "balance": "0x3635C9ADC5DEA00000",
+ "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220",
+ "storage": {
+ "0x0": "0x7b"
+ }
+ },
+ "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": {
+ "balance": "0xDE0B6B3A7640000"
+ }
+ },
+ "calls": [
+ {
+ "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
+ "to": "0x014d023e954bAae7F21E56ed8a5d81b12902684D",
+ "data": "0x6057361d000000000000000000000000000000000000000000000000000000000000007b",
+ "gas": "0x40000",
+ "maxFeePerGas": "0x14",
+ "value": "0x0"
+ },
+ {
+ "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
+ "to": "0x014d023e954bAae7F21E56ed8a5d81b12902684D",
+ "data": "0x2e64cec1",
+ "gas": "0x30000",
+ "maxFeePerGas": "0x14",
+ "value": "0x0"
+ }
+ ]
+ }
+ ],
+ "validation": True,
+ "traceTransfers": True
+ }]
+ }
+ ]
+
+def gather_data(url):
+ results = []
+ for i in Payloads:
+ res= requests.post(url, json=i)
+ if res.status_code == 200:
+ results.append(res.json().get("result"))
+ else:
+ print(f"error calling {i["method"]}: {res.text}")
+
+ return results
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-e", "--endpoint", required=True)
+ args = parser.parse_args()
+
+ data = gather_data(args.endpoint)
+ if data:
+ with gzip.open("./resources/control-data.json.gz", "wt", compresslevel=5) as fo:
+ json.dump(data, fo)
+
+
+
\ No newline at end of file
diff --git a/hardfork-tests/requirements.txt b/hardfork-tests/requirements.txt
new file mode 100644
index 000000000..3dbbf4ec6
--- /dev/null
+++ b/hardfork-tests/requirements.txt
@@ -0,0 +1,10 @@
+certifi==2025.10.5
+charset-normalizer==3.4.4
+idna==3.11
+iniconfig==2.1.0
+packaging==25.0
+pluggy==1.6.0
+Pygments==2.19.2
+pytest==8.4.2
+requests==2.32.5
+urllib3==2.5.0
diff --git a/hardfork-tests/resources/config.yaml b/hardfork-tests/resources/config.yaml
new file mode 100644
index 000000000..bb5e85985
--- /dev/null
+++ b/hardfork-tests/resources/config.yaml
@@ -0,0 +1,13 @@
+http.port: 8000
+chainid: 7092415936
+log.level: 2
+datadir: /Users/jesseakoh/Desktop/work/code/openrelay/cardinal-evm/hardfork-tests/fd5-data
+reorg.threshold: 128
+cloudwatch:
+ namespace: cardinal
+ dimensions:
+ network: fd5
+#topic.transactions: hoodi-tx
+block.wait.ms: 2000
+brokers:
+ - url: "null://"
\ No newline at end of file
diff --git a/hardfork-tests/resources/control-data.json.gz b/hardfork-tests/resources/control-data.json.gz
new file mode 100644
index 000000000..031674531
Binary files /dev/null and b/hardfork-tests/resources/control-data.json.gz differ
diff --git a/hardfork-tests/resources/genesis.json b/hardfork-tests/resources/genesis.json
new file mode 100644
index 000000000..f3f70cc0a
--- /dev/null
+++ b/hardfork-tests/resources/genesis.json
@@ -0,0 +1,934 @@
+{
+ "hash": "0x482478a8edda693bcad4f504b8654165ec52382f8b04f5f66fc477452e3a4c25",
+ "config": {
+ "chainId": 70722,
+ "homesteadBlock": 0,
+ "eip150Block": 0,
+ "eip155Block": 0,
+ "eip158Block": 0,
+ "byzantiumBlock": 0,
+ "constantinopleBlock": 0,
+ "petersburgBlock": 0,
+ "istanbulBlock": 0,
+ "berlinBlock": 0,
+ "londonBlock": 0,
+ "mergeNetsplitBlock": 0,
+ "terminalTotalDifficulty": 0,
+ "terminalTotalDifficultyPassed": true,
+ "shanghaiTime": 0,
+ "cancunTime": 0,
+ "depositContractAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa",
+ "pragueTime": 0,
+ "osakaTime": 0,
+ "bpo1Time": 0,
+ "bpo2Time": 0,
+ "bpo3Time": 0,
+ "bpo4Time": 0,
+ "bpo5Time": 0
+ },
+ "alloc": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000001": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000002": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000003": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000004": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000005": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000006": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000007": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000008": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000009": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000010": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000011": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000012": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000013": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000014": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000015": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000016": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000017": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000018": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000019": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000020": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000021": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000022": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000023": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000024": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000025": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000026": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000027": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000028": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000029": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000030": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000031": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000032": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000033": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000034": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000035": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000036": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000037": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000038": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000039": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000040": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000041": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000042": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000043": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000044": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000045": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000046": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000047": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000048": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000049": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000050": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000051": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000052": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000053": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000054": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000055": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000056": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000057": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000058": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000059": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000060": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000061": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000062": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000063": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000064": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000065": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000066": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000067": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000068": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000069": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000070": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000071": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000072": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000073": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000074": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000075": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000076": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000077": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000078": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000079": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000080": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000081": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000082": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000083": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000084": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000085": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000086": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000087": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000088": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000089": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000090": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000091": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000092": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000093": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000094": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000095": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000096": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000097": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000098": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000099": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009f": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000aa": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ab": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ac": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ad": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ae": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000af": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ba": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000be": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bf": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ca": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ce": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cf": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000da": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000db": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000dc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000dd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000de": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000df": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ea": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000eb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ec": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ed": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ee": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ef": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fa": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fe": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ff": {
+ "balance": "0x1"
+ },
+ "0x00000000219ab540356cBB839Cbe05303d7705Fa": {
+ "balance": "0x0",
+ "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
+ "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
+ "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c",
+ "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c",
+ "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30",
+ "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1",
+ "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c",
+ "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193",
+ "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1",
+ "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
+ "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
+ "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f",
+ "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e",
+ "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784",
+ "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb",
+ "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb",
+ "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab",
+ "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4",
+ "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f",
+ "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa",
+ "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c",
+ "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167",
+ "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7",
+ "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0",
+ "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544",
+ "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765",
+ "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4",
+ "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1",
+ "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636",
+ "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c",
+ "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7"
+ }
+ },
+ "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"
+ },
+ "0x0000F90827F1C53a10cb7A02335B175320002935": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500"
+ },
+ "0x00000961Ef480Eb55e80D19ad83579A64c007002": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ }
+ },
+ "0x0000BBdDc7CE488642fb579F8B00f3a590007251": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ }
+ },
+ "0x454b0EA7d8aD3C56D0CF2e44Ed97b2Feab4D7AF2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xd3248BA3E5492D767F8e427Cb9C7B9D5C3972D7B": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xAD01b55d7c3448B8899862eb335FBb17075d8DE2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x7e454a14B8e7528465eeF86f0DC1da4f235d9D79": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x7a40026A3b9A41754a95EeC8c92C6B99886f440C": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x8c4D8CDD1f474510Dd70D66F2785a3a38a29AC1A": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xfC7360b3b28cf4204268A8354dbEc60720d155D2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x2F7626bBDb8c0f9071bC98046Ef6fDed2167F97F": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x752CE31Dec0dde7D1563CdF6438d892De2D4FBee": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x455f42d91096c4Aa708D7Cbcb2DC499dE89C402c": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x85154341488732D57a97F54AB9706Bc4B71B8636": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x6a9CcA73d4Ff3a249fa778C7651f4Df8B9fFa0Df": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xee2d0567AAe8080CA269b7908F4aF8BBb59A6804": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xDd8D4027078a471816e4Ef7F69aFc0A5d2947dDc": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x20466E9A67f299F6056bE52A50ea324FA6Bd05D5": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x03F24BB0C9cfb30217Ff992A36ae9230F2A1697f": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x032d8372C519c3927b87BDe4479E846a81EF2d10": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xF863DF14954df73804b3150F3754a8F98CBB1D0d": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xbe918A6aef1920F3706E23d153146aA6C5982620": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xA0c7edA3CE474BC670A11EA9537cBEfd36331123": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xF03b43BeB861044492Eb43E247bEE2AC6C80c651": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ }
+ },
+ "coinbase": "0x0000000000000000000000000000000000000000",
+ "difficulty": "0x0",
+ "extraData": "",
+ "gasLimit": "0x2aea540",
+ "nonce": "0x4d2",
+ "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "timestamp": 1757512500
+}
+
diff --git a/hardfork-tests/resources/master-genesis.json b/hardfork-tests/resources/master-genesis.json
new file mode 100644
index 000000000..34fc77825
--- /dev/null
+++ b/hardfork-tests/resources/master-genesis.json
@@ -0,0 +1,958 @@
+{
+ "hash": "0x482478a8edda693bcad4f504b8654165ec52382f8b04f5f66fc477452e3a4c25",
+ "config": {
+ "chainId": 70722,
+ "homesteadBlock": 0,
+ "eip150Block": 0,
+ "eip155Block": 0,
+ "eip158Block": 0,
+ "byzantiumBlock": 0,
+ "constantinopleBlock": 0,
+ "petersburgBlock": 0,
+ "istanbulBlock": 0,
+ "berlinBlock": 0,
+ "londonBlock": 0,
+ "mergeNetsplitBlock": 0,
+ "terminalTotalDifficulty": 0,
+ "terminalTotalDifficultyPassed": true,
+ "shanghaiTime": 0,
+ "cancunTime": 0,
+ "depositContractAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa",
+ "pragueTime": 0,
+ "osakaTime": 0,
+ "bpo1Time": 0,
+ "bpo2Time": 0,
+ "blobSchedule": {
+ "cancun": {
+ "target": 3,
+ "max": 6,
+ "baseFeeUpdateFraction": 3338477
+ },
+ "prague": {
+ "target": 6,
+ "max": 9,
+ "baseFeeUpdateFraction": 5007716
+ },
+ "osaka": {
+ "target": 6,
+ "max": 9,
+ "baseFeeUpdateFraction": 5007716
+ },
+ "bpo1": {
+ "target": 10,
+ "max": 15,
+ "baseFeeUpdateFraction": 8346193
+ },
+ "bpo2": {
+ "target": 14,
+ "max": 21,
+ "baseFeeUpdateFraction": 11684671
+ }
+ }
+ },
+ "alloc": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000001": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000002": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000003": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000004": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000005": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000006": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000007": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000008": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000009": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000000f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000010": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000011": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000012": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000013": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000014": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000015": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000016": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000017": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000018": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000019": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000001f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000020": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000021": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000022": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000023": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000024": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000025": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000026": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000027": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000028": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000029": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000002f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000030": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000031": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000032": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000033": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000034": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000035": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000036": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000037": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000038": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000039": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000003f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000040": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000041": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000042": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000043": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000044": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000045": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000046": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000047": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000048": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000049": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000004f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000050": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000051": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000052": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000053": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000054": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000055": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000056": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000057": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000058": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000059": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000005f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000060": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000061": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000062": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000063": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000064": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000065": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000066": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000067": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000068": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000069": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000006f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000070": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000071": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000072": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000073": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000074": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000075": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000076": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000077": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000078": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000079": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000007f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000080": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000081": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000082": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000083": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000084": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000085": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000086": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000087": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000088": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000089": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000008f": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000090": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000091": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000092": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000093": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000094": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000095": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000096": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000097": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000098": {
+ "balance": "0x1"
+ },
+ "0x0000000000000000000000000000000000000099": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009a": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009b": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009c": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009d": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009e": {
+ "balance": "0x1"
+ },
+ "0x000000000000000000000000000000000000009f": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000a9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000aa": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ab": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ac": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ad": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ae": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000af": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000b9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ba": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000be": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000bf": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000c9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ca": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ce": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000cf": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000d9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000da": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000db": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000dc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000dd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000de": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000df": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000e9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ea": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000eb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ec": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ed": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ee": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ef": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f0": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f1": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f2": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f3": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f4": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f5": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f6": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f7": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f8": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000f9": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fa": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fb": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fc": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fd": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000fe": {
+ "balance": "0x1"
+ },
+ "0x00000000000000000000000000000000000000ff": {
+ "balance": "0x1"
+ },
+ "0x00000000219ab540356cBB839Cbe05303d7705Fa": {
+ "balance": "0x0",
+ "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
+ "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
+ "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c",
+ "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c",
+ "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30",
+ "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1",
+ "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c",
+ "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193",
+ "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1",
+ "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
+ "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
+ "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f",
+ "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e",
+ "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784",
+ "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb",
+ "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb",
+ "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab",
+ "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4",
+ "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f",
+ "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa",
+ "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c",
+ "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167",
+ "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7",
+ "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0",
+ "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544",
+ "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765",
+ "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4",
+ "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1",
+ "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636",
+ "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c",
+ "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7"
+ }
+ },
+ "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"
+ },
+ "0x0000F90827F1C53a10cb7A02335B175320002935": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500"
+ },
+ "0x00000961Ef480Eb55e80D19ad83579A64c007002": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ }
+ },
+ "0x0000BBdDc7CE488642fb579F8B00f3a590007251": {
+ "balance": "0x0",
+ "nonce": "0x1",
+ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ }
+ },
+ "0x454b0EA7d8aD3C56D0CF2e44Ed97b2Feab4D7AF2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xd3248BA3E5492D767F8e427Cb9C7B9D5C3972D7B": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xAD01b55d7c3448B8899862eb335FBb17075d8DE2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x7e454a14B8e7528465eeF86f0DC1da4f235d9D79": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x7a40026A3b9A41754a95EeC8c92C6B99886f440C": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x8c4D8CDD1f474510Dd70D66F2785a3a38a29AC1A": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xfC7360b3b28cf4204268A8354dbEc60720d155D2": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x2F7626bBDb8c0f9071bC98046Ef6fDed2167F97F": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x752CE31Dec0dde7D1563CdF6438d892De2D4FBee": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x455f42d91096c4Aa708D7Cbcb2DC499dE89C402c": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x85154341488732D57a97F54AB9706Bc4B71B8636": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x6a9CcA73d4Ff3a249fa778C7651f4Df8B9fFa0Df": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xee2d0567AAe8080CA269b7908F4aF8BBb59A6804": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xDd8D4027078a471816e4Ef7F69aFc0A5d2947dDc": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x20466E9A67f299F6056bE52A50ea324FA6Bd05D5": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x03F24BB0C9cfb30217Ff992A36ae9230F2A1697f": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0x032d8372C519c3927b87BDe4479E846a81EF2d10": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xF863DF14954df73804b3150F3754a8F98CBB1D0d": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xbe918A6aef1920F3706E23d153146aA6C5982620": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xA0c7edA3CE474BC670A11EA9537cBEfd36331123": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ },
+ "0xF03b43BeB861044492Eb43E247bEE2AC6C80c651": {
+ "balance": "0x33b2e3c9fd0803ce8000000"
+ }
+ },
+ "coinbase": "0x0000000000000000000000000000000000000000",
+ "difficulty": "0x0",
+ "extraData": "",
+ "gasLimit": "0x2aea540",
+ "nonce": "0x4d2",
+ "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "timestamp": "1757512500"
+}
+
diff --git a/hardfork-tests/resources/null-test-config.yaml b/hardfork-tests/resources/null-test-config.yaml
new file mode 100644
index 000000000..e541f14fc
--- /dev/null
+++ b/hardfork-tests/resources/null-test-config.yaml
@@ -0,0 +1,13 @@
+http.port: 8000
+chainid: 70722
+log.level: 2
+datadir: ./data
+reorg.threshold: 128
+cloudwatch:
+ namespace: cardinal
+ dimensions:
+ network: IntegrationTest
+#topic.transactions: hoodi-tx
+block.wait.ms: 2000
+brokers:
+ - url: "null://"
diff --git a/hardfork-tests/simv1.py b/hardfork-tests/simv1.py
new file mode 100644
index 000000000..6451783b0
--- /dev/null
+++ b/hardfork-tests/simv1.py
@@ -0,0 +1,132 @@
+import subprocess
+import requests
+import pytest, logging
+import argparse
+import os, time, json, gzip, shutil
+from collect import Payloads
+
+logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
+
+node = None
+
+ignored_keys = ['blockHash', 'hash', 'stateRoot', 'size', 'parentHash']
+
+def start_node(bin_path):
+ global node
+ bin_path = os.path.abspath(bin_path)
+ if not os.path.exists("./data"):
+ os.mkdir("./data")
+ else:
+ shutil.rmtree("./data")
+ os.mkdir("./data")
+
+ node = subprocess.Popen([
+ bin_path, "--debug", f"-init.genesis=./resources/genesis.json", "./resources/null-test-config.yaml"
+ ])
+ time.sleep(3)
+
+def gather_data(endpoint=None):
+ logging.info("running method")
+ url = endpoint if endpoint else "http://localhost:8000"
+ results = []
+ for i,j in enumerate(Payloads):
+ response = requests.post(url, json=j)
+ if response.status_code == 200:
+ results.append(response.json().get("result"))
+ else:
+ raise Exception(f"error calling method {i} :{response.text}")
+
+ output_file = os.path.join(os.path.dirname(__file__), "./resources/cardinal_test.json")
+ with open(output_file, "w") as f:
+ json.dump(results, f)
+
+ return output_file
+
+def compare_dicts(control, test, path=""):
+ control_keys = set(k for k in control.keys() if k not in ignored_keys)
+ test_keys = set(k for k in test.keys() if k not in ignored_keys)
+
+ if control_keys != test_keys:
+ missing = control_keys - test_keys
+ extra = test_keys - control_keys
+ if missing:
+ pytest.fail(f"Missing keys in test at {path}: {missing}")
+ if extra:
+ pytest.fail(f"Extra keys in test at {path}: {extra}")
+
+ for key in control.keys():
+ if key in ignored_keys:
+ continue
+
+ new_path = f"{path}.{key}" if path else key
+
+ if key not in test:
+ pytest.fail(f"Missing key '{key}' in test at {new_path}")
+
+ compare_values(control[key], test[key], new_path)
+
+def compare_lists(control, test, path=""):
+ if len(control) != len(test):
+ pytest.fail(f"List length mismatch at {path}: expected {len(control)}, got {len(test)}")
+
+ for i, (control_item, test_item) in enumerate(zip(control, test)):
+ new_path = f"{path}[{i}]"
+ compare_values(control_item, test_item, new_path)
+
+def compare_values(control, test, path=""):
+ if type(control) != type(test):
+ pytest.fail(f"Type mismatch at {path}: expected {type(control).__name__}, got {type(test).__name__}")
+ elif isinstance(control, dict):
+ compare_dicts(control, test, path)
+ elif isinstance(control, list):
+ compare_lists(control, test, path)
+ elif control != test:
+ pytest.fail(f"Value mismatch at {path}: expected {control}, got {test}")
+
+
+def compare_results():
+ with gzip.open('./resources/control-data.json.gz', "rb") as f:
+ with open('./resources/cardinal_control.json', "wb") as f_o:
+ shutil.copyfileobj(f, f_o)
+
+ with open('./resources/cardinal_test.json', 'r') as cf:
+ test_data = json.load(cf)
+
+ with open('./resources/cardinal_control.json', 'r') as cf:
+ control_data = json.load(cf)
+
+ compare_values(control_data, test_data, path="result")
+
+
+def run_test(args):
+ if args.binary_path:
+ start_node(args.binary_path)
+ try:
+ gather_data(args.endpoint)
+ compare_results()
+ logging.info("test passed")
+ finally:
+ if args.binary_path and node:
+ node.terminate()
+ node.wait()
+ print("node terminated")
+ cleanup()
+
+def cleanup():
+ logging.info("cleaning up")
+ files_to_remove = [
+ './resources/cardinal_control.json',
+ './resources/cardinal_test.json'
+ ]
+
+ for path in files_to_remove:
+ if os.path.exists(path):
+ os.remove(path)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-p", "--binary_path")
+ parser.add_argument("-e", "--endpoint", default='http://localhost:8000')
+ args = parser.parse_args()
+
+ run_test(args)
diff --git a/params/config.go b/params/config.go
index f4909b3e3..36e65f2d7 100644
--- a/params/config.go
+++ b/params/config.go
@@ -467,6 +467,66 @@ var (
},
}
+ IntegrationTestChainConfig = &ChainConfig{
+ ChainID: big.NewInt(70722),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: nil,
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ByzantiumBlock: big.NewInt(0),
+ ConstantinopleBlock: big.NewInt(0),
+ PetersburgBlock: big.NewInt(0),
+ IstanbulBlock: big.NewInt(0),
+ MuirGlacierBlock: big.NewInt(0),
+ BerlinBlock: big.NewInt(0),
+ LondonBlock: big.NewInt(0),
+ ShanghaiTime: big.NewInt(0),
+ CancunTime: big.NewInt(0),
+ PragueTime: big.NewInt(0),
+ OsakaTime: big.NewInt(0),
+ Ethash: new(EthashConfig),
+ Engine: ETHashEngine,
+ BlobSchedule: []*BlobConfig{
+ // Cancun
+ &BlobConfig{
+ ActivationTime: 0,
+ Target: 3,
+ Max : 6,
+ UpdateFraction: 3338477,
+ },
+ // Prague
+ &BlobConfig{
+ ActivationTime: 0,
+ Target: 6,
+ Max : 9,
+ UpdateFraction: 5007716,
+ },
+ // Osaka
+ &BlobConfig{
+ ActivationTime: 0,
+ Target: 6,
+ Max: 9,
+ UpdateFraction: 5007716,
+ },
+ // BP01
+ &BlobConfig{
+ ActivationTime: 0,
+ Target: 10,
+ Max: 15,
+ UpdateFraction: 8346193,
+ },
+ // BP02
+ &BlobConfig{
+ ActivationTime: 0,
+ Target: 14,
+ Max: 21,
+ UpdateFraction: 11684671,
+ },
+ },
+ }
+
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Ethash consensus.
//
@@ -498,6 +558,7 @@ var ChainLookup = map[int64]*ChainConfig{
1337802: KilnChainConfig,
11155111: SepoliaChainConfig,
560048: HoodiChainConfig,
+ 70722: IntegrationTestChainConfig,
}
// ChainConfig is the core config which determines the blockchain settings.
diff --git a/params/protocol_params.go b/params/protocol_params.go
index e5da6d592..ea99f9378 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -16,7 +16,9 @@
package params
-import "math/big"
+import (
+ "math/big"
+)
const (
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
@@ -169,7 +171,6 @@ const (
BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs
BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
- BlobTxTargetBlobGasPerBlock = 1 << 18 // Target consumable blob gas for data blobs per block (for 1559-like pricing)
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
BlobTxBlobGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for blob gas price
@@ -195,4 +196,4 @@ var (
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
-)
+)
\ No newline at end of file
diff --git a/state/interface.go b/state/interface.go
index b31b8a96f..3ccd4fb6a 100644
--- a/state/interface.go
+++ b/state/interface.go
@@ -66,6 +66,8 @@ type StateDB interface {
Copy() StateDB
ALCalcCopy() StateDB
Finalise()
+ GetLogs(hash ctypes.Hash, blockNumber uint64, blockHash ctypes.Hash) []*types.Log
+ SetTxContext(thash ctypes.Hash, ti int)
// ForEachStorage(common.Address, func(ctypes.Hash, ctypes.Hash) bool) error
}
diff --git a/state/state_object.go b/state/state_object.go
index aa10d9f5d..893fbde29 100644
--- a/state/state_object.go
+++ b/state/state_object.go
@@ -111,7 +111,6 @@ func (s *stateObject) equal(b *stateObject) bool {
}
func (s *stateObject) copy() *stateObject {
-
state := &stateObject{
address: s.address,
account: s.account,
@@ -128,6 +127,9 @@ func (s *stateObject) copy() *stateObject {
if s.nonce != nil {
state.nonce = &(*s.nonce)
}
+ if s.fakeBalance != nil {
+ state.fakeBalance = new(big.Int).Set(s.fakeBalance)
+ }
return state
}
diff --git a/state/statedb.go b/state/statedb.go
index 192bf3124..af18f6903 100644
--- a/state/statedb.go
+++ b/state/statedb.go
@@ -43,6 +43,10 @@ type stateDB struct {
refund uint64
accessList *accessList
alcalc bool
+ logs map[ctypes.Hash][]*types.Log
+ thash ctypes.Hash
+ txIndex int
+ logSize uint
}
func NewStateDB(tx storage.Transaction, chainid int64) StateDB {
@@ -165,6 +169,9 @@ func (sdb *stateDB) AddBalance(addr common.Address, amount *big.Int) {
}
func (sdb *stateDB) GetBalance(addr common.Address) *big.Int {
sobj := sdb.getAccount(addr)
+ if sobj.fakeBalance != nil {
+ return sobj.getBalance()
+ }
if !sobj.loadAccount(sdb.tx, sdb.chainid) {
return common.Big0
}
@@ -345,10 +352,21 @@ func (sdb *stateDB) RevertToSnapshot(snap int) {
sdb.journal = sdb.journal[:snap]
}
func (sdb *stateDB) Snapshot() int { return len(sdb.journal) }
-func (sdb *stateDB) AddLog(*types.Log) {
- // At this time, I don't think we have any features that require logs to
- // actually be tracked, but we'll leave this as a placeholder so if we ever
- // need it we don't have to rework it back into the EVM
+
+func (sdb *stateDB) AddLog(log *types.Log) {
+
+ sdb.journal = append(sdb.journal, journalEntry{nil, func(sdb *stateDB) {
+ logs := sdb.logs[sdb.thash]
+ if len(logs) > 0 {
+ sdb.logs[sdb.thash] = logs[:len(logs)-1]
+ sdb.logSize--
+ }
+ }})
+ log.TxHash = sdb.thash
+ log.TxIndex = uint(sdb.txIndex)
+ log.Index = sdb.logSize
+ sdb.logs[sdb.thash] = append(sdb.logs[sdb.thash], log)
+ sdb.logSize++
}
func (sdb *stateDB) AddPreimage(ctypes.Hash, []byte) {
// I doubt we'll ever support preimage tracking, but easier to leave a
@@ -356,3 +374,25 @@ func (sdb *stateDB) AddPreimage(ctypes.Hash, []byte) {
}
// func (sdb *stateDB) ForEachStorage(addr common.Address, func(ctypes.Hash, ctypes.Hash) bool) error {return nil}
+
+// GetLogs returns the logs matching the specified transaction hash, and annotates
+// them with the given blockNumber and blockHash.
+func (s *stateDB) GetLogs(hash ctypes.Hash, blockNumber uint64, blockHash ctypes.Hash) []*types.Log {
+ logs := s.logs[hash]
+ for _, l := range logs {
+ l.BlockNumber = blockNumber
+ l.BlockHash = blockHash
+ }
+ return logs
+}
+
+// SetTxContext sets the current transaction hash and index which are
+// used when the EVM emits new state logs. It should be invoked before
+// transaction execution.
+func (s *stateDB) SetTxContext(thash ctypes.Hash, ti int) {
+ if s.logs == nil {
+ s.logs = make(map[ctypes.Hash][]*types.Log)
+ }
+ s.thash = thash
+ s.txIndex = ti
+}
diff --git a/trie/bytepool.go b/trie/bytepool.go
new file mode 100644
index 000000000..31be7ae74
--- /dev/null
+++ b/trie/bytepool.go
@@ -0,0 +1,101 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+// bytesPool is a pool for byte slices. It is safe for concurrent use.
+type bytesPool struct {
+ c chan []byte
+ w int
+}
+
+// newBytesPool creates a new bytesPool. The sliceCap sets the capacity of
+// newly allocated slices, and the nitems determines how many items the pool
+// will hold, at maximum.
+func newBytesPool(sliceCap, nitems int) *bytesPool {
+ return &bytesPool{
+ c: make(chan []byte, nitems),
+ w: sliceCap,
+ }
+}
+
+// get returns a slice. Safe for concurrent use.
+func (bp *bytesPool) get() []byte {
+ select {
+ case b := <-bp.c:
+ return b
+ default:
+ return make([]byte, 0, bp.w)
+ }
+}
+
+// getWithSize returns a slice with specified byte slice size.
+func (bp *bytesPool) getWithSize(s int) []byte {
+ b := bp.get()
+ if cap(b) < s {
+ return make([]byte, s)
+ }
+ return b[:s]
+}
+
+// put returns a slice to the pool. Safe for concurrent use. This method
+// will ignore slices that are too small or too large (>3x the cap)
+func (bp *bytesPool) put(b []byte) {
+ if c := cap(b); c < bp.w || c > 3*bp.w {
+ return
+ }
+ select {
+ case bp.c <- b:
+ default:
+ }
+}
+
+// unsafeBytesPool is a pool for byte slices. It is not safe for concurrent use.
+type unsafeBytesPool struct {
+ items [][]byte
+ w int
+}
+
+// newUnsafeBytesPool creates a new unsafeBytesPool. The sliceCap sets the
+// capacity of newly allocated slices, and the nitems determines how many
+// items the pool will hold, at maximum.
+func newUnsafeBytesPool(sliceCap, nitems int) *unsafeBytesPool {
+ return &unsafeBytesPool{
+ items: make([][]byte, 0, nitems),
+ w: sliceCap,
+ }
+}
+
+// Get returns a slice with pre-allocated space.
+func (bp *unsafeBytesPool) get() []byte {
+ if len(bp.items) > 0 {
+ last := bp.items[len(bp.items)-1]
+ bp.items = bp.items[:len(bp.items)-1]
+ return last
+ }
+ return make([]byte, 0, bp.w)
+}
+
+// put returns a slice to the pool. This method will ignore slices that are
+// too small or too large (>3x the cap)
+func (bp *unsafeBytesPool) put(b []byte) {
+ if c := cap(b); c < bp.w || c > 3*bp.w {
+ return
+ }
+ if len(bp.items) < cap(bp.items) {
+ bp.items = append(bp.items, b)
+ }
+}
diff --git a/trie/encoding.go b/trie/encoding.go
new file mode 100644
index 000000000..4cd29f531
--- /dev/null
+++ b/trie/encoding.go
@@ -0,0 +1,156 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+// Trie keys are dealt with in three distinct encodings:
+//
+// KEYBYTES encoding contains the actual key and nothing else. This encoding is the
+// input to most API functions.
+//
+// HEX encoding contains one byte for each nibble of the key and an optional trailing
+// 'terminator' byte of value 0x10 which indicates whether or not the node at the key
+// contains a value. Hex key encoding is used for nodes loaded in memory because it's
+// convenient to access.
+//
+// COMPACT encoding is defined by the Ethereum Yellow Paper (it's called "hex prefix
+// encoding" there) and contains the bytes of the key and a flag. The high nibble of the
+// first byte contains the flag; the lowest bit encoding the oddness of the length and
+// the second-lowest encoding whether the node at the key is a value node. The low nibble
+// of the first byte is zero in the case of an even number of nibbles and the first nibble
+// in the case of an odd number. All remaining nibbles (now an even number) fit properly
+// into the remaining bytes. Compact encoding is used for nodes stored on disk.
+
+func hexToCompact(hex []byte) []byte {
+ terminator := byte(0)
+ if hasTerm(hex) {
+ terminator = 1
+ hex = hex[:len(hex)-1]
+ }
+ buf := make([]byte, len(hex)/2+1)
+ buf[0] = terminator << 5 // the flag byte
+ if len(hex)&1 == 1 {
+ buf[0] |= 1 << 4 // odd flag
+ buf[0] |= hex[0] // first nibble is contained in the first byte
+ hex = hex[1:]
+ }
+ decodeNibbles(hex, buf[1:])
+ return buf
+}
+
+// hexToCompactInPlace places the compact key in input buffer, returning the compacted key.
+func hexToCompactInPlace(hex []byte) []byte {
+ var (
+ hexLen = len(hex) // length of the hex input
+ firstByte = byte(0)
+ )
+ // Check if we have a terminator there
+ if hexLen > 0 && hex[hexLen-1] == 16 {
+ firstByte = 1 << 5
+ hexLen-- // last part was the terminator, ignore that
+ }
+ var (
+ binLen = hexLen/2 + 1
+ ni = 0 // index in hex
+ bi = 1 // index in bin (compact)
+ )
+ if hexLen&1 == 1 {
+ firstByte |= 1 << 4 // odd flag
+ firstByte |= hex[0] // first nibble is contained in the first byte
+ ni++
+ }
+ for ; ni < hexLen; bi, ni = bi+1, ni+2 {
+ hex[bi] = hex[ni]<<4 | hex[ni+1]
+ }
+ hex[0] = firstByte
+ return hex[:binLen]
+}
+
+func compactToHex(compact []byte) []byte {
+ if len(compact) == 0 {
+ return compact
+ }
+ base := keybytesToHex(compact)
+ // delete terminator flag
+ if base[0] < 2 {
+ base = base[:len(base)-1]
+ }
+ // apply odd flag
+ chop := 2 - base[0]&1
+ return base[chop:]
+}
+
+func keybytesToHex(str []byte) []byte {
+ l := len(str)*2 + 1
+ var nibbles = make([]byte, l)
+ for i, b := range str {
+ nibbles[i*2] = b / 16
+ nibbles[i*2+1] = b % 16
+ }
+ nibbles[l-1] = 16
+ return nibbles
+}
+
+// writeHexKey writes the hexkey into the given slice.
+// OBS! This method omits the termination flag.
+// OBS! The dst slice must be at least 2x as large as the key
+func writeHexKey(dst []byte, key []byte) []byte {
+ _ = dst[2*len(key)-1]
+ for i, b := range key {
+ dst[i*2] = b / 16
+ dst[i*2+1] = b % 16
+ }
+ return dst[:2*len(key)]
+}
+
+// hexToKeybytes turns hex nibbles into key bytes.
+// This can only be used for keys of even length.
+func hexToKeybytes(hex []byte) []byte {
+ if hasTerm(hex) {
+ hex = hex[:len(hex)-1]
+ }
+ if len(hex)&1 != 0 {
+ panic("can't convert hex key of odd length")
+ }
+ key := make([]byte, len(hex)/2)
+ decodeNibbles(hex, key)
+ return key
+}
+
+func decodeNibbles(nibbles []byte, bytes []byte) {
+ for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
+ bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
+ }
+}
+
+// prefixLen returns the length of the common prefix of a and b.
+func prefixLen(a, b []byte) int {
+ var i, length = 0, len(a)
+ if len(b) < length {
+ length = len(b)
+ }
+ for ; i < length; i++ {
+ if a[i] != b[i] {
+ break
+ }
+ }
+ return i
+}
+
+// hasTerm returns whether a hex key has the terminator flag.
+func hasTerm(s []byte) bool {
+ return len(s) > 0 && s[len(s)-1] == 16
+}
diff --git a/trie/hasher.go b/trie/hasher.go
new file mode 100644
index 000000000..78a32040a
--- /dev/null
+++ b/trie/hasher.go
@@ -0,0 +1,220 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+
+ "github.com/openrelayxyz/cardinal-evm/crypto"
+ "github.com/openrelayxyz/cardinal-evm/rlp"
+)
+
+// hasher is a type used for the trie Hash operation. A hasher has some
+// internal preallocated temp space
+type hasher struct {
+ sha crypto.KeccakState
+ tmp []byte
+ encbuf rlp.EncoderBuffer
+ parallel bool // Whether to use parallel threads when hashing
+}
+
+// hasherPool holds pureHashers
+var hasherPool = sync.Pool{
+ New: func() any {
+ return &hasher{
+ tmp: make([]byte, 0, 550), // cap is as large as a full fullNode.
+ sha: crypto.NewKeccakState(),
+ encbuf: rlp.NewEncoderBuffer(nil),
+ }
+ },
+}
+
+func newHasher(parallel bool) *hasher {
+ h := hasherPool.Get().(*hasher)
+ h.parallel = parallel
+ return h
+}
+
+func returnHasherToPool(h *hasher) {
+ hasherPool.Put(h)
+}
+
+// hash collapses a node down into a hash node.
+func (h *hasher) hash(n node, force bool) []byte {
+ // Return the cached hash if it's available
+ if hash, _ := n.cache(); hash != nil {
+ return hash
+ }
+ // Trie not processed yet, walk the children
+ switch n := n.(type) {
+ case *shortNode:
+ enc := h.encodeShortNode(n)
+ if len(enc) < 32 && !force {
+ // Nodes smaller than 32 bytes are embedded directly in their parent.
+ // In such cases, return the raw encoded blob instead of the node hash.
+ // It's essential to deep-copy the node blob, as the underlying buffer
+ // of enc will be reused later.
+ buf := make([]byte, len(enc))
+ copy(buf, enc)
+ return buf
+ }
+ hash := h.hashData(enc)
+ n.flags.hash = hash
+ return hash
+
+ case *fullNode:
+ enc := h.encodeFullNode(n)
+ if len(enc) < 32 && !force {
+ // Nodes smaller than 32 bytes are embedded directly in their parent.
+ // In such cases, return the raw encoded blob instead of the node hash.
+ // It's essential to deep-copy the node blob, as the underlying buffer
+ // of enc will be reused later.
+ buf := make([]byte, len(enc))
+ copy(buf, enc)
+ return buf
+ }
+ hash := h.hashData(enc)
+ n.flags.hash = hash
+ return hash
+
+ case hashNode:
+ // hash nodes don't have children, so they're left as were
+ return n
+
+ default:
+ panic(fmt.Errorf("unexpected node type, %T", n))
+ }
+}
+
+// encodeShortNode encodes the provided shortNode into the bytes. Notably, the
+// return slice must be deep-copied explicitly, otherwise the underlying slice
+// will be reused later.
+func (h *hasher) encodeShortNode(n *shortNode) []byte {
+ // Encode leaf node
+ if hasTerm(n.Key) {
+ var ln leafNodeEncoder
+ ln.Key = hexToCompact(n.Key)
+ ln.Val = n.Val.(valueNode)
+ ln.encode(h.encbuf)
+ return h.encodedBytes()
+ }
+ // Encode extension node
+ var en extNodeEncoder
+ en.Key = hexToCompact(n.Key)
+ en.Val = h.hash(n.Val, false)
+ en.encode(h.encbuf)
+ return h.encodedBytes()
+}
+
+// fnEncoderPool is the pool for storing shared fullNode encoder to mitigate
+// the significant memory allocation overhead.
+var fnEncoderPool = sync.Pool{
+ New: func() interface{} {
+ var enc fullnodeEncoder
+ return &enc
+ },
+}
+
+// encodeFullNode encodes the provided fullNode into the bytes. Notably, the
+// return slice must be deep-copied explicitly, otherwise the underlying slice
+// will be reused later.
+func (h *hasher) encodeFullNode(n *fullNode) []byte {
+ fn := fnEncoderPool.Get().(*fullnodeEncoder)
+ fn.reset()
+
+ if h.parallel {
+ var wg sync.WaitGroup
+ for i := 0; i < 16; i++ {
+ if n.Children[i] == nil {
+ continue
+ }
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+
+ h := newHasher(false)
+ fn.Children[i] = h.hash(n.Children[i], false)
+ returnHasherToPool(h)
+ }(i)
+ }
+ wg.Wait()
+ } else {
+ for i := 0; i < 16; i++ {
+ if child := n.Children[i]; child != nil {
+ fn.Children[i] = h.hash(child, false)
+ }
+ }
+ }
+ if n.Children[16] != nil {
+ fn.Children[16] = n.Children[16].(valueNode)
+ }
+ fn.encode(h.encbuf)
+ fnEncoderPool.Put(fn)
+
+ return h.encodedBytes()
+}
+
+// encodedBytes returns the result of the last encoding operation on h.encbuf.
+// This also resets the encoder buffer.
+//
+// All node encoding must be done like this:
+//
+// node.encode(h.encbuf)
+// enc := h.encodedBytes()
+//
+// This convention exists because node.encode can only be inlined/escape-analyzed when
+// called on a concrete receiver type.
+func (h *hasher) encodedBytes() []byte {
+ h.tmp = h.encbuf.AppendToBytes(h.tmp[:0])
+ h.encbuf.Reset(nil)
+ return h.tmp
+}
+
+// hashData hashes the provided data. It is safe to modify the returned slice after
+// the function returns.
+func (h *hasher) hashData(data []byte) []byte {
+ n := make([]byte, 32)
+ h.sha.Reset()
+ h.sha.Write(data)
+ h.sha.Read(n)
+ return n
+}
+
+// hashDataTo hashes the provided data to the given destination buffer. The caller
+// must ensure that the dst buffer is of appropriate size.
+func (h *hasher) hashDataTo(dst, data []byte) {
+ h.sha.Reset()
+ h.sha.Write(data)
+ h.sha.Read(dst)
+}
+
+// proofHash is used to construct trie proofs, returning the rlp-encoded node blobs.
+// Note, only resolved node (shortNode or fullNode) is expected for proofing.
+//
+// It is safe to modify the returned slice after the function returns.
+func (h *hasher) proofHash(original node) []byte {
+ switch n := original.(type) {
+ case *shortNode:
+ return bytes.Clone(h.encodeShortNode(n))
+ case *fullNode:
+ return bytes.Clone(h.encodeFullNode(n))
+ default:
+ panic(fmt.Errorf("unexpected node type, %T", original))
+ }
+}
diff --git a/trie/node.go b/trie/node.go
new file mode 100644
index 000000000..801f547ea
--- /dev/null
+++ b/trie/node.go
@@ -0,0 +1,266 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+import (
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ ctypes "github.com/openrelayxyz/cardinal-types"
+ "github.com/openrelayxyz/cardinal-evm/rlp"
+)
+
+var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"}
+
+type node interface {
+ cache() (hashNode, bool)
+ encode(w rlp.EncoderBuffer)
+ fstring(string) string
+}
+
+type (
+ fullNode struct {
+ Children [17]node // Actual trie node data to encode/decode (needs custom encoder)
+ flags nodeFlag
+ }
+ shortNode struct {
+ Key []byte
+ Val node
+ flags nodeFlag
+ }
+ hashNode []byte
+ valueNode []byte
+
+ // fullnodeEncoder is a type used exclusively for encoding fullNode.
+ // Briefly instantiating a fullnodeEncoder and initializing with
+ // existing slices is less memory intense than using the fullNode type.
+ fullnodeEncoder struct {
+ Children [17][]byte
+ }
+
+ // extNodeEncoder is a type used exclusively for encoding extension node.
+ // Briefly instantiating a extNodeEncoder and initializing with existing
+ // slices is less memory intense than using the shortNode type.
+ extNodeEncoder struct {
+ Key []byte
+ Val []byte
+ }
+
+ // leafNodeEncoder is a type used exclusively for encoding leaf node.
+ leafNodeEncoder struct {
+ Key []byte
+ Val []byte
+ }
+)
+
+// EncodeRLP encodes a full node into the consensus RLP format.
+func (n *fullNode) EncodeRLP(w io.Writer) error {
+ eb := rlp.NewEncoderBuffer(w)
+ n.encode(eb)
+ return eb.Flush()
+}
+
+// nodeFlag contains caching-related metadata about a node.
+type nodeFlag struct {
+ hash hashNode // cached hash of the node (may be nil)
+ dirty bool // whether the node has changes that must be written to the database
+}
+
+func (n nodeFlag) copy() nodeFlag {
+ return nodeFlag{
+ hash: common.CopyBytes(n.hash),
+ dirty: n.dirty,
+ }
+}
+
+func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
+func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
+func (n hashNode) cache() (hashNode, bool) { return nil, true }
+func (n valueNode) cache() (hashNode, bool) { return nil, true }
+
+// Pretty printing.
+func (n *fullNode) String() string { return n.fstring("") }
+func (n *shortNode) String() string { return n.fstring("") }
+func (n hashNode) String() string { return n.fstring("") }
+func (n valueNode) String() string { return n.fstring("") }
+
+func (n *fullNode) fstring(ind string) string {
+ resp := fmt.Sprintf("[\n%s ", ind)
+ for i, node := range &n.Children {
+ if node == nil {
+ resp += fmt.Sprintf("%s: ", indices[i])
+ } else {
+ resp += fmt.Sprintf("%s: %v", indices[i], node.fstring(ind+" "))
+ }
+ }
+ return resp + fmt.Sprintf("\n%s] ", ind)
+}
+
+func (n *shortNode) fstring(ind string) string {
+ return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" "))
+}
+func (n hashNode) fstring(ind string) string {
+ return fmt.Sprintf("<%x> ", []byte(n))
+}
+func (n valueNode) fstring(ind string) string {
+ return fmt.Sprintf("%x ", []byte(n))
+}
+
+// mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered.
+func mustDecodeNode(hash, buf []byte) node {
+ n, err := decodeNode(hash, buf)
+ if err != nil {
+ panic(fmt.Sprintf("node %x: %v", hash, err))
+ }
+ return n
+}
+
+// mustDecodeNodeUnsafe is a wrapper of decodeNodeUnsafe and panic if any error is
+// encountered.
+func mustDecodeNodeUnsafe(hash, buf []byte) node {
+ n, err := decodeNodeUnsafe(hash, buf)
+ if err != nil {
+ panic(fmt.Sprintf("node %x: %v", hash, err))
+ }
+ return n
+}
+
+// decodeNode parses the RLP encoding of a trie node. It will deep-copy the passed
+// byte slice for decoding, so it's safe to modify the byte slice afterwards. The-
+// decode performance of this function is not optimal, but it is suitable for most
+// scenarios with low performance requirements and hard to determine whether the
+// byte slice be modified or not.
+func decodeNode(hash, buf []byte) (node, error) {
+ return decodeNodeUnsafe(hash, common.CopyBytes(buf))
+}
+
+// decodeNodeUnsafe parses the RLP encoding of a trie node. The passed byte slice
+// will be directly referenced by node without bytes deep copy, so the input MUST
+// not be changed after.
+func decodeNodeUnsafe(hash, buf []byte) (node, error) {
+ if len(buf) == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ elems, _, err := rlp.SplitList(buf)
+ if err != nil {
+ return nil, fmt.Errorf("decode error: %v", err)
+ }
+ switch c, _ := rlp.CountValues(elems); c {
+ case 2:
+ n, err := decodeShort(hash, elems)
+ return n, wrapError(err, "short")
+ case 17:
+ n, err := decodeFull(hash, elems)
+ return n, wrapError(err, "full")
+ default:
+ return nil, fmt.Errorf("invalid number of list elements: %v", c)
+ }
+}
+
+func decodeShort(hash, elems []byte) (node, error) {
+ kbuf, rest, err := rlp.SplitString(elems)
+ if err != nil {
+ return nil, err
+ }
+ flag := nodeFlag{hash: hash}
+ key := compactToHex(kbuf)
+ if hasTerm(key) {
+ // value node
+ val, _, err := rlp.SplitString(rest)
+ if err != nil {
+ return nil, fmt.Errorf("invalid value node: %v", err)
+ }
+ return &shortNode{key, valueNode(val), flag}, nil
+ }
+ r, _, err := decodeRef(rest)
+ if err != nil {
+ return nil, wrapError(err, "val")
+ }
+ return &shortNode{key, r, flag}, nil
+}
+
+func decodeFull(hash, elems []byte) (*fullNode, error) {
+ n := &fullNode{flags: nodeFlag{hash: hash}}
+ for i := 0; i < 16; i++ {
+ cld, rest, err := decodeRef(elems)
+ if err != nil {
+ return n, wrapError(err, fmt.Sprintf("[%d]", i))
+ }
+ n.Children[i], elems = cld, rest
+ }
+ val, _, err := rlp.SplitString(elems)
+ if err != nil {
+ return n, err
+ }
+ if len(val) > 0 {
+ n.Children[16] = valueNode(val)
+ }
+ return n, nil
+}
+
+const hashLen = len(ctypes.Hash{})
+
+func decodeRef(buf []byte) (node, []byte, error) {
+ kind, val, rest, err := rlp.Split(buf)
+ if err != nil {
+ return nil, buf, err
+ }
+ switch {
+ case kind == rlp.List:
+ // 'embedded' node reference. The encoding must be smaller
+ // than a hash in order to be valid.
+ if size := len(buf) - len(rest); size > hashLen {
+ err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen)
+ return nil, buf, err
+ }
+ // The buffer content has already been copied or is safe to use;
+ // no additional copy is required.
+ n, err := decodeNodeUnsafe(nil, buf)
+ return n, rest, err
+ case kind == rlp.String && len(val) == 0:
+ // empty node
+ return nil, rest, nil
+ case kind == rlp.String && len(val) == 32:
+ return hashNode(val), rest, nil
+ default:
+ return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val))
+ }
+}
+
+// wraps a decoding error with information about the path to the
+// invalid child node (for debugging encoding issues).
+type decodeError struct {
+ what error
+ stack []string
+}
+
+func wrapError(err error, ctx string) error {
+ if err == nil {
+ return nil
+ }
+ if decErr, ok := err.(*decodeError); ok {
+ decErr.stack = append(decErr.stack, ctx)
+ return decErr
+ }
+ return &decodeError{err, []string{ctx}}
+}
+
+func (err *decodeError) Error() string {
+ return fmt.Sprintf("%v (decode path: %s)", err.what, strings.Join(err.stack, "<-"))
+}
diff --git a/trie/node_enc.go b/trie/node_enc.go
new file mode 100644
index 000000000..d1498d518
--- /dev/null
+++ b/trie/node_enc.go
@@ -0,0 +1,106 @@
+// Copyright 2022 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+import (
+ "github.com/openrelayxyz/cardinal-evm/rlp"
+)
+
+func nodeToBytes(n node) []byte {
+ w := rlp.NewEncoderBuffer(nil)
+ n.encode(w)
+ result := w.ToBytes()
+ w.Flush()
+ return result
+}
+
+func (n *fullNode) encode(w rlp.EncoderBuffer) {
+ offset := w.List()
+ for _, c := range n.Children {
+ if c != nil {
+ c.encode(w)
+ } else {
+ w.Write(rlp.EmptyString)
+ }
+ }
+ w.ListEnd(offset)
+}
+
+func (n *fullnodeEncoder) encode(w rlp.EncoderBuffer) {
+ offset := w.List()
+ for i, c := range n.Children {
+ if len(c) == 0 {
+ w.Write(rlp.EmptyString)
+ } else {
+ // valueNode or hashNode
+ if i == 16 || len(c) >= 32 {
+ w.WriteBytes(c)
+ } else {
+ w.Write(c) // rawNode
+ }
+ }
+ }
+ w.ListEnd(offset)
+}
+
+func (n *fullnodeEncoder) reset() {
+ for i, c := range n.Children {
+ if len(c) != 0 {
+ n.Children[i] = n.Children[i][:0]
+ }
+ }
+}
+
+func (n *shortNode) encode(w rlp.EncoderBuffer) {
+ offset := w.List()
+ w.WriteBytes(n.Key)
+ if n.Val != nil {
+ n.Val.encode(w)
+ } else {
+ w.Write(rlp.EmptyString)
+ }
+ w.ListEnd(offset)
+}
+
+func (n *extNodeEncoder) encode(w rlp.EncoderBuffer) {
+ offset := w.List()
+ w.WriteBytes(n.Key)
+
+ if n.Val == nil {
+ w.Write(rlp.EmptyString) // theoretically impossible to happen
+ } else if len(n.Val) < 32 {
+ w.Write(n.Val) // rawNode
+ } else {
+ w.WriteBytes(n.Val) // hashNode
+ }
+ w.ListEnd(offset)
+}
+
+func (n *leafNodeEncoder) encode(w rlp.EncoderBuffer) {
+ offset := w.List()
+ w.WriteBytes(n.Key) // Compact format key
+ w.WriteBytes(n.Val) // Value node, must be non-nil
+ w.ListEnd(offset)
+}
+
+func (n hashNode) encode(w rlp.EncoderBuffer) {
+ w.WriteBytes(n)
+}
+
+func (n valueNode) encode(w rlp.EncoderBuffer) {
+ w.WriteBytes(n)
+}
diff --git a/trie/stacktrie.go b/trie/stacktrie.go
new file mode 100644
index 000000000..2044375b6
--- /dev/null
+++ b/trie/stacktrie.go
@@ -0,0 +1,437 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package trie
+
+import (
+ "bytes"
+ "errors"
+ "sync"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/types"
+ ctypes "github.com/openrelayxyz/cardinal-types"
+)
+
+var (
+ stPool = sync.Pool{New: func() any { return new(stNode) }}
+ bPool = newBytesPool(32, 100)
+ _ = types.TrieHasher((*StackTrie)(nil))
+)
+
+// OnTrieNode is a callback method invoked when a trie node is committed
+// by the stack trie. The node is only committed if it's considered complete.
+//
+// The caller should not modify the contents of the returned path and blob
+// slice, and their contents may be changed after the call. It is up to the
+// `onTrieNode` receiver function to deep-copy the data if it wants to retain
+// it after the call ends.
+type OnTrieNode func(path []byte, hash ctypes.Hash, blob []byte)
+
+// StackTrie is a trie implementation that expects keys to be inserted
+// in order. Once it determines that a subtree will no longer be inserted
+// into, it will hash it and free up the memory it uses.
+type StackTrie struct {
+ root *stNode
+ h *hasher
+ last []byte
+ onTrieNode OnTrieNode
+ kBuf []byte // buf space used for hex-key during insertions
+ pBuf []byte // buf space used for path during insertions
+ vPool *unsafeBytesPool
+}
+
+// NewStackTrie allocates and initializes an empty trie. The committed nodes
+// will be discarded immediately if no callback is configured.
+func NewStackTrie(onTrieNode OnTrieNode) *StackTrie {
+ return &StackTrie{
+ root: stPool.Get().(*stNode),
+ h: newHasher(false),
+ onTrieNode: onTrieNode,
+ kBuf: make([]byte, 64),
+ pBuf: make([]byte, 64),
+ vPool: newUnsafeBytesPool(300, 20),
+ }
+}
+
+func (t *StackTrie) grow(key []byte) {
+ if cap(t.kBuf) < 2*len(key) {
+ t.kBuf = make([]byte, 2*len(key))
+ }
+ if cap(t.pBuf) < 2*len(key) {
+ t.pBuf = make([]byte, 2*len(key))
+ }
+}
+
+// Update inserts a (key, value) pair into the stack trie.
+//
+// Note the supplied key value pair is copied and managed internally,
+// they are safe to be modified after this method returns.
+func (t *StackTrie) Update(key, value []byte) error {
+ if len(value) == 0 {
+ return errors.New("trying to insert empty (deletion)")
+ }
+ t.grow(key)
+ k := writeHexKey(t.kBuf, key)
+ if bytes.Compare(t.last, k) >= 0 {
+ return errors.New("non-ascending key order")
+ }
+ if t.last == nil {
+ t.last = append([]byte{}, k...) // allocate key slice
+ } else {
+ t.last = append(t.last[:0], k...) // reuse key slice
+ }
+ vBuf := t.vPool.get()
+ if cap(vBuf) < len(value) {
+ vBuf = common.CopyBytes(value)
+ } else {
+ vBuf = vBuf[:len(value)]
+ copy(vBuf, value)
+ }
+ t.insert(t.root, k, vBuf, t.pBuf[:0])
+ return nil
+}
+
+// Reset resets the stack trie object to empty state.
+func (t *StackTrie) Reset() {
+ t.root = stPool.Get().(*stNode)
+ t.last = nil
+}
+
+// TrieKey returns the internal key representation for the given user key.
+func (t *StackTrie) TrieKey(key []byte) []byte {
+ k := keybytesToHex(key)
+ k = k[:len(k)-1] // chop the termination flag
+ return k
+}
+
+// stNode represents a node within a StackTrie
+type stNode struct {
+ typ uint8 // node type (as in branch, ext, leaf)
+ key []byte // exclusive owned key chunk covered by this (leaf|ext) node
+ val []byte // exclusive owned value contained by this node (leaf: value; hash: hash)
+ children [16]*stNode // list of children (for branch and ext)
+}
+
+// newLeaf constructs a leaf node with provided node key and value.
+//
+// The key is deep-copied within the function, so it can be safely modified
+// afterwards. The value is retained directly without copying, as it is
+// exclusively owned by the stackTrie.
+func newLeaf(key, val []byte) *stNode {
+ st := stPool.Get().(*stNode)
+ st.typ = leafNode
+ st.key = append(st.key, key...)
+ st.val = val
+ return st
+}
+
+// newExt constructs an extension node with provided node key and child. The
+// key will be deep-copied in the function and safe to modify afterwards.
+func newExt(key []byte, child *stNode) *stNode {
+ st := stPool.Get().(*stNode)
+ st.typ = extNode
+ st.key = append(st.key, key...)
+ st.children[0] = child
+ return st
+}
+
+// List all values that stNode#nodeType can hold
+const (
+ emptyNode = iota
+ branchNode
+ extNode
+ leafNode
+ hashedNode
+)
+
+func (n *stNode) reset() *stNode {
+ if n.typ == hashedNode {
+ // On hashnodes, we 'own' the val: it is guaranteed to be not held
+ // by external caller. Hence, when we arrive here, we can put it
+ // back into the pool
+ bPool.put(n.val)
+ }
+ n.key = n.key[:0]
+ n.val = nil
+ for i := range n.children {
+ n.children[i] = nil
+ }
+ n.typ = emptyNode
+ return n
+}
+
+// Helper function that, given a full key, determines the index
+// at which the chunk pointed by st.keyOffset is different from
+// the same chunk in the full key.
+func (n *stNode) getDiffIndex(key []byte) int {
+ for idx, nibble := range n.key {
+ if nibble != key[idx] {
+ return idx
+ }
+ }
+ return len(n.key)
+}
+
+// Helper function to that inserts a (key, value) pair into the trie.
+func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
+ switch st.typ {
+ case branchNode: /* Branch */
+ idx := int(key[0])
+
+ // Unresolve elder siblings
+ for i := idx - 1; i >= 0; i-- {
+ if st.children[i] != nil {
+ if st.children[i].typ != hashedNode {
+ t.hash(st.children[i], append(path, byte(i)))
+ }
+ break
+ }
+ }
+
+ // Add new child
+ if st.children[idx] == nil {
+ st.children[idx] = newLeaf(key[1:], value)
+ } else {
+ t.insert(st.children[idx], key[1:], value, append(path, key[0]))
+ }
+
+ case extNode: /* Ext */
+ // Compare both key chunks and see where they differ
+ diffidx := st.getDiffIndex(key)
+
+ // Check if chunks are identical. If so, recurse into
+ // the child node. Otherwise, the key has to be split
+ // into 1) an optional common prefix, 2) the fullnode
+ // representing the two differing path, and 3) a leaf
+ // for each of the differentiated subtrees.
+ if diffidx == len(st.key) {
+ // Ext key and key segment are identical, recurse into
+ // the child node.
+ t.insert(st.children[0], key[diffidx:], value, append(path, key[:diffidx]...))
+ return
+ }
+ // Save the original part. Depending if the break is
+ // at the extension's last byte or not, create an
+ // intermediate extension or use the extension's child
+ // node directly.
+ var n *stNode
+ if diffidx < len(st.key)-1 {
+ // Break on the non-last byte, insert an intermediate
+ // extension. The path prefix of the newly-inserted
+ // extension should also contain the different byte.
+ n = newExt(st.key[diffidx+1:], st.children[0])
+ t.hash(n, append(path, st.key[:diffidx+1]...))
+ } else {
+ // Break on the last byte, no need to insert
+ // an extension node: reuse the current node.
+ // The path prefix of the original part should
+ // still be same.
+ n = st.children[0]
+ t.hash(n, append(path, st.key...))
+ }
+ var p *stNode
+ if diffidx == 0 {
+ // the break is on the first byte, so the current node
+ // is converted into a branch node.
+ st.children[0] = nil
+ st.typ = branchNode
+ p = st
+ } else {
+ // the common prefix is at least one byte long, insert
+ // a new intermediate branch node.
+ st.children[0] = stPool.Get().(*stNode)
+ st.children[0].typ = branchNode
+ p = st.children[0]
+ }
+ // Create a leaf for the inserted part
+ o := newLeaf(key[diffidx+1:], value)
+
+ // Insert both child leaves where they belong:
+ origIdx := st.key[diffidx]
+ newIdx := key[diffidx]
+ p.children[origIdx] = n
+ p.children[newIdx] = o
+ st.key = st.key[:diffidx]
+
+ case leafNode: /* Leaf */
+ // Compare both key chunks and see where they differ
+ diffidx := st.getDiffIndex(key)
+
+ // Overwriting a key isn't supported, which means that
+ // the current leaf is expected to be split into 1) an
+ // optional extension for the common prefix of these 2
+ // keys, 2) a fullnode selecting the path on which the
+ // keys differ, and 3) one leaf for the differentiated
+ // component of each key.
+ if diffidx >= len(st.key) {
+ panic("Trying to insert into existing key")
+ }
+
+ // Check if the split occurs at the first nibble of the
+ // chunk. In that case, no prefix extnode is necessary.
+ // Otherwise, create that
+ var p *stNode
+ if diffidx == 0 {
+ // Convert current leaf into a branch
+ st.typ = branchNode
+ st.children[0] = nil
+ p = st
+ } else {
+ // Convert current node into an ext,
+ // and insert a child branch node.
+ st.typ = extNode
+ st.children[0] = stPool.Get().(*stNode)
+ st.children[0].typ = branchNode
+ p = st.children[0]
+ }
+
+ // Create the two child leaves: one containing the original
+ // value and another containing the new value. The child leaf
+ // is hashed directly in order to free up some memory.
+ origIdx := st.key[diffidx]
+ p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val)
+ t.hash(p.children[origIdx], append(path, st.key[:diffidx+1]...))
+
+ newIdx := key[diffidx]
+ p.children[newIdx] = newLeaf(key[diffidx+1:], value)
+
+ // Finally, cut off the key part that has been passed
+ // over to the children.
+ st.key = st.key[:diffidx]
+ st.val = nil
+
+ case emptyNode: /* Empty */
+ *st = *newLeaf(key, value)
+
+ case hashedNode:
+ panic("trying to insert into hash")
+
+ default:
+ panic("invalid type")
+ }
+}
+
+// hash converts st into a 'hashedNode', if possible. Possible outcomes:
+//
+// 1. The rlp-encoded value was >= 32 bytes:
+// - Then the 32-byte `hash` will be accessible in `st.val`.
+// - And the 'st.type' will be 'hashedNode'
+//
+// 2. The rlp-encoded value was < 32 bytes
+// - Then the <32 byte rlp-encoded value will be accessible in 'st.val'.
+// - And the 'st.type' will be 'hashedNode' AGAIN
+//
+// This method also sets 'st.type' to hashedNode, and clears 'st.key'.
+func (t *StackTrie) hash(st *stNode, path []byte) {
+ var blob []byte // RLP-encoded node blob
+ switch st.typ {
+ case hashedNode:
+ return
+
+ case emptyNode:
+ st.val = types.EmptyRootHash.Bytes()
+ st.key = st.key[:0]
+ st.typ = hashedNode
+ return
+
+ case branchNode:
+ var nodes fullnodeEncoder
+ for i, child := range st.children {
+ if child == nil {
+ continue
+ }
+ t.hash(child, append(path, byte(i)))
+ nodes.Children[i] = child.val
+ }
+ nodes.encode(t.h.encbuf)
+ blob = t.h.encodedBytes()
+
+ for i, child := range st.children {
+ if child == nil {
+ continue
+ }
+ st.children[i] = nil
+ stPool.Put(child.reset()) // Release child back to pool.
+ }
+
+ case extNode:
+ // recursively hash and commit child as the first step
+ t.hash(st.children[0], append(path, st.key...))
+
+ // encode the extension node
+ n := extNodeEncoder{
+ Key: hexToCompactInPlace(st.key),
+ Val: st.children[0].val,
+ }
+ n.encode(t.h.encbuf)
+ blob = t.h.encodedBytes()
+
+ stPool.Put(st.children[0].reset()) // Release child back to pool.
+ st.children[0] = nil
+
+ case leafNode:
+ st.key = append(st.key, byte(16))
+ n := leafNodeEncoder{
+ Key: hexToCompactInPlace(st.key),
+ Val: st.val,
+ }
+ n.encode(t.h.encbuf)
+ blob = t.h.encodedBytes()
+
+ default:
+ panic("invalid node type")
+ }
+ // Convert the node type to hashNode and reset the key slice.
+ st.typ = hashedNode
+ st.key = st.key[:0]
+
+ // Release reference to value slice which is exclusively owned
+ // by stackTrie itself.
+ if cap(st.val) > 0 && t.vPool != nil {
+ t.vPool.put(st.val)
+ }
+ st.val = nil
+
+ // Skip committing the non-root node if the size is smaller than 32 bytes
+ // as tiny nodes are always embedded in their parent except root node.
+ if len(blob) < 32 && len(path) > 0 {
+ st.val = bPool.getWithSize(len(blob))
+ copy(st.val, blob)
+ return
+ }
+ // Write the hash to the 'val'. We allocate a new val here to not mutate
+ // input values.
+ st.val = bPool.getWithSize(32)
+ t.h.hashDataTo(st.val, blob)
+
+ // Invoke the callback it's provided. Notably, the path and blob slices are
+ // volatile, please deep-copy the slices in callback if the contents need
+ // to be retained.
+ if t.onTrieNode != nil {
+ t.onTrieNode(path, ctypes.BytesToHash(st.val), blob)
+ }
+}
+
+// Hash will firstly hash the entire trie if it's still not hashed and then commit
+// all leftover nodes to the associated database. Actually most of the trie nodes
+// have been committed already. The main purpose here is to commit the nodes on
+// right boundary.
+func (t *StackTrie) Hash() ctypes.Hash {
+ n := t.root
+ t.hash(n, nil)
+ return ctypes.BytesToHash(n.val)
+}
diff --git a/types/block.go b/types/block.go
index 1b8999e46..f116e5a56 100644
--- a/types/block.go
+++ b/types/block.go
@@ -1,38 +1,244 @@
package types
import (
+ "math/big"
+ "crypto/sha256"
+ "sync/atomic"
+ "time"
+ "slices"
+ "encoding/binary"
+
+ "github.com/ethereum/go-verkle"
+
"github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
"github.com/openrelayxyz/cardinal-types"
- "math/big"
)
+// A BlockNonce is a 64-bit hash which proves (combined with the
+// mix-hash) that a sufficient amount of computation has been carried
+// out on a block.
+type BlockNonce [8]byte
+
+// EncodeNonce converts the given integer to a block nonce.
+func EncodeNonce(i uint64) BlockNonce {
+ var n BlockNonce
+ binary.BigEndian.PutUint64(n[:], i)
+ return n
+}
+
+// Uint64 returns the integer value of a block nonce.
+func (n BlockNonce) Uint64() uint64 {
+ return binary.BigEndian.Uint64(n[:])
+}
+
+// MarshalText encodes n as a hex string with 0x prefix.
+func (n BlockNonce) MarshalText() ([]byte, error) {
+ return hexutil.Bytes(n[:]).MarshalText()
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (n *BlockNonce) UnmarshalText(input []byte) error {
+ return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
+}
+
+// ExecutionWitness represents the witness + proof used in a verkle context,
+// to provide the ability to execute a block statelessly.
+type ExecutionWitness struct {
+ StateDiff verkle.StateDiff `json:"stateDiff"`
+ VerkleProof *verkle.VerkleProof `json:"verkleProof"`
+}
+
+// Header represents a block header in the Ethereum blockchain.
type Header struct {
- ParentHash types.Hash
- UncleHash types.Hash
- Coinbase common.Address
- Root types.Hash
- TxHash types.Hash
- ReceiptHash types.Hash
- Bloom [256]byte
- Difficulty *big.Int
- Number *big.Int
- GasLimit uint64
- GasUsed uint64
- Time uint64
- Extra []byte
- MixDigest types.Hash
- Nonce [8]byte
- BaseFee *big.Int `rlp:"optional"`
- WithdrawalsHash *types.Hash `rlp:"optional"`
+ ParentHash types.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash types.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase common.Address `json:"miner"`
+ Root types.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash types.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash types.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *big.Int `json:"difficulty" gencodec:"required"`
+ Number *big.Int `json:"number" gencodec:"required"`
+ GasLimit uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed uint64 `json:"gasUsed" gencodec:"required"`
+ Time uint64 `json:"timestamp" gencodec:"required"`
+ Extra []byte `json:"extraData" gencodec:"required"`
+ MixDigest types.Hash `json:"mixHash"`
+ Nonce BlockNonce `json:"nonce"`
+
+ // BaseFee was added by EIP-1559 and is ignored in legacy headers.
+ BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
+
+ // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers.
+ WithdrawalsHash *types.Hash `json:"withdrawalsRoot" rlp:"optional"`
+
// BlobGasUsed was added by EIP-4844 and is ignored in legacy headers.
- BlobGasUsed *uint64 `rlp:"optional"`
+ BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
// ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers.
- ExcessBlobGas *uint64 `rlp:"optional"`
+ ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
- // BeaconRoot was added by EIP-4788 and is ignored in legacy headers.
- BeaconRoot *types.Hash `rlp:"optional"`
+ // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
+ ParentBeaconRoot *types.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
- RequestsHash *types.Hash `json:"requestsHash" rlp:"optional"`
+ RequestsHash *types.Hash `json:"requestsHash" rlp:"optional"`
+}
+
+type Block struct {
+ header *Header
+ uncles []*Header
+ transactions Transactions
+ withdrawals Withdrawals
+
+ // caches
+ hash atomic.Pointer[types.Hash]
+ size atomic.Uint64
+
+ // These fields are used by package eth to track
+ // inter-peer block relay.
+ ReceivedAt time.Time
+ ReceivedFrom interface{}
+}
+
+// Header returns the block header (as a copy).
+func (b *Block) Header() *Header {
+ return CopyHeader(b.header)
+}
+
+// CopyHeader creates a deep copy of a block header.
+func CopyHeader(h *Header) *Header {
+ cpy := *h
+ if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
+ cpy.Difficulty.Set(h.Difficulty)
+ }
+ if cpy.Number = new(big.Int); h.Number != nil {
+ cpy.Number.Set(h.Number)
+ }
+ if h.BaseFee != nil {
+ cpy.BaseFee = new(big.Int).Set(h.BaseFee)
+ }
+ if len(h.Extra) > 0 {
+ cpy.Extra = make([]byte, len(h.Extra))
+ copy(cpy.Extra, h.Extra)
+ }
+ if h.WithdrawalsHash != nil {
+ cpy.WithdrawalsHash = new(types.Hash)
+ *cpy.WithdrawalsHash = *h.WithdrawalsHash
+ }
+ if h.ExcessBlobGas != nil {
+ cpy.ExcessBlobGas = new(uint64)
+ *cpy.ExcessBlobGas = *h.ExcessBlobGas
+ }
+ if h.BlobGasUsed != nil {
+ cpy.BlobGasUsed = new(uint64)
+ *cpy.BlobGasUsed = *h.BlobGasUsed
+ }
+ if h.RequestsHash != nil {
+ cpy.RequestsHash = new(types.Hash)
+ *cpy.RequestsHash = *h.RequestsHash
+ }
+ return &cpy
+}
+
+// Hash returns the block hash of the header, which is simply the keccak256 hash of its
+// RLP encoding.
+func (h *Header) Hash() types.Hash {
+ return rlpHash(h)
+}
+
+// Body is a simple (mutable, non-safe) data container for storing and moving
+// a block's data contents (transactions and uncles) together.
+type Body struct {
+ Transactions []*Transaction
+ Uncles []*Header
+ Withdrawals []*Withdrawal `rlp:"optional"`
+}
+
+// NewBlockWithHeader creates a block with the given header data. The
+// header data is copied, changes to header and to the field values
+// will not affect the block.
+func NewBlockWithHeader(header *Header) *Block {
+ return &Block{header: CopyHeader(header)}
}
+
+// NewBlock creates a new block. The input data is copied, changes to header and to the
+// field values will not affect the block.
+//
+// The body elements and the receipts are used to recompute and overwrite the
+// relevant portions of the header.
+//
+// The receipt's bloom must already calculated for the block's bloom to be
+// correctly calculated.
+func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block {
+ if body == nil {
+ body = &Body{}
+ }
+ var (
+ b = NewBlockWithHeader(header)
+ txs = body.Transactions
+ uncles = body.Uncles
+ withdrawals = body.Withdrawals
+ )
+
+ if len(txs) == 0 {
+ b.header.TxHash = EmptyTxsHash
+ } else {
+ b.header.TxHash = DeriveSha(Transactions(txs), hasher)
+ b.transactions = make(Transactions, len(txs))
+ copy(b.transactions, txs)
+ }
+
+ if len(receipts) == 0 {
+ b.header.ReceiptHash = EmptyReceiptsHash
+ } else {
+ b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher)
+ b.header.Bloom = MergeBloom(receipts)
+ }
+
+ if len(uncles) == 0 {
+ b.header.UncleHash = EmptyUncleHash
+ } else {
+ b.header.UncleHash = CalcUncleHash(uncles)
+ b.uncles = make([]*Header, len(uncles))
+ for i := range uncles {
+ b.uncles[i] = CopyHeader(uncles[i])
+ }
+ }
+
+ if withdrawals == nil {
+ b.header.WithdrawalsHash = nil
+ } else if len(withdrawals) == 0 {
+ b.header.WithdrawalsHash = &EmptyWithdrawalsHash
+ b.withdrawals = Withdrawals{}
+ } else {
+ hash := DeriveSha(Withdrawals(withdrawals), hasher)
+ b.header.WithdrawalsHash = &hash
+ b.withdrawals = slices.Clone(withdrawals)
+ }
+
+ return b
+}
+
+func CalcUncleHash(uncles []*Header) types.Hash {
+ if len(uncles) == 0 {
+ return EmptyUncleHash
+ }
+ return rlpHash(uncles)
+}
+
+// CalcRequestsHash creates the block requestsHash value for a list of requests.
+func CalcRequestsHash(requests [][]byte) types.Hash {
+ h1, h2 := sha256.New(), sha256.New()
+ var buf types.Hash
+ for _, item := range requests {
+ if len(item) > 1 { // skip items with only requestType and no data.
+ h1.Reset()
+ h1.Write(item)
+ h2.Write(h1.Sum(buf[:0]))
+ }
+ }
+ h2.Sum(buf[:0])
+ return buf
+}
\ No newline at end of file
diff --git a/types/bloom9.go b/types/bloom9.go
new file mode 100644
index 000000000..1811deb43
--- /dev/null
+++ b/types/bloom9.go
@@ -0,0 +1,82 @@
+package types
+
+import (
+ "encoding/binary"
+ "github.com/openrelayxyz/cardinal-evm/crypto"
+)
+
+type bytesBacked interface {
+ Bytes() []byte
+}
+
+const (
+ // BloomByteLength represents the number of bytes used in a header log bloom.
+ BloomByteLength = 256
+
+)
+
+// Bloom represents a 2048 bit bloom filter.
+type Bloom [BloomByteLength]byte
+
+// add is internal version of Add, which takes a scratch buffer for reuse (needs to be at least 6 bytes)
+func (b *Bloom) add(d []byte, buf []byte) {
+ i1, v1, i2, v2, i3, v3 := bloomValues(d, buf)
+ b[i1] |= v1
+ b[i2] |= v2
+ b[i3] |= v3
+}
+
+// Bytes returns the backing byte slice of the bloom
+func (b Bloom) Bytes() []byte {
+ return b[:]
+}
+
+// CreateBloom creates a bloom filter out of the give Receipts (+Logs)
+func CreateBloom(receipts Receipts) Bloom {
+ buf := make([]byte, 6)
+ var bin Bloom
+ for _, receipt := range receipts {
+ for _, log := range receipt.Logs {
+ bin.add(log.Address.Bytes(), buf)
+ for _, b := range log.Topics {
+ bin.add(b[:], buf)
+ }
+ }
+ }
+ return bin
+}
+
+// bloomValues returns the bytes (index-value pairs) to set for the given data
+func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) {
+ sha := hasherPool.Get().(crypto.KeccakState)
+ sha.Reset()
+ sha.Write(data)
+ sha.Read(hashbuf)
+ hasherPool.Put(sha)
+ // The actual bits to flip
+ v1 := byte(1 << (hashbuf[1] & 0x7))
+ v2 := byte(1 << (hashbuf[3] & 0x7))
+ v3 := byte(1 << (hashbuf[5] & 0x7))
+ // The indices for the bytes to OR in
+ i1 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf)&0x7ff)>>3) - 1
+ i2 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[2:])&0x7ff)>>3) - 1
+ i3 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[4:])&0x7ff)>>3) - 1
+
+ return i1, v1, i2, v2, i3, v3
+}
+
+// MergeBloom merges the precomputed bloom filters in the Receipts without
+// recalculating them. It assumes that each receipt’s Bloom field is already
+// correctly populated.
+func MergeBloom(receipts Receipts) Bloom {
+ var bin Bloom
+ for _, receipt := range receipts {
+ if len(receipt.Logs) != 0 {
+ bl := receipt.Bloom.Bytes()
+ for i := range bin {
+ bin[i] |= bl[i]
+ }
+ }
+ }
+ return bin
+}
\ No newline at end of file
diff --git a/types/gen_authorization.go b/types/gen_authorization.go
index 1c361e215..8e3575f4d 100644
--- a/types/gen_authorization.go
+++ b/types/gen_authorization.go
@@ -1,75 +1,92 @@
-// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
-
package types
import (
"encoding/json"
"errors"
- "github.com/holiman/uint256"
"github.com/openrelayxyz/cardinal-evm/common"
"github.com/openrelayxyz/cardinal-types/hexutil"
+ "github.com/holiman/uint256"
)
+// field type overrides for gencodec
+type authorizationMarshaling struct {
+ ChainID U256
+ Nonce hexutil.Uint64
+ V hexutil.Uint64
+ R U256
+ S U256
+}
+
+// SetCodeAuthorization is an authorization from an account to deploy code at its address.
+type SetCodeAuthorization struct {
+ ChainID uint256.Int `json:"chainId" gencodec:"required"`
+ Address common.Address `json:"address" gencodec:"required"`
+ Nonce uint64 `json:"nonce" gencodec:"required"`
+ V uint8 `json:"yParity" gencodec:"required"`
+ R uint256.Int `json:"r" gencodec:"required"`
+ S uint256.Int `json:"s" gencodec:"required"`
+}
+
var _ = (*authorizationMarshaling)(nil)
// MarshalJSON marshals as JSON.
-func (a Authorization) MarshalJSON() ([]byte, error) {
- type Authorization struct {
- ChainID U256 `json:"chainId" gencodec:"required"`
+func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
+ type SetCodeAuthorization struct {
+ ChainID U256 `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"`
Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
V hexutil.Uint64 `json:"yParity" gencodec:"required"`
- R U256 `json:"r" gencodec:"required"`
- S U256 `json:"s" gencodec:"required"`
+ R U256 `json:"r" gencodec:"required"`
+ S U256 `json:"s" gencodec:"required"`
}
- var enc Authorization
- enc.ChainID = U256(a.ChainID)
- enc.Address = a.Address
- enc.Nonce = hexutil.Uint64(a.Nonce)
- enc.V = hexutil.Uint64(a.V)
- enc.R = U256(a.R)
- enc.S = U256(a.S)
+ var enc SetCodeAuthorization
+ enc.ChainID = U256(s.ChainID)
+ enc.Address = s.Address
+ enc.Nonce = hexutil.Uint64(s.Nonce)
+ enc.V = hexutil.Uint64(s.V)
+ enc.R = U256(s.R)
+ enc.S = U256(s.S)
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
-func (a *Authorization) UnmarshalJSON(input []byte) error {
- type Authorization struct {
- ChainID *U256 `json:"chainId" gencodec:"required"`
+func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error {
+ type SetCodeAuthorization struct {
+ ChainID *U256 `json:"chainId" gencodec:"required"`
Address *common.Address `json:"address" gencodec:"required"`
Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
V *hexutil.Uint64 `json:"yParity" gencodec:"required"`
- R *U256 `json:"r" gencodec:"required"`
- S *U256 `json:"s" gencodec:"required"`
+ R *U256 `json:"r" gencodec:"required"`
+ S *U256 `json:"s" gencodec:"required"`
}
- var dec Authorization
+ var dec SetCodeAuthorization
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.ChainID == nil {
- return errors.New("missing required field 'chainId' for Authorization")
+ return errors.New("missing required field 'chainId' for SetCodeAuthorization")
}
- a.ChainID = uint256.Int(*dec.ChainID)
+ s.ChainID = uint256.Int(*dec.ChainID)
if dec.Address == nil {
- return errors.New("missing required field 'address' for Authorization")
+ return errors.New("missing required field 'address' for SetCodeAuthorization")
}
- a.Address = *dec.Address
+ s.Address = *dec.Address
if dec.Nonce == nil {
- return errors.New("missing required field 'nonce' for Authorization")
+ return errors.New("missing required field 'nonce' for SetCodeAuthorization")
}
- a.Nonce = uint64(*dec.Nonce)
+ s.Nonce = uint64(*dec.Nonce)
if dec.V == nil {
- return errors.New("missing required field 'yParity' for Authorization")
+ return errors.New("missing required field 'yParity' for SetCodeAuthorization")
}
- a.V = uint8(*dec.V)
+ s.V = uint8(*dec.V)
if dec.R == nil {
- return errors.New("missing required field 'r' for Authorization")
+ return errors.New("missing required field 'r' for SetCodeAuthorization")
}
- a.R = uint256.Int(*dec.R)
+ s.R = uint256.Int(*dec.R)
if dec.S == nil {
- return errors.New("missing required field 's' for Authorization")
+ return errors.New("missing required field 's' for SetCodeAuthorization")
}
- a.S = uint256.Int(*dec.S)
+ s.S = uint256.Int(*dec.S)
return nil
}
diff --git a/types/gen_log_json.go b/types/gen_log_json.go
new file mode 100644
index 000000000..63512da1a
--- /dev/null
+++ b/types/gen_log_json.go
@@ -0,0 +1,97 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
+ "github.com/openrelayxyz/cardinal-types"
+)
+
+var _ = (*logMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (l Log) MarshalJSON() ([]byte, error) {
+ type Log struct {
+ Address common.Address `json:"address" gencodec:"required"`
+ Topics []types.Hash `json:"topics" gencodec:"required"`
+ Data hexutil.Bytes `json:"data" gencodec:"required"`
+ BlockNumber hexutil.Uint64 `json:"blockNumber" rlp:"-"`
+ TxHash types.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
+ TxIndex hexutil.Uint `json:"transactionIndex" rlp:"-"`
+ BlockHash types.Hash `json:"blockHash" rlp:"-"`
+ BlockTimestamp hexutil.Uint64 `json:"blockTimestamp" rlp:"-"`
+ Index hexutil.Uint `json:"logIndex" rlp:"-"`
+ Removed bool `json:"removed" rlp:"-"`
+ }
+ var enc Log
+ enc.Address = l.Address
+ enc.Topics = l.Topics
+ enc.Data = l.Data
+ enc.BlockNumber = hexutil.Uint64(l.BlockNumber)
+ enc.TxHash = l.TxHash
+ enc.TxIndex = hexutil.Uint(l.TxIndex)
+ enc.BlockHash = l.BlockHash
+ enc.BlockTimestamp = hexutil.Uint64(l.BlockTimestamp)
+ enc.Index = hexutil.Uint(l.Index)
+ enc.Removed = l.Removed
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (l *Log) UnmarshalJSON(input []byte) error {
+ type Log struct {
+ Address *common.Address `json:"address" gencodec:"required"`
+ Topics []types.Hash `json:"topics" gencodec:"required"`
+ Data *hexutil.Bytes `json:"data" gencodec:"required"`
+ BlockNumber *hexutil.Uint64 `json:"blockNumber" rlp:"-"`
+ TxHash *types.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
+ TxIndex *hexutil.Uint `json:"transactionIndex" rlp:"-"`
+ BlockHash *types.Hash `json:"blockHash" rlp:"-"`
+ BlockTimestamp *hexutil.Uint64 `json:"blockTimestamp" rlp:"-"`
+ Index *hexutil.Uint `json:"logIndex" rlp:"-"`
+ Removed *bool `json:"removed" rlp:"-"`
+ }
+ var dec Log
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Address == nil {
+ return errors.New("missing required field 'address' for Log")
+ }
+ l.Address = *dec.Address
+ if dec.Topics == nil {
+ return errors.New("missing required field 'topics' for Log")
+ }
+ l.Topics = dec.Topics
+ if dec.Data == nil {
+ return errors.New("missing required field 'data' for Log")
+ }
+ l.Data = *dec.Data
+ if dec.BlockNumber != nil {
+ l.BlockNumber = uint64(*dec.BlockNumber)
+ }
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionHash' for Log")
+ }
+ l.TxHash = *dec.TxHash
+ if dec.TxIndex != nil {
+ l.TxIndex = uint(*dec.TxIndex)
+ }
+ if dec.BlockHash != nil {
+ l.BlockHash = *dec.BlockHash
+ }
+ if dec.BlockTimestamp != nil {
+ l.BlockTimestamp = uint64(*dec.BlockTimestamp)
+ }
+ if dec.Index != nil {
+ l.Index = uint(*dec.Index)
+ }
+ if dec.Removed != nil {
+ l.Removed = *dec.Removed
+ }
+ return nil
+}
diff --git a/types/hashes.go b/types/hashes.go
new file mode 100644
index 000000000..06e0e3a80
--- /dev/null
+++ b/types/hashes.go
@@ -0,0 +1,48 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package types
+
+import (
+ "github.com/openrelayxyz/cardinal-types"
+ "github.com/openrelayxyz/cardinal-evm/crypto"
+)
+
+var (
+ // EmptyRootHash is the known root hash of an empty merkle trie.
+ EmptyRootHash = types.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyUncleHash is the known hash of the empty uncle set.
+ EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
+
+ // EmptyCodeHash is the known hash of the empty EVM bytecode.
+ EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
+
+ // EmptyTxsHash is the known hash of the empty transaction set.
+ EmptyTxsHash = types.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyReceiptsHash is the known hash of the empty receipt set.
+ EmptyReceiptsHash = types.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
+ EmptyWithdrawalsHash = types.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyRequestsHash is the known hash of an empty request set, sha256("").
+ EmptyRequestsHash = types.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
+
+ // EmptyVerkleHash is the known hash of an empty verkle trie.
+ EmptyVerkleHash = types.Hash{}
+)
diff --git a/types/hashing.go b/types/hashing.go
index 83ba5adaf..4c1abef30 100644
--- a/types/hashing.go
+++ b/types/hashing.go
@@ -63,7 +63,7 @@ func prefixedRlpHash(prefix byte, x interface{}) (h ctypes.Hash) {
// This is internal, do not use.
type TrieHasher interface {
Reset()
- Update([]byte, []byte)
+ Update(key []byte, value []byte) error
Hash() ctypes.Hash
}
diff --git a/types/legacy_tx.go b/types/legacy_tx.go
index 331c551fc..e6c00cd9a 100644
--- a/types/legacy_tx.go
+++ b/types/legacy_tx.go
@@ -123,4 +123,4 @@ func (tx *LegacyTx) encode(b *bytes.Buffer) error {
func (tx *LegacyTx) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
-}
\ No newline at end of file
+}
diff --git a/types/log.go b/types/log.go
index 947587061..cdafa19af 100644
--- a/types/log.go
+++ b/types/log.go
@@ -41,19 +41,21 @@ type Log struct {
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
// block in which the transaction was included
- BlockNumber uint64 `json:"blockNumber"`
+ BlockNumber uint64 `json:"blockNumber" rlp:"-"`
// hash of the transaction
- TxHash types.Hash `json:"transactionHash" gencodec:"required"`
+ TxHash types.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
// index of the transaction in the block
- TxIndex uint `json:"transactionIndex"`
+ TxIndex uint `json:"transactionIndex" rlp:"-"`
// hash of the block in which the transaction was included
- BlockHash types.Hash `json:"blockHash"`
+ BlockHash types.Hash `json:"blockHash" rlp:"-"`
+ // timestamp of the block in which the transaction was included
+ BlockTimestamp uint64 `json:"blockTimestamp" rlp:"-"`
// index of the log in the block
- Index uint `json:"logIndex"`
+ Index uint `json:"logIndex" rlp:"-"`
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
- Removed bool `json:"removed"`
+ Removed bool `json:"removed" rlp:"-"`
}
type logMarshaling struct {
diff --git a/types/marshalling.go b/types/marshalling.go
new file mode 100644
index 000000000..da805e4c3
--- /dev/null
+++ b/types/marshalling.go
@@ -0,0 +1,82 @@
+package types
+
+import (
+ // "github.com/openrelayxyz/cardinal-evm/api"
+ "github.com/openrelayxyz/cardinal-evm/params"
+ "github.com/openrelayxyz/cardinal-types"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
+)
+
+// RPCMarshalHeader converts the given header to the RPC output .
+func RPCMarshalHeader(head *Header) map[string]interface{} {
+ result := map[string]interface{}{
+ "number": (*hexutil.Big)(head.Number),
+ "hash": head.Hash(),
+ "parentHash": head.ParentHash,
+ "nonce": head.Nonce,
+ "mixHash": head.MixDigest,
+ "sha3Uncles": head.UncleHash,
+ "logsBloom": hexutil.Encode(head.Bloom.Bytes()),
+ // "stateRoot": head.Root,
+ "miner": head.Coinbase,
+ "difficulty": (*hexutil.Big)(head.Difficulty),
+ "extraData": hexutil.Bytes(head.Extra),
+ "gasLimit": hexutil.Uint64(head.GasLimit),
+ "gasUsed": hexutil.Uint64(head.GasUsed),
+ "timestamp": hexutil.Uint64(head.Time),
+ "transactionsRoot": head.TxHash,
+ "receiptsRoot": head.ReceiptHash,
+ }
+ if head.BaseFee != nil {
+ result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
+ }
+ if head.WithdrawalsHash != nil {
+ result["withdrawalsRoot"] = head.WithdrawalsHash
+ }
+ if head.BlobGasUsed != nil {
+ result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed)
+ }
+ if head.ExcessBlobGas != nil {
+ result["excessBlobGas"] = hexutil.Uint64(*head.ExcessBlobGas)
+ }
+ if head.ParentBeaconRoot != nil {
+ result["parentBeaconBlockRoot"] = head.ParentBeaconRoot
+ }
+ if head.RequestsHash != nil {
+ result["requestsHash"] = head.RequestsHash
+ }
+ return result
+}
+
+// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
+// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
+// transaction hashes.
+func RPCMarshalBlock(block *Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} {
+ fields := RPCMarshalHeader(block.Header())
+ if inclTx {
+ formatTx := func(idx int, tx *Transaction) interface{} {
+ return tx.Hash()
+ }
+ if fullTx {
+ formatTx = func(idx int, tx *Transaction) interface{} {
+ return NewRPCTransactionFromBlockIndex(block, uint64(idx), config)
+ }
+ }
+ txs := block.transactions
+ transactions := make([]interface{}, len(txs))
+ for i, tx := range txs {
+ transactions[i] = formatTx(i, tx)
+ }
+ fields["transactions"] = transactions
+ }
+ uncles := block.uncles
+ uncleHashes := make([]types.Hash, len(uncles))
+ for i, uncle := range uncles {
+ uncleHashes[i] = uncle.Hash()
+ }
+ fields["uncles"] = uncleHashes
+ if block.withdrawals != nil {
+ fields["withdrawals"] = block.withdrawals
+ }
+ return fields
+}
diff --git a/types/receipt.go b/types/receipt.go
new file mode 100644
index 000000000..9ac86a0c9
--- /dev/null
+++ b/types/receipt.go
@@ -0,0 +1,166 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package types
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
+ "github.com/openrelayxyz/cardinal-evm/rlp"
+ "github.com/openrelayxyz/cardinal-types"
+)
+
+//go:generate go run github.com/fjl/gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
+
+var (
+ receiptStatusFailedRLP = []byte{}
+ receiptStatusSuccessfulRLP = []byte{0x01}
+)
+
+var errShortTypedReceipt = errors.New("typed receipt too short")
+
+const (
+ // ReceiptStatusFailed is the status code of a transaction if execution failed.
+ ReceiptStatusFailed = uint64(0)
+
+ // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
+ ReceiptStatusSuccessful = uint64(1)
+)
+
+
+// Receipt represents the results of a transaction.
+type Receipt struct {
+ // Consensus fields: These fields are defined by the Yellow Paper
+ Type uint8 `json:"type,omitempty"`
+ PostState []byte `json:"root"`
+ Status uint64 `json:"status"`
+ CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Logs []*Log `json:"logs" gencodec:"required"`
+
+ // Implementation fields: These fields are added by geth when processing a transaction.
+ TxHash types.Hash `json:"transactionHash" gencodec:"required"`
+ ContractAddress common.Address `json:"contractAddress"`
+ GasUsed uint64 `json:"gasUsed" gencodec:"required"`
+ EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility
+ BlobGasUsed uint64 `json:"blobGasUsed,omitempty"`
+ BlobGasPrice *big.Int `json:"blobGasPrice,omitempty"`
+
+ // Inclusion information: These fields provide information about the inclusion of the
+ // transaction corresponding to this receipt.
+ BlockHash types.Hash `json:"blockHash,omitempty"`
+ BlockNumber *big.Int `json:"blockNumber,omitempty"`
+ TransactionIndex uint `json:"transactionIndex"`
+}
+
+type receiptMarshaling struct {
+ Type hexutil.Uint64
+ PostState hexutil.Bytes
+ Status hexutil.Uint64
+ CumulativeGasUsed hexutil.Uint64
+ GasUsed hexutil.Uint64
+ EffectiveGasPrice *hexutil.Big
+ BlobGasUsed hexutil.Uint64
+ BlobGasPrice *hexutil.Big
+ BlockNumber *hexutil.Big
+ TransactionIndex hexutil.Uint
+}
+
+// receiptRLP is the consensus encoding of a receipt.
+type receiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ Bloom Bloom
+ Logs []*Log
+}
+
+// storedReceiptRLP is the storage encoding of a receipt.
+type storedReceiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ Logs []*Log
+}
+
+
+
+func (r *Receipt) setStatus(postStateOrStatus []byte) error {
+ switch {
+ case bytes.Equal(postStateOrStatus, receiptStatusSuccessfulRLP):
+ r.Status = ReceiptStatusSuccessful
+ case bytes.Equal(postStateOrStatus, receiptStatusFailedRLP):
+ r.Status = ReceiptStatusFailed
+ case len(postStateOrStatus) == len(types.Hash{}):
+ r.PostState = postStateOrStatus
+ default:
+ return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
+ }
+ return nil
+}
+
+func (r *Receipt) statusEncoding() []byte {
+ if len(r.PostState) == 0 {
+ if r.Status == ReceiptStatusFailed {
+ return receiptStatusFailedRLP
+ }
+ return receiptStatusSuccessfulRLP
+ }
+ return r.PostState
+}
+
+// DeriveReceiptContext holds the contextual information needed to derive a receipt
+type DeriveReceiptContext struct {
+ BlockHash types.Hash
+ BlockNumber uint64
+ BlockTime uint64
+ BaseFee *big.Int
+ BlobGasPrice *big.Int
+ GasUsed uint64
+ LogIndex uint // Number of logs in the block until this receipt
+ Tx *Transaction
+ TxIndex uint
+}
+
+
+
+// Receipts implements DerivableList for receipts.
+type Receipts []*Receipt
+
+// Len returns the number of receipts in this list.
+func (rs Receipts) Len() int { return len(rs) }
+
+// EncodeIndex encodes the i'th receipt to w.
+func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
+ r := rs[i]
+ data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
+ if r.Type == LegacyTxType {
+ rlp.Encode(w, data)
+ return
+ }
+ w.WriteByte(r.Type)
+ switch r.Type {
+ case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType:
+ rlp.Encode(w, data)
+ default:
+ // For unsupported types, write nothing. Since this is for
+ // DeriveSha, the error will be caught matching the derived hash
+ // to the block.
+ }
+}
diff --git a/types/rpc.go b/types/rpc.go
new file mode 100644
index 000000000..35c85fd08
--- /dev/null
+++ b/types/rpc.go
@@ -0,0 +1,234 @@
+package types
+
+import (
+ "math/big"
+
+ // "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/params"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
+
+ "github.com/openrelayxyz/cardinal-types"
+)
+
+// // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
+// type RPCTransaction struct {
+// BlockHash *Hash `json:"blockHash"`
+// BlockNumber *hexutil.Big `json:"blockNumber"`
+// From common.Address `json:"from"`
+// Gas hexutil.Uint64 `json:"gas"`
+// GasPrice *hexutil.Big `json:"gasPrice"`
+// GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
+// GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
+// MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
+// Hash Hash `json:"hash"`
+// Input hexutil.Bytes `json:"input"`
+// Nonce hexutil.Uint64 `json:"nonce"`
+// To *common.Address `json:"to"`
+// TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
+// Value *hexutil.Big `json:"value"`
+// Type hexutil.Uint64 `json:"type"`
+// Accesses *types.AccessList `json:"accessList,omitempty"`
+// ChainID *hexutil.Big `json:"chainId,omitempty"`
+// BlobVersionedHashes []Hash `json:"blobVersionedHashes,omitempty"`
+// AuthorizationList []SetCodeAuthorization `json:"authorizationList,omitempty"`
+// V *hexutil.Big `json:"v"`
+// R *hexutil.Big `json:"r"`
+// S *hexutil.Big `json:"s"`
+// YParity *hexutil.Uint64 `json:"yParity,omitempty"`
+// }
+
+// newRPCTransaction returns a transaction that will serialize to the RPC
+// representation, with the given location metadata set (if available).
+// func newRPCTransaction(tx *Transaction, blockHash types.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) {
+func newRPCTransaction(tx *Transaction, blockHash types.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
+ signer := MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
+ from, _ := Sender(signer, tx)
+ v, r, s := tx.RawSignatureValues()
+ result := &RPCTransaction{
+ Type: hexutil.Uint64(tx.Type()),
+ From: from,
+ Gas: hexutil.Uint64(tx.Gas()),
+ GasPrice: (*hexutil.Big)(tx.GasPrice()),
+ Hash: tx.Hash(),
+ Input: hexutil.Bytes(tx.Data()),
+ Nonce: hexutil.Uint64(tx.Nonce()),
+ To: tx.To(),
+ Value: (*hexutil.Big)(tx.Value()),
+ V: (*hexutil.Big)(v),
+ R: (*hexutil.Big)(r),
+ S: (*hexutil.Big)(s),
+ }
+ if blockHash != (types.Hash{}) {
+ result.BlockHash = &blockHash
+ result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
+ result.TransactionIndex = (*hexutil.Uint64)(&index)
+ }
+
+ switch tx.Type() {
+ case LegacyTxType:
+ // if a legacy transaction has an EIP-155 chain id, include it explicitly
+ if id := tx.ChainId(); id.Sign() != 0 {
+ result.ChainID = (*hexutil.Big)(id)
+ }
+
+ case AccessListTxType:
+ al := tx.AccessList()
+ yparity := hexutil.Uint64(v.Sign())
+ result.Accesses = &al
+ result.ChainID = (*hexutil.Big)(tx.ChainId())
+ result.YParity = &yparity
+
+ case DynamicFeeTxType:
+ al := tx.AccessList()
+ yparity := hexutil.Uint64(v.Sign())
+ result.Accesses = &al
+ result.ChainID = (*hexutil.Big)(tx.ChainId())
+ result.YParity = &yparity
+ result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
+ result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
+ // if the transaction has been mined, compute the effective gas price
+ if baseFee != nil && blockHash != (types.Hash{}) {
+ // price = min(gasTipCap + baseFee, gasFeeCap)
+ result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee))
+ } else {
+ result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
+ }
+
+ case BlobTxType:
+ al := tx.AccessList()
+ yparity := hexutil.Uint64(v.Sign())
+ result.Accesses = &al
+ result.ChainID = (*hexutil.Big)(tx.ChainId())
+ result.YParity = &yparity
+ result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
+ result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
+ // if the transaction has been mined, compute the effective gas price
+ if baseFee != nil && blockHash != (types.Hash{}) {
+ result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee))
+ } else {
+ result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
+ }
+ result.MaxFeePerBlobGas = (*hexutil.Big)(tx.BlobGasFeeCap())
+ result.BlobVersionedHashes = tx.BlobHashes()
+
+ case SetCodeTxType:
+ al := tx.AccessList()
+ yparity := hexutil.Uint64(v.Sign())
+ result.Accesses = &al
+ result.ChainID = (*hexutil.Big)(tx.ChainId())
+ result.YParity = &yparity
+ result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
+ result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
+ // if the transaction has been mined, compute the effective gas price
+ if baseFee != nil && blockHash != (types.Hash{}) {
+ result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee))
+ } else {
+ result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
+ }
+ result.AuthorizationList = tx.SetCodeAuthorizations()
+ }
+ return result
+}
+
+// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
+// func newRPCTransactionFromBlockIndex(b *Block, index uint64, config *params.ChainConfig) {
+func newRPCTransactionFromBlockIndex(b *Block, index uint64, config *params.ChainConfig) *RPCTransaction {
+ txs := b.transactions
+ if index >= uint64(len(txs)) {
+ return nil
+ }
+ return newRPCTransaction(txs[index], b.header.Hash(), b.header.Number.Uint64(), b.header.Time, index, b.header.BaseFee, config)
+}
+
+// func NewRPCTransactionFromBlockIndex(b *Block, index uint64, config *params.ChainConfig) {
+func NewRPCTransactionFromBlockIndex(b *Block, index uint64, config *params.ChainConfig) *RPCTransaction {
+ return newRPCTransactionFromBlockIndex(b, index, config)
+}
+
+// effectiveGasPrice computes the transaction gas fee, based on the given basefee value.
+//
+// price = min(gasTipCap + baseFee, gasFeeCap)
+func effectiveGasPrice(tx *Transaction, baseFee *big.Int) *big.Int {
+ fee := tx.GasTipCap()
+ fee = fee.Add(fee, baseFee)
+ if tx.GasFeeCapIntCmp(fee) < 0 {
+ return tx.GasFeeCap()
+ }
+ return fee
+}
+
+// // RPCMarshalHeader converts the given header to the RPC output .
+// func RPCMarshalHeader(head *types.Header) map[string]interface{} {
+// result := map[string]interface{}{
+// "number": (*hexutil.Big)(head.Number),
+// "hash": head.Hash(),
+// "parentHash": head.ParentHash,
+// "nonce": head.Nonce,
+// "mixHash": head.MixDigest,
+// "sha3Uncles": head.UncleHash,
+// "logsBloom": head.Bloom,
+// "stateRoot": head.Root,
+// "miner": head.Coinbase,
+// "difficulty": (*hexutil.Big)(head.Difficulty),
+// "extraData": hexutil.Bytes(head.Extra),
+// "gasLimit": hexutil.Uint64(head.GasLimit),
+// "gasUsed": hexutil.Uint64(head.GasUsed),
+// "timestamp": hexutil.Uint64(head.Time),
+// "transactionsRoot": head.TxHash,
+// "receiptsRoot": head.ReceiptHash,
+// }
+// if head.BaseFee != nil {
+// result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
+// }
+// if head.WithdrawalsHash != nil {
+// result["withdrawalsRoot"] = head.WithdrawalsHash
+// }
+// if head.BlobGasUsed != nil {
+// result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed)
+// }
+// if head.ExcessBlobGas != nil {
+// result["excessBlobGas"] = hexutil.Uint64(*head.ExcessBlobGas)
+// }
+// if head.ParentBeaconRoot != nil {
+// result["parentBeaconBlockRoot"] = head.ParentBeaconRoot
+// }
+// if head.RequestsHash != nil {
+// result["requestsHash"] = head.RequestsHash
+// }
+// return result
+// }
+
+// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
+// // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
+// // transaction hashes.
+// func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} {
+// fields := RPCMarshalHeader(block.Header())
+// fields["size"] = hexutil.Uint64(block.Size())
+
+// if inclTx {
+// formatTx := func(idx int, tx *types.Transaction) interface{} {
+// return tx.Hash()
+// }
+// if fullTx {
+// formatTx = func(idx int, tx *types.Transaction) interface{} {
+// return newRPCTransactionFromBlockIndex(block, uint64(idx), config)
+// }
+// }
+// txs := block.Transactions()
+// transactions := make([]interface{}, len(txs))
+// for i, tx := range txs {
+// transactions[i] = formatTx(i, tx)
+// }
+// fields["transactions"] = transactions
+// }
+// uncles := block.Uncles()
+// uncleHashes := make([]Hash, len(uncles))
+// for i, uncle := range uncles {
+// uncleHashes[i] = uncle.Hash()
+// }
+// fields["uncles"] = uncleHashes
+// if block.Withdrawals() != nil {
+// fields["withdrawals"] = block.Withdrawals()
+// }
+// return fields
+// }
\ No newline at end of file
diff --git a/types/transaction.go b/types/transaction.go
index bb4e30a54..cdbacc39a 100644
--- a/types/transaction.go
+++ b/types/transaction.go
@@ -29,6 +29,7 @@ import (
"github.com/openrelayxyz/cardinal-evm/common/math"
"github.com/openrelayxyz/cardinal-evm/crypto"
"github.com/openrelayxyz/cardinal-evm/rlp"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
ctypes "github.com/openrelayxyz/cardinal-types"
)
@@ -305,6 +306,24 @@ func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() }
func (tx *Transaction) BlobHashes() []ctypes.Hash { return tx.inner.blobHashes() }
+// SetCodeAuthorizations returns the authorizations list of the transaction.
+func (tx *Transaction) SetCodeAuthorizations() []SetCodeAuthorization {
+ // setcodetx, ok := tx.inner.(*SetCodeTx)
+ // if !ok {
+ // return nil
+ // }
+ // return setcodetx.AuthList
+ setcodetx, ok := tx.inner.(*SetCodeTx)
+ if !ok {
+ return nil
+ }
+ auths := make([]SetCodeAuthorization, len(setcodetx.AuthList))
+ for i, a := range setcodetx.AuthList {
+ auths[i] = SetCodeAuthorization(a) // requires they are type-compatible
+ }
+ return auths
+}
+
// To returns the recipient address of the transaction.
// For contract-creation transactions, To returns nil.
func (tx *Transaction) To() *common.Address {
@@ -682,4 +701,31 @@ func copyAddressPtr(a *common.Address) *common.Address {
}
cpy := *a
return &cpy
+}
+
+// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
+type RPCTransaction struct {
+ BlockHash *ctypes.Hash `json:"blockHash"`
+ BlockNumber *hexutil.Big `json:"blockNumber"`
+ From common.Address `json:"from"`
+ Gas hexutil.Uint64 `json:"gas"`
+ GasPrice *hexutil.Big `json:"gasPrice"`
+ GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
+ GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
+ MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
+ Hash ctypes.Hash `json:"hash"`
+ Input hexutil.Bytes `json:"input"`
+ Nonce hexutil.Uint64 `json:"nonce"`
+ To *common.Address `json:"to"`
+ TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
+ Value *hexutil.Big `json:"value"`
+ Type hexutil.Uint64 `json:"type"`
+ Accesses *AccessList `json:"accessList,omitempty"`
+ ChainID *hexutil.Big `json:"chainId,omitempty"`
+ BlobVersionedHashes []ctypes.Hash `json:"blobVersionedHashes,omitempty"`
+ AuthorizationList []SetCodeAuthorization `json:"authorizationList,omitempty"`
+ V *hexutil.Big `json:"v"`
+ R *hexutil.Big `json:"r"`
+ S *hexutil.Big `json:"s"`
+ YParity *hexutil.Uint64 `json:"yParity,omitempty"`
}
\ No newline at end of file
diff --git a/types/tx_setcode.go b/types/tx_setcode.go
index 92750aef3..29f86e1ed 100644
--- a/types/tx_setcode.go
+++ b/types/tx_setcode.go
@@ -26,7 +26,6 @@ import (
"github.com/openrelayxyz/cardinal-evm/crypto"
"github.com/openrelayxyz/cardinal-evm/rlp"
ctypes "github.com/openrelayxyz/cardinal-types"
- "github.com/openrelayxyz/cardinal-types/hexutil"
"github.com/holiman/uint256"
)
@@ -79,14 +78,14 @@ type Authorization struct {
S uint256.Int `json:"s" gencodec:"required"`
}
-// field type overrides for gencodec
-type authorizationMarshaling struct {
- ChainID U256
- Nonce hexutil.Uint64
- V hexutil.Uint64
- R U256
- S U256
-}
+// // field type overrides for gencodec
+// type authorizationMarshaling struct {
+// ChainID U256
+// Nonce hexutil.Uint64
+// V hexutil.Uint64
+// R U256
+// S U256
+// }
// SignAuth signs the provided authorization.
func SignAuth(auth Authorization, prv *ecdsa.PrivateKey) (Authorization, error) {
diff --git a/types/withdrawals.go b/types/withdrawal.go
similarity index 84%
rename from types/withdrawals.go
rename to types/withdrawal.go
index d92f59925..8ac137e67 100644
--- a/types/withdrawals.go
+++ b/types/withdrawal.go
@@ -1,4 +1,3 @@
-
// Copyright 2022 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
@@ -19,10 +18,11 @@ package types
import (
"bytes"
+ "reflect"
- "github.com/openrelayxyz/plugeth-utils/core"
- "github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
- "github.com/openrelayxyz/plugeth-utils/restricted/rlp"
+ "github.com/openrelayxyz/cardinal-evm/common"
+ "github.com/openrelayxyz/cardinal-evm/rlp"
+ "github.com/openrelayxyz/cardinal-types/hexutil"
)
//go:generate go run github.com/fjl/gencodec -type Withdrawal -field-override withdrawalMarshaling -out gen_withdrawal_json.go
@@ -32,7 +32,7 @@ import (
type Withdrawal struct {
Index uint64 `json:"index"` // monotonically increasing identifier issued by consensus layer
Validator uint64 `json:"validatorIndex"` // index of validator associated with withdrawal
- Address core.Address `json:"address"` // target address for withdrawn ether
+ Address common.Address `json:"address"` // target address for withdrawn ether
Amount uint64 `json:"amount"` // value of withdrawal in Gwei
}
@@ -49,9 +49,15 @@ type Withdrawals []*Withdrawal
// Len returns the length of s.
func (s Withdrawals) Len() int { return len(s) }
+var withdrawalSize = int(reflect.TypeFor[Withdrawal]().Size())
+
+func (s Withdrawals) Size() int {
+ return withdrawalSize * len(s)
+}
+
// EncodeIndex encodes the i'th withdrawal to w. Note that this does not check for errors
// because we assume that *Withdrawal will only ever contain valid withdrawals that were either
// constructed by decoding or via public API in this package.
func (s Withdrawals) EncodeIndex(i int, w *bytes.Buffer) {
rlp.Encode(w, s[i])
-}
\ No newline at end of file
+}