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 +}