diff --git a/.gitignore b/.gitignore index b03960262..7f0c48cb0 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ nimcache /debug*.json /block*.json /.update.timestamp + +*.generated.nim diff --git a/.gitmodules b/.gitmodules index 323c31aeb..63a2b5dd8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -114,8 +114,8 @@ ignore = dirty branch = master [submodule "vendor/nim-web3"] - path = vendor/nim-web3 - url = https://github.com/status-im/nim-web3.git + path = vendor/nim-web3 + url = https://github.com/status-im/nim-web3.git ignore = dirty branch = master [submodule "vendor/nim-byteutils"] diff --git a/nimbus/accounts/manager.nim b/nimbus/accounts/manager.nim index 3d4db9394..a77366875 100644 --- a/nimbus/accounts/manager.nim +++ b/nimbus/accounts/manager.nim @@ -8,7 +8,7 @@ # those terms. import - std/[os, json, tables], + std/[os, json, tables, strutils], stew/[byteutils, results], eth/[keyfile, common, keys], chronicles @@ -87,7 +87,7 @@ iterator addresses*(am: AccountsManager): EthAddress = proc importPrivateKey*(am: var AccountsManager, fileName: string): Result[void, string] = try: let pkhex = readFile(fileName) - let res = PrivateKey.fromHex(pkhex) + let res = PrivateKey.fromHex(pkhex.strip) if res.isErr: return err("not a valid private key, expect 32 bytes hex") diff --git a/nimbus/chain_config.nim b/nimbus/chain_config.nim index c6680582a..2e51c8022 100644 --- a/nimbus/chain_config.nim +++ b/nimbus/chain_config.nim @@ -40,6 +40,7 @@ type londonBlock : Option[BlockNumber] arrowGlacierBlock : Option[BlockNumber] clique : CliqueOptions + terminalTotalDifficulty*: Option[UInt256] ChainConfig* = object chainId* : ChainId @@ -67,6 +68,8 @@ type cliquePeriod* : int cliqueEpoch* : int + terminalTotalDifficulty*: Option[UInt256] + Genesis* = object nonce* : BlockNonce timestamp* : EthTime @@ -76,6 +79,9 @@ type mixHash* : Hash256 coinbase* : EthAddress alloc* : GenesisAlloc + number* : BlockNumber + gasUser* : GasInt + parentHash* : Hash256 baseFeePerGas*: Option[UInt256] GenesisAlloc* = Table[EthAddress, GenesisAccount] @@ -97,6 +103,21 @@ type config : ChainOptions genesis: Genesis + GenesisFile* = object + config : ChainOptions + nonce* : BlockNonce + timestamp* : EthTime + extraData* : seq[byte] + gasLimit* : GasInt + difficulty* : DifficultyInt + mixHash* : Hash256 + coinbase* : EthAddress + alloc* : GenesisAlloc + number* : BlockNumber + gasUser* : GasInt + parentHash* : Hash256 + baseFeePerGas*: Option[UInt256] + const CustomNet* = 0.NetworkId # these are public network id @@ -194,6 +215,8 @@ proc loadNetworkParams*(fileName: string, cg: var NetworkParams): if cc.config.clique.epoch.isSome: cg.config.cliqueEpoch = cc.config.clique.epoch.get() + cg.config.terminalTotalDifficulty = cc.config.terminalTotalDifficulty + template validateFork(forkName: untyped, nextBlock: BlockNumber) = let fork = astToStr(forkName) if cc.config.forkName.isSome: diff --git a/nimbus/config.nim b/nimbus/config.nim index c7fd9005d..a267f441c 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -102,6 +102,7 @@ const defaultEthRpcPort = 8545 defaultEthWsPort = 8546 defaultEthGraphqlPort = 8547 + defaultEngineApiPort = 8550 defaultListenAddress = (static ValidIpAddress.init("0.0.0.0")) defaultAdminListenAddress = (static ValidIpAddress.init("127.0.0.1")) defaultListenAddressDesc = $defaultListenAddress & ", meaning all network interfaces" @@ -306,6 +307,27 @@ type defaultValueDesc: $DiscoveryType.V4 name: "discovery" .}: DiscoveryType + terminalTotalDifficulty* {. + desc: "The terminal total difficulty of the eth2 merge transition block" + name: "terminal-total-difficulty" .}: Option[UInt256] + + engineApiEnabled* {. + desc: "Enable the Engine API" + defaultValue: false + name: "engine-api" .}: bool + + engineApiPort* {. + desc: "Listening port for the Engine API" + defaultValue: defaultEngineApiPort + defaultValueDesc: $defaultEngineApiPort + name: "engine-api-port" .}: Port + + engineApiAddress* {. + desc: "Listening address for the Engine API" + defaultValue: defaultAdminListenAddress + defaultValueDesc: defaultAdminListenAddressDesc + name: "engine-api-address" .}: ValidIpAddress + nodeKeyHex* {. desc: "P2P node private key (as 32 bytes hex string)" defaultValue: "" @@ -418,13 +440,18 @@ type defaultValue: "" name: "blocks-file" }: InputFile - proc parseCmdArg(T: type NetworkId, p: TaintedString): T = parseInt(p.string).T proc completeCmdArg(T: type NetworkId, val: TaintedString): seq[string] = return @[] +proc parseCmdArg(T: type UInt256, p: TaintedString): T = + parse(string p, T) + +proc completeCmdArg(T: type UInt256, val: TaintedString): seq[string] = + return @[] + proc parseCmdArg(T: type EthAddress, p: TaintedString): T = try: result = hexToByteArray(p.string, 20) diff --git a/nimbus/db/db_chain.nim b/nimbus/db/db_chain.nim index 2827cbda2..ce5b931f5 100644 --- a/nimbus/db/db_chain.nim +++ b/nimbus/db/db_chain.nim @@ -55,8 +55,13 @@ proc exists*(self: BaseChainDB, hash: Hash256): bool = proc getBlockHeader*(self: BaseChainDB; blockHash: Hash256, output: var BlockHeader): bool = let data = self.db.get(genericHashKey(blockHash).toOpenArray) if data.len != 0: - output = rlp.decode(data, BlockHeader) - result = true + try: + output = rlp.decode(data, BlockHeader) + true + except RlpError: + false + else: + false proc getBlockHeader*(self: BaseChainDB, blockHash: Hash256): BlockHeader = ## Returns the requested block header as specified by block hash. @@ -273,6 +278,17 @@ proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockH return newCanonicalHeaders +proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool = + ## Returns True if the header with the given block hash is in our DB. + self.db.contains(genericHashKey(blockHash).toOpenArray) + +proc setHead*(self: BaseChainDB, blockHash: Hash256): bool = + if self.headerExists(blockHash): + self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(blockHash)) + return true + else: + return false + proc setHead*(self: BaseChainDB, header: BlockHeader, writeHeader = false) = var headerHash = rlpHash(header) if writeHeader: @@ -280,10 +296,6 @@ proc setHead*(self: BaseChainDB, header: BlockHeader, writeHeader = false) = self.addBlockNumberToHashLookup(header) self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(headerHash)) -proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool = - ## Returns True if the header with the given block hash is in our DB. - self.db.contains(genericHashKey(blockHash).toOpenArray) - proc persistReceipts*(self: BaseChainDB, receipts: openArray[Receipt]): Hash256 = var trie = initHexaryTrie(self.db) for idx, rec in receipts: diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index 35f2f1873..bf9b243e4 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -18,11 +18,12 @@ import chronos, json_rpc/rpcserver, chronicles, eth/p2p/rlpx_protocols/les_protocol, ./p2p/blockchain_sync, eth/net/nat, eth/p2p/peer_pool, + ./p2p/clique/[clique_desc, clique_sealer], ./sync/protocol_eth65, - config, genesis, rpc/[common, p2p, debug], p2p/chain, + config, genesis, rpc/[common, p2p, debug, engine_api], p2p/chain, eth/trie/db, metrics, metrics/[chronos_httpserver, chronicles_support], graphql/ethapi, context, - "."/[conf_utils, sealer, constants] + "."/[conf_utils, sealer, constants, utils] when defined(evmc_enabled): import transaction/evmc_dynamic_loader @@ -38,6 +39,7 @@ type NimbusNode = ref object rpcServer: RpcHttpServer + engineApiServer: RpcHttpServer ethNode: EthereumNode state: NimbusState graphqlServer: GraphqlHttpServerRef @@ -183,11 +185,38 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf, if rs.isErr: echo rs.error quit(QuitFailure) + + proc signFunc(signer: EthAddress, message: openArray[byte]): Result[RawSignature, cstring] {.gcsafe.} = + let + hashData = keccakHash(message) + acc = nimbus.ctx.am.getAccount(signer).tryGet() + rawSign = sign(acc.privateKey, SkMessage(hashData.data)).toRaw + + ok(rawSign) + + # TODO: There should be a better place to initialize this + nimbus.chainRef.clique.authorize(conf.engineSigner, signFunc) + + let initialSealingEngineState = + if conf.networkParams.config.terminalTotalDifficulty.isSome and + conf.networkParams.config.terminalTotalDifficulty.get.isZero: + nimbus.chainRef.ttdReachedAt = some(BlockNumber.zero) + EnginePostMerge + else: + EngineStopped nimbus.sealingEngine = SealingEngineRef.new( - nimbus.chainRef, nimbus.ctx, conf.engineSigner - ) + # TODO: Implement the initial state correctly + nimbus.chainRef, nimbus.ctx, conf.engineSigner, initialSealingEngineState) nimbus.sealingEngine.start() + if conf.engineApiEnabled: + nimbus.engineApiServer = newRpcHttpServer([ + initTAddress(conf.engineApiAddress, conf.engineApiPort) + ]) + setupEngineAPI(nimbus.sealingEngine, nimbus.engineApiServer) + nimbus.engineAPiServer.start() + info "Starting engine API server", port = conf.engineApiPort + # metrics server if conf.metricsEnabled: info "Starting metrics HTTP server", address = conf.metricsAddress, port = conf.metricsPort @@ -241,6 +270,8 @@ proc stop*(nimbus: NimbusNode, conf: NimbusConf) {.async, gcsafe.} = trace "Graceful shutdown" if conf.rpcEnabled: await nimbus.rpcServer.stop() + if conf.engineApiEnabled: + await nimbus.engineAPiServer.stop() if conf.wsEnabled: nimbus.wsRpcServer.stop() if conf.graphqlEnabled: diff --git a/nimbus/p2p/chain/chain_desc.nim b/nimbus/p2p/chain/chain_desc.nim index edbe109d5..1d2673bb8 100644 --- a/nimbus/p2p/chain/chain_desc.nim +++ b/nimbus/p2p/chain/chain_desc.nim @@ -63,6 +63,11 @@ type ## For non-PoA networks (when `db.config.poaEngine` is `false`), ## this descriptor is ignored. + ttdReachedAt*: Option[BlockNumber] + ## The first block which difficulty was above the terminal + ## total difficulty. In networks with TTD=0, this would be + ## the very first block. + {.push raises: [Defect].} # ------------------------------------------------------------------------------ @@ -75,6 +80,9 @@ func toNextFork(n: BlockNumber): uint64 = else: result = n.truncate(uint64) +func isBlockAfterTtd*(c: Chain, blockNum: BlockNumber): bool = + c.ttdReachedAt.isSome and blockNum > c.ttdReachedAt.get + func getNextFork(c: ChainConfig, fork: ChainFork): uint64 = let next: array[ChainFork, uint64] = [ 0'u64, @@ -165,7 +173,6 @@ proc newChain*(db: BaseChainDB; poa: Clique; extraValidation: bool): Chain new result result.initChain(db, poa, extraValidation) - proc newChain*(db: BaseChainDB, extraValidation: bool): Chain {.gcsafe, raises: [Defect,CatchableError].} = ## Constructor for the `Chain` descriptor object with default initialisation diff --git a/nimbus/p2p/chain/persist_blocks.nim b/nimbus/p2p/chain/persist_blocks.nim index a1349f8db..a1617b37f 100644 --- a/nimbus/p2p/chain/persist_blocks.nim +++ b/nimbus/p2p/chain/persist_blocks.nim @@ -90,7 +90,8 @@ proc persistBlocksImpl(c: Chain; headers: openarray[BlockHeader]; header, body, checkSealOK = false, # TODO: how to checkseal from here - c.pow) + ttdReached = c.isBlockAfterTtd(header.blockNumber), + pow = c.pow) if res.isErr: debug "block validation error", msg = res.error diff --git a/nimbus/p2p/clique/clique_sealer.nim b/nimbus/p2p/clique/clique_sealer.nim index 4d85f1002..55a3bdcc9 100644 --- a/nimbus/p2p/clique/clique_sealer.nim +++ b/nimbus/p2p/clique/clique_sealer.nim @@ -167,7 +167,7 @@ proc verifyUncles*(c: Clique; ethBlock: EthBlock): CliqueOkResult = # clique/clique.go(506): func (c *Clique) Prepare(chain [..] proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOkResult - {.gcsafe, raises: [Defect,CatchableError].} = + {.gcsafe, raises: [Defect, CatchableError].} = ## For the Consensus Engine, `prepare()` initializes the consensus fields ## of a block header according to the rules of a particular engine. The ## changes are executed inline. @@ -175,10 +175,6 @@ proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOk ## This implementation prepares all the consensus fields of the header for ## running the transactions on top. - # If the block isn't a checkpoint, cast a random vote (good enough for now) - header.coinbase.reset - header.nonce.reset - # Assemble the voting snapshot to check which votes make sense let rc = c.cliqueSnapshot(header.parentHash, @[]) if rc.isErr: @@ -225,7 +221,6 @@ proc authorize*(c: Clique; signer: EthAddress; signFn: CliqueSignerFn) = c.signer = signer c.signFn = signFn - # clique/clique.go(724): func CliqueRLP(header [..] proc cliqueRlp*(header: BlockHeader): seq[byte] = ## Returns the rlp bytes which needs to be signed for the proof-of-authority @@ -238,7 +233,6 @@ proc cliqueRlp*(header: BlockHeader): seq[byte] = ##hashes for the same header. header.encodeSealHeader - # clique/clique.go(688): func SealHash(header *types.Header) common.Hash { proc sealHash*(header: BlockHeader): Hash256 = ## For the Consensus Engine, `sealHash()` returns the hash of a block prior diff --git a/nimbus/p2p/gaslimit.nim b/nimbus/p2p/gaslimit.nim index b5d8429a1..58ea65aff 100644 --- a/nimbus/p2p/gaslimit.nim +++ b/nimbus/p2p/gaslimit.nim @@ -35,7 +35,8 @@ const # Pre Eip 1559 gas limit validation # ------------------------------------------------------------------------------ -proc validateGasLimit(header: BlockHeader; limit: GasInt): Result[void, string] = +proc validateGasLimit(header: BlockHeader; limit: GasInt): Result[void, string] + {.raises: [Defect].} = let diff = if limit > header.gasLimit: limit - header.gasLimit else: @@ -44,14 +45,21 @@ proc validateGasLimit(header: BlockHeader; limit: GasInt): Result[void, string] let upperLimit = limit div GAS_LIMIT_ADJUSTMENT_FACTOR if diff >= upperLimit: - return err(&"invalid gas limit: have {header.gasLimit}, want {limit} +-= {upperLimit-1}") + try: + return err(&"invalid gas limit: have {header.gasLimit}, want {limit} +-= {upperLimit-1}") + except ValueError: + # TODO deprecate-strformat + raiseAssert "strformat cannot fail" if header.gasLimit < GAS_LIMIT_MINIMUM: return err("invalid gas limit below 5000") ok() -proc validateGasLimit(c: BaseChainDB; header: BlockHeader): Result[void, string] {. - gcsafe, raises: [Defect,RlpError,BlockNotFound,ValueError].} = - let parent = c.getBlockHeader(header.parentHash) +proc validateGasLimit(c: BaseChainDB; header: BlockHeader): Result[void, string] + {.raises: [Defect].} = + let parent = try: + c.getBlockHeader(header.parentHash) + except CatchableError: + return err "Parent block not in database" header.validateGasLimit(parent.gasLimit) # ------------------------------------------------------------------------------ @@ -105,8 +113,8 @@ proc calcEip1599BaseFee*(c: ChainConfig; parent: BlockHeader): UInt256 = # consensus/misc/eip1559.go(32): func VerifyEip1559Header(config [..] proc verifyEip1559Header(c: ChainConfig; - parent, header: BlockHeader): Result[void, string] {. - gcsafe, raises: [Defect,ValueError].} = + parent, header: BlockHeader): Result[void, string] + {.raises: [Defect].} = ## Verify that the gas limit remains within allowed bounds let limit = if c.isLondonOrLater(parent.blockNumber): parent.gasLimit @@ -124,22 +132,25 @@ proc verifyEip1559Header(c: ChainConfig; # Verify the baseFee is correct based on the parent header. var expectedBaseFee = c.calcEip1599BaseFee(parent) if headerBaseFee != expectedBaseFee: - return err(&"invalid baseFee: have {expectedBaseFee}, "& - &"want {header.baseFee}, " & - &"parent.baseFee {parent.baseFee}, "& - &"parent.gasUsed {parent.gasUsed}") + try: + return err(&"invalid baseFee: have {expectedBaseFee}, "& + &"want {header.baseFee}, " & + &"parent.baseFee {parent.baseFee}, "& + &"parent.gasUsed {parent.gasUsed}") + except ValueError: + # TODO deprecate-strformat + raiseAssert "strformat cannot fail" return ok() proc validateGasLimitOrBaseFee*(c: BaseChainDB; - header, parent: BlockHeader): Result[void, string] {. - gcsafe, raises: [Defect,ValueError,CatchableError].} = + header, parent: BlockHeader): Result[void, string] + {.gcsafe, raises: [Defect].} = if not c.config.isLondonOrLater(header.blockNumber): # Verify BaseFee not present before EIP-1559 fork. if not header.baseFee.isZero: - return err("invalid baseFee before London fork: have " & - &"{header.baseFee}, want <0>") + return err("invalid baseFee before London fork: have " & $header.baseFee & ", want <0>") let rc = c.validateGasLimit(header) if rc.isErr: return rc diff --git a/nimbus/p2p/validate.nim b/nimbus/p2p/validate.nim index fd07c096c..f623c2aa8 100644 --- a/nimbus/p2p/validate.nim +++ b/nimbus/p2p/validate.nim @@ -13,18 +13,15 @@ import ../constants, ../db/[db_chain, accounts_cache], ../transaction, - ../utils/[difficulty, header], - ../vm_state, - ../vm_types, - ../forks, + ../utils/[difficulty, header, pow], + ".."/[vm_state, vm_types, forks, errors], ./dao, - ../utils/pow, ./gaslimit, chronicles, eth/[common, rlp], nimcrypto, options, - stew/[results, endians2] + stew/[objects, results, endians2] from stew/byteutils import nil @@ -52,14 +49,17 @@ func isGenesis(header: BlockHeader): bool = # Pivate validator functions # ------------------------------------------------------------------------------ -proc validateSeal(pow: PoWRef; header: BlockHeader): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = - let (expMixDigest,miningValue) = pow.getPowDigest(header) +proc validateSeal(pow: PoWRef; header: BlockHeader): Result[void,string] = + let (expMixDigest, miningValue) = try: + pow.getPowDigest(header) + except CatchableError as err: + return err("test") if expMixDigest != header.mixDigest: let miningHash = header.getPowSpecs.miningHash - (size, cachedHash) = pow.getPowCacheLookup(header.blockNumber) + (size, cachedHash) = try: pow.getPowCacheLookup(header.blockNumber) + except KeyError: return err("Unknown block") debug "mixHash mismatch", actual = header.mixDigest, expected = expMixDigest, @@ -79,8 +79,7 @@ proc validateSeal(pow: PoWRef; header: BlockHeader): Result[void,string] proc validateHeader(db: BaseChainDB; header, parentHeader: BlockHeader; numTransactions: int; checkSealOK: bool; - pow: PowRef): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = + ttdReached: bool; pow: PowRef): Result[void,string] = template inDAOExtraRange(blockNumber: BlockNumber): bool = # EIP-799 @@ -109,16 +108,28 @@ proc validateHeader(db: BaseChainDB; header, parentHeader: BlockHeader; if header.extraData != daoForkBlockExtraData: return err("header extra data should be marked DAO") - let calcDiffc = db.config.calcDifficulty(header.timestamp, parentHeader) - if header.difficulty < calcDiffc: - return err("provided header difficulty is too low") + if ttdReached: + if not header.mixDigest.isZeroMemory: + return err("Non-zero mix hash in a post-merge block") - if checkSealOK: - return pow.validateSeal(header) + if not header.difficulty.isZero: + return err("Non-zero difficulty in a post-merge block") + + if not header.nonce.isZeroMemory: + return err("Non-zero nonce in a post-merge block") + + if header.ommersHash != EMPTY_UNCLE_HASH: + return err("Invalid ommers hash in a post-merge block") + else: + let calcDiffc = db.config.calcDifficulty(header.timestamp, parentHeader) + if header.difficulty < calcDiffc: + return err("provided header difficulty is too low") + + if checkSealOK: + return pow.validateSeal(header) result = ok() - func validateUncle(currBlock, uncle, uncleParent: BlockHeader): Result[void,string] = if uncle.blockNumber >= currBlock.blockNumber: @@ -138,8 +149,7 @@ func validateUncle(currBlock, uncle, uncleParent: BlockHeader): proc validateUncles(chainDB: BaseChainDB; header: BlockHeader; uncles: seq[BlockHeader]; checkSealOK: bool; - pow: PowRef): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = + pow: PowRef): Result[void,string] = let hasUncles = uncles.len > 0 let shouldHaveUncles = header.ommersHash != EMPTY_UNCLE_HASH @@ -161,9 +171,16 @@ proc validateUncles(chainDB: BaseChainDB; header: BlockHeader; else: uncleSet.incl uncleHash - let recentAncestorHashes = chainDB.getAncestorsHashes( - MAX_UNCLE_DEPTH + 1, header) - let recentUncleHashes = chainDB.getUncleHashes(recentAncestorHashes) + let recentAncestorHashes = try: + chainDB.getAncestorsHashes(MAX_UNCLE_DEPTH + 1, header) + except CatchableError as err: + return err("Block not present in database") + + let recentUncleHashes = try: + chainDB.getUncleHashes(recentAncestorHashes) + except CatchableError as err: + return err("Ancenstors not present in database") + let blockHash = header.blockHash for uncle in uncles: @@ -199,7 +216,11 @@ proc validateUncles(chainDB: BaseChainDB; header: BlockHeader; if result.isErr: return - let uncleParent = chainDB.getBlockHeader(uncle.parentHash) + let uncleParent = try: + chainDB.getBlockHeader(uncle.parentHash) + except BlockNotFound: + return err("Uncle parent not found") + result = validateUncle(header, uncle, uncleParent) if result.isErr: return @@ -318,18 +339,26 @@ proc validateTransaction*( # Public functions, extracted from test_blockchain_json # ------------------------------------------------------------------------------ -proc validateHeaderAndKinship*(chainDB: BaseChainDB; header: BlockHeader; - uncles: seq[BlockHeader]; numTransactions: int; checkSealOK: bool; - pow: PowRef): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = +proc validateHeaderAndKinship*( + chainDB: BaseChainDB; + header: BlockHeader; + uncles: seq[BlockHeader]; + numTransactions: int; + checkSealOK: bool; + ttdReached: bool; + pow: PowRef): Result[void, string] = if header.isGenesis: if header.extraData.len > 32: return err("BlockHeader.extraData larger than 32 bytes") return ok() - let parent = chainDB.getBlockHeader(header.parentHash) + let parent = try: + chainDB.getBlockHeader(header.parentHash) + except CatchableError as err: + return err("Failed to load block header from DB") + result = chainDB.validateHeader( - header, parent, numTransactions, checkSealOK, pow) + header, parent, numTransactions, checkSealOK, ttdReached, pow) if result.isErr: return @@ -339,24 +368,32 @@ proc validateHeaderAndKinship*(chainDB: BaseChainDB; header: BlockHeader; if not chainDB.exists(header.stateRoot): return err("`state_root` was not found in the db.") - result = chainDB.validateUncles(header, uncles, checkSealOK, pow) + if not ttdReached: + result = chainDB.validateUncles(header, uncles, checkSealOK, pow) + if result.isOk: result = chainDB.validateGasLimitOrBaseFee(header, parent) +proc validateHeaderAndKinship*( + chainDB: BaseChainDB; + header: BlockHeader; + body: BlockBody; + checkSealOK: bool; + ttdReached: bool; + pow: PowRef): Result[void, string] {.gcsafe,raises: [CatchableError, Defect].} = -proc validateHeaderAndKinship*(chainDB: BaseChainDB; - header: BlockHeader; body: BlockBody; checkSealOK: bool; - pow: PowRef): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = chainDB.validateHeaderAndKinship( - header, body.uncles, body.transactions.len, checkSealOK, pow) + header, body.uncles, body.transactions.len, checkSealOK, ttdReached, pow) - -proc validateHeaderAndKinship*(chainDB: BaseChainDB; ethBlock: EthBlock; - checkSealOK: bool; pow: PowRef): Result[void,string] - {.gcsafe,raises: [Defect,CatchableError].} = +proc validateHeaderAndKinship*( + chainDB: BaseChainDB; + ethBlock: EthBlock; + checkSealOK: bool; + ttdReached: bool; + pow: PowRef): Result[void,string] = chainDB.validateHeaderAndKinship( - ethBlock.header, ethBlock.uncles, ethBlock.txs.len, checkSealOK, pow) + ethBlock.header, ethBlock.uncles, ethBlock.txs.len, + checkSealOK, ttdReached, pow) # ------------------------------------------------------------------------------ # End diff --git a/nimbus/rpc/engine_api.nim b/nimbus/rpc/engine_api.nim new file mode 100644 index 000000000..0509ee565 --- /dev/null +++ b/nimbus/rpc/engine_api.nim @@ -0,0 +1,111 @@ +# Nimbus +# Copyright (c) 2018 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +# * MIT license ([LICENSE-MIT](LICENSE-MIT)) +# at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import + std/[typetraits, times], + stew/[objects, results], + json_rpc/[rpcserver, errors], + web3/[conversions, engine_api_types], + eth/[trie, rlp, common, trie/db], + ".."/db/db_chain, + ".."/p2p/chain/[chain_desc, persist_blocks], + ".."/[sealer, utils, constants] + +import eth/common/eth_types except BlockHeader +type EthBlockHeader = eth_types.BlockHeader + +# TODO move this to stew/objects +template newClone*[T: not ref](x: T): ref T = + # TODO not nil in return type: https://github.com/nim-lang/Nim/issues/14146 + # TODO use only when x is a function call that returns a new instance! + let res = new typeof(x) # TODO safe to do noinit here? + res[] = x + res + +template asEthHash*(hash: engine_api_types.BlockHash): Hash256 = + Hash256(data: distinctBase(hash)) + +template unsafeQuantityToInt64(q: Quantity): int64 = + int64 q + +proc calcRootHashRlp*(items: openArray[seq[byte]]): Hash256 = + var tr = initHexaryTrie(newMemoryDB()) + for i, t in items: + tr.put(rlp.encode(i), t) + return tr.rootHash() + +proc toBlockHeader(payload: ExecutionPayload): eth_types.BlockHeader = + discard payload.random # TODO: What should this be used for? + + let transactions = seq[seq[byte]](payload.transactions) + let txRoot = calcRootHashRlp(transactions) + + EthBlockHeader( + parentHash : payload.parentHash.asEthHash, + ommersHash : EMPTY_UNCLE_HASH, + coinbase : EthAddress payload.coinbase, + stateRoot : payload.stateRoot.asEthHash, + txRoot : txRoot, + receiptRoot : payload.receiptRoot.asEthHash, + bloom : distinctBase(payload.logsBloom), + difficulty : default(DifficultyInt), + blockNumber : payload.blockNumber.distinctBase.u256, + gasLimit : payload.gasLimit.unsafeQuantityToInt64, + gasUsed : payload.gasUsed.unsafeQuantityToInt64, + timestamp : fromUnix payload.timestamp.unsafeQuantityToInt64, + extraData : distinctBase payload.extraData, + mixDigest : default(Hash256), + nonce : default(BlockNonce), + fee : some payload.baseFeePerGas + ) + +proc toBlockBody(payload: ExecutionPayload): BlockBody = + # TODO the transactions from the payload have to be converted here + discard payload.transactions + +proc setupEngineAPI*(sealingEngine: SealingEngineRef, server: RpcServer) = + + var payloadsInstance = newClone(newSeq[ExecutionPayload]()) + template payloads: auto = payloadsInstance[] + + server.rpc("engine_getPayload") do(payloadId: Quantity) -> ExecutionPayload: + if payloadId.uint64 > high(int).uint64 or + int(payloadId) >= payloads.len: + raise (ref InvalidRequest)(code: UNKNOWN_PAYLOAD, msg: "Unknown payload") + return payloads[int payloadId] + + server.rpc("engine_executePayload") do(payload: ExecutionPayload) -> ExecutePayloadResponse: + # TODO + if payload.transactions.len > 0: + # Give us a break, a block with transcations? instructions to execute? + # Nah, we are syncing! + return ExecutePayloadResponse(status: $PayloadExecutionStatus.syncing) + let + headers = [payload.toBlockHeader] + bodies = [payload.toBlockBody] + + if rlpHash(headers[0]) != payload.blockHash.asEthHash: + return ExecutePayloadResponse(status: $PayloadExecutionStatus.invalid) + + if sealingEngine.chain.persistBlocks(headers, bodies) != ValidationResult.OK: + return ExecutePayloadResponse(status: $PayloadExecutionStatus.invalid) + + return ExecutePayloadResponse(status: $PayloadExecutionStatus.valid) + + server.rpc("engine_forkchoiceUpdated") do(update: ForkChoiceUpdate): + let + db = sealingEngine.chain.db + newHead = update.headBlockHash.asEthHash + + # TODO Use the finalized block information to prune any alterantive + # histories that are no longer relevant + discard update.finalizedBlockHash + + if not db.setHead(newHead): + raise (ref InvalidRequest)(code: UNKNOWN_HEADER, msg: "Uknown head block hash") diff --git a/nimbus/sealer.nim b/nimbus/sealer.nim index 367f97385..a622ff1c6 100644 --- a/nimbus/sealer.nim +++ b/nimbus/sealer.nim @@ -9,8 +9,8 @@ # according to those terms. import - std/[times, tables], - pkg/[chronos, eth/common, eth/keys, stew/results, chronicles], + std/[times, tables, typetraits], + pkg/[chronos, stew/results, chronicles, eth/common, eth/keys], "."/[config, db/db_chain, p2p/chain, constants, utils/header], "."/p2p/clique/[clique_defs, clique_desc, @@ -19,18 +19,31 @@ import ./p2p/gaslimit, "."/[chain_config, utils, context] +from web3/ethtypes as web3types import nil +from web3/engine_api_types import ExecutionPayload, PayloadAttributes + type - EngineState = enum - EngineStopped, EngineRunning + EngineState* = enum + EngineStopped, + EngineRunning, + EnginePostMerge + + Web3BlockHash = web3types.BlockHash + Web3Address = web3types.Address + Web3Bloom = web3types.FixedBytes[256] + Web3Quantity = web3types.Quantity SealingEngineRef* = ref SealingEngineObj SealingEngineObj = object of RootObj state: EngineState engineLoop: Future[void] - chain: Chain + chain*: Chain ctx: EthContext signer: EthAddress +template asEthHash*(hash: Web3BlockHash): Hash256 = + Hash256(data: distinctBase(hash)) + proc validateSealer*(conf: NimbusConf, ctx: EthContext, chain: Chain): Result[void, string] = if conf.engineSigner == ZERO_ADDRESS: return err("signer address should not zero, use --engine-signer to set signer address") @@ -52,7 +65,10 @@ proc validateSealer*(conf: NimbusConf, ctx: EthContext, chain: Chain): Result[vo proc isLondon(c: ChainConfig, number: BlockNumber): bool {.inline.} = number >= c.londonBlock -proc prepareHeader(engine: SealingEngineRef, parent: BlockHeader, time: Time): Result[BlockHeader, string] = +proc prepareHeader(engine: SealingEngineRef, + coinbase: EthAddress, + parent: BlockHeader, + time: Time): Result[BlockHeader, string] = let timestamp = if parent.timestamp >= time: parent.timestamp + 1.seconds else: @@ -69,6 +85,7 @@ proc prepareHeader(engine: SealingEngineRef, parent: BlockHeader, time: Time): R gasCeil = DEFAULT_GAS_LIMIT), # TODO: extraData can be configured via cli #extraData : engine.extra, + coinbase : coinbase, timestamp : timestamp, ommersHash : EMPTY_UNCLE_HASH, stateRoot : parent.stateRoot, @@ -87,14 +104,21 @@ proc prepareHeader(engine: SealingEngineRef, parent: BlockHeader, time: Time): R # TODO: desiredLimit can be configured by user, gasCeil header.gasLimit = calcGasLimit1559(parentGasLimit, desiredLimit = DEFAULT_GAS_LIMIT) + # TODO Post merge, clique should not be executing let clique = engine.chain.clique let res = clique.prepare(parent, header) if res.isErr: return err($res.error) + if engine.chain.isBlockAfterTtd(header.blockNumber): + header.difficulty = DifficultyInt.zero + ok(header) -proc generateBlock(engine: SealingEngineRef, ethBlock: var EthBlock): Result[void,string] = +proc generateBlock(engine: SealingEngineRef, + coinbase: EthAddress, + parentBlockHeader: BlockHeader, + outBlock: var EthBlock): Result[void, string] = # deviation from standard block generator # - no local and remote transactions inclusion(need tx pool) # - no receipts from tx @@ -102,23 +126,48 @@ proc generateBlock(engine: SealingEngineRef, ethBlock: var EthBlock): Result[voi # - no local and remote uncles inclusion let clique = engine.chain.clique - let parent = engine.chain.currentBlock() - let time = getTime() - let res = prepareHeader(engine, parent, time) + let res = prepareHeader(engine, coinbase, parentBlockHeader, time) if res.isErr: return err("error prepare header") - ethBlock = EthBlock( + outBlock = EthBlock( header: res.get() ) - let sealRes = clique.seal(ethBlock) + # TODO Post merge, Clique should not be executing + let sealRes = clique.seal(outBlock) if sealRes.isErr: return err("error sealing block header: " & $sealRes.error) + debug "generated block", + blockNumber = outBlock.header.blockNumber, + blockHash = blockHash(outBlock.header) + ok() +proc generateBlock(engine: SealingEngineRef, + coinbase: EthAddress, + parentHash: Hash256, + outBlock: var EthBlock): Result[void, string] = + var parentBlockHeader: BlockHeader + if engine.chain.db.getBlockHeader(parentHash, parentBlockHeader): + generateBlock(engine, coinbase, parentBlockHeader, outBlock) + else: + # TODO: + # This hack shouldn't be necessary if the database can find + # the genesis block hash in `getBlockHeader`. + let maybeGenesisBlock = engine.chain.currentBlock() + if parentHash == maybeGenesisBlock.blockHash: + generateBlock(engine, coinbase, maybeGenesisBlock, outBlock) + else: + return err "parent block not found" + +proc generateBlock(engine: SealingEngineRef, + coinbase: EthAddress, + outBlock: var EthBlock): Result[void, string] = + generateBlock(engine, coinbase, engine.chain.currentBlock(), outBlock) + proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} = let clique = engine.chain.clique @@ -134,6 +183,9 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} = clique.authorize(engine.signer, signerFunc) + # TODO: This should be configurable + var coinbase: EthAddress + # convert times.Duration to chronos.Duration let period = chronos.seconds(clique.cfg.period.inSeconds) @@ -148,7 +200,7 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} = # - no queue for chain reorgs # - no async lock/guard against race with sync algo var blk: EthBlock - let blkRes = engine.generateBlock(blk) + let blkRes = engine.generateBlock(coinbase, blk) if blkRes.isErr: error "sealing engine generateBlock error", msg=blkRes.error break @@ -163,14 +215,50 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} = info "block generated", number=blk.header.blockNumber +proc generateExecutionPayload*(engine: SealingEngineRef, + payloadAttrs: PayloadAttributes, + payloadRes: var ExecutionPayload): Result[void, string] = + var blk: EthBlock + let blkRes = engine.generateBlock(EthAddress payloadAttrs.feeRecipient, + payloadAttrs.parentHash.asEthHash, + blk) + if blkRes.isErr: + error "sealing engine generateBlock error", msg = blkRes.error + return blkRes + + let res = engine.chain.persistBlocks([blk.header], [ + BlockBody(transactions: blk.txs, uncles: blk.uncles) + ]) + + payloadRes.parentHash = Web3BlockHash blk.header.parentHash.data + payloadRes.coinbase = Web3Address blk.header.coinbase + payloadRes.stateRoot = Web3BlockHash blk.header.stateRoot.data + payloadRes.receiptRoot = Web3BlockHash blk.header.receiptRoot.data + payloadRes.logsBloom = Web3Bloom blk.header.bloom + payloadRes.random = web3types.FixedBytes[32](payloadAttrs.random) + payloadRes.blockNumber = Web3Quantity blk.header.blockNumber.truncate(uint64) + payloadRes.gasLimit = Web3Quantity blk.header.gasLimit + payloadRes.gasUsed = Web3Quantity blk.header.gasUsed + payloadRes.timestamp = payloadAttrs.timestamp + # TODO + # res.extraData + payloadRes.baseFeePerGas = blk.header.fee.get(UInt256.zero) + payloadRes.blockHash = Web3BlockHash rlpHash(blk.header).data + # TODO + # res.transactions*: seq[TypedTransaction] + + return ok() + proc new*(_: type SealingEngineRef, chain: Chain, ctx: EthContext, - signer: EthAddress): SealingEngineRef = + signer: EthAddress, + initialState: EngineState): SealingEngineRef = SealingEngineRef( chain: chain, ctx: ctx, - signer: signer + signer: signer, + state: initialState ) proc start*(engine: SealingEngineRef) = diff --git a/nimbus/utils/pow.nim b/nimbus/utils/pow.nim index 63f5af4f8..e67ab6e06 100644 --- a/nimbus/utils/pow.nim +++ b/nimbus/utils/pow.nim @@ -227,8 +227,8 @@ proc getPowSpecs*(header: BlockHeader): PowSpecs = difficulty: header.difficulty) proc getPowCacheLookup*(tm: PowRef; - blockNumber: BlockNumber): (uint64,Hash256) - {.gcsafe,raises: [Defect,CatchableError].} = + blockNumber: BlockNumber): (uint64, Hash256) + {.gcsafe, raises: [KeyError, Defect].} = ## Returns the pair `(size,digest)` derived from the lookup cache for the ## `hashimotoLight()` function for the given block number. The `size` is the ## full size of the dataset (the cache represents) as passed on to the @@ -238,6 +238,8 @@ proc getPowCacheLookup*(tm: PowRef; ## This function is intended for error reporting and might also be useful ## for testing and debugging. let ds = tm.lightByEpoch.get(blockNumber) + if ds == nil: + raise newException(KeyError, "block not found") result[0] = ds.size diff --git a/nimbus/utils/pow/pow_cache.nim b/nimbus/utils/pow/pow_cache.nim index 32b3f0577..81c8d5e00 100644 --- a/nimbus/utils/pow/pow_cache.nim +++ b/nimbus/utils/pow/pow_cache.nim @@ -71,7 +71,7 @@ proc new*(T: type PowCacheRef; maxItems = nItemsMax): T = # ------------------------------------------------------------------------------ proc get*(pc: var PowCache; bn: BlockNumber): PowCacheItemRef - {.gcsafe,raises: [Defect,CatchableError].} = + {.gcsafe, raises: [Defect].} = ## Return a cache derived from argument `blockNumber` ready to be used ## for the `hashimotoLight()` method. let @@ -91,12 +91,10 @@ proc get*(pc: var PowCache; bn: BlockNumber): PowCacheItemRef pc.cache.lruAppend(key, pair, pc.cacheMax) -proc get*(pcr: PowCacheRef; bn: BlockNumber): PowCacheItemRef - {.gcsafe,raises: [Defect,CatchableError].} = +proc get*(pcr: PowCacheRef; bn: BlockNumber): PowCacheItemRef = ## Variant of `getCache()` pcr[].get(bn) - proc hasItem*(pc: var PowCache; bn: BlockNumber): bool {.gcsafe,raises: [Defect,CatchableError].} = ## Returns true if there is a cache entry for argument `bn`. diff --git a/tests/amphora/.gitignore b/tests/amphora/.gitignore new file mode 100644 index 000000000..b189e585f --- /dev/null +++ b/tests/amphora/.gitignore @@ -0,0 +1 @@ +hacknet/ diff --git a/tests/amphora/amphora-interop-genesis-m1.json b/tests/amphora/amphora-interop-genesis-m1.json new file mode 100644 index 000000000..3c7b19f26 --- /dev/null +++ b/tests/amphora/amphora-interop-genesis-m1.json @@ -0,0 +1,41 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "daoForkBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + }, + "terminalTotalDifficulty": 0 + }, + "genesis": { + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1C9C380", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x6d6172697573766477000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x7" + } +} diff --git a/tests/amphora/check-merge-test-vectors.sh b/tests/amphora/check-merge-test-vectors.sh new file mode 100755 index 000000000..82a577e10 --- /dev/null +++ b/tests/amphora/check-merge-test-vectors.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# https://notes.ethereum.org/@9AeMAlpyQYaAAyuj47BzRw/rkwW3ceVY +# +# git clone --branch merge-interop-spec https://github.com/MariusVanDerWijden/go-ethereum.git +# +# Last checked against geth as of +# commit d6b04900423634d27be1178edf46622394085bb9 (HEAD -> merge-interop-spec, origin/merge-interop-spec) +# Author: Marius van der Wijden +# Date: Wed Sep 29 19:24:56 2021 +0200 +# +# eth/catalyst: fix random in payload, payloadid as hexutil + +# Get the payload +resp_get_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_getPayload","params":["0x0"],"id":67}' http://localhost:8550) +echo "engine_getPayload response: ${resp_get_payload}" + +expected_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}' +empirical_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0x7a694c5e6e372e6f865b073c101c2fba01f899f16480eb13f7e333a3b7e015bc","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}' +[[ ${resp_get_payload} == ${expected_resp_get_payload} ]] || [[ ${resp_get_payload} == ${empirical_resp_get_payload} ]] || (echo "Unexpected response to engine_getPayload"; false) + +# Execute the payload +# Needed two tweaks vs upstream note: (a) add blockNumber field and (b) switch receiptRoots to receiptRoot +resp_execute_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_executePayload","params":[{"blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858","parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x7","transactions":[]}],"id":67}' http://localhost:8550) +[[ ${resp_execute_payload} == '{"jsonrpc":"2.0","id":67,"result":{"status":"VALID"}}' ]] || (echo "Unexpected response to engine_executePayload"; false) + +# Update the fork choice +resp_fork_choice_updated=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_forkchoiceUpdated","params":[{"headBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", "finalizedBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"}],"id":67}' http://localhost:8550) +[[ ${resp_consensus_validated} == '{"jsonrpc":"2.0","id":67,"result":null}' ]] || (echo "Unexpected response to engine_forkChoiceUpdated"; false) + +echo "Execution test vectors for Merge passed" diff --git a/tests/amphora/connect-to-hacknet-v2.sh b/tests/amphora/connect-to-hacknet-v2.sh new file mode 100755 index 000000000..caa3548e3 --- /dev/null +++ b/tests/amphora/connect-to-hacknet-v2.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -eu + +SCRIPT_DIR=$(cd $(dirname "$0") && pwd) + +cd "$SCRIPT_DIR" + +if [[ ! -d hacknet ]]; then + git clone https://github.com/karalabe/hacknet/ +fi + +DATA_DIR=hacknet/data/nimbus-eth1 +mkdir -p $DATA_DIR + +BOOT_NODE=enode://e95870e55cf62fd3d7091d7e0254d10ead007a1ac64ea071296a603d94694b8d92b49f9a3d3851d9aa95ee1452de8b854e0d5e095ef58cc25e7291e7588f4dfc@35.178.114.73:30303 + +$SCRIPT_DIR/../../build/nimbus \ + --log-level:DEBUG \ + --data-dir:"$SCRIPT_DIR/$DATA_DIR" \ + --custom-network:"$SCRIPT_DIR/hacknet/v2/genesis.json" \ + --bootstrap-node:$BOOT_NODE \ + --network:1337002 \ + --engine-api \ + --rpc + diff --git a/tests/amphora/launch-nimbus.sh b/tests/amphora/launch-nimbus.sh new file mode 100755 index 000000000..ca4841f80 --- /dev/null +++ b/tests/amphora/launch-nimbus.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# set -Eeuo pipefail + +# https://notes.ethereum.org/@9AeMAlpyQYaAAyuj47BzRw/rkwW3ceVY + +# To increase verbosity: debug.verbosity(4) +# MetaMask seed phrase for address with balance is: +# lecture manual soon title cloth uncle gesture cereal common fruit tooth crater + +set -eu + +SCRIPT_DIR=$(cd $(dirname "$0") && pwd) + +DATA_DIR=$(mktemp -d) +echo Using data dir ${DATA_DIR} + +$SCRIPT_DIR/../../build/nimbus \ + --log-level:TRACE \ + --data-dir:"${DATA_DIR}" \ + --custom-network:"$SCRIPT_DIR/amphora-interop-genesis-m1.json" \ + --network:0 \ + --engine-api \ + --rpc \ + --nat:none --discovery:none \ + --import-key:"$SCRIPT_DIR/signer-key.txt" \ + --engine-signer:0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b + diff --git a/tests/amphora/signer-key.txt b/tests/amphora/signer-key.txt new file mode 100644 index 000000000..da79bfa4c --- /dev/null +++ b/tests/amphora/signer-key.txt @@ -0,0 +1 @@ +0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8 diff --git a/tests/test_blockchain_json.nim b/tests/test_blockchain_json.nim index b64ad6f60..f17dd884f 100644 --- a/tests/test_blockchain_json.nim +++ b/tests/test_blockchain_json.nim @@ -262,7 +262,7 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB, if validation: let rc = chainDB.validateHeaderAndKinship( - result.header, body, checkSeal, pow) + result.header, body, checkSeal, false, pow) if rc.isErr: raise newException( ValidationError, "validateHeaderAndKinship: " & rc.error) @@ -312,7 +312,7 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes # manually validating check chainDB.validateHeaderAndKinship( - preminedBlock, checkSeal, pow).isOk + preminedBlock, checkSeal, false, pow).isOk except: debugEcho "FATAL ERROR(WE HAVE BUG): ", getCurrentExceptionMsg() diff --git a/tests/test_configuration.nim b/tests/test_configuration.nim index cebbc2711..9f31b5205 100644 --- a/tests/test_configuration.nim +++ b/tests/test_configuration.nim @@ -65,7 +65,7 @@ proc configurationMain*() = check conf.networkId == 678.NetworkId check conf.networkParams == NetworkParams() - test "network-id not set, copy from chainId of customnetwork": + test "network-id not set, copy from chainId of custom network": let conf = makeConfig(@["--custom-network:" & genesisFile]) check conf.networkId == 123.NetworkId diff --git a/vendor/nim-stew b/vendor/nim-stew index b464505b4..bb705bf17 160000 --- a/vendor/nim-stew +++ b/vendor/nim-stew @@ -1 +1 @@ -Subproject commit b464505b4dcbe2ef52d19b2cfca8f2be4ebf2c7e +Subproject commit bb705bf17b46d2c8f9bfb106d9cc7437009a2501 diff --git a/vendor/nim-web3 b/vendor/nim-web3 new file mode 160000 index 000000000..16ae908e4 --- /dev/null +++ b/vendor/nim-web3 @@ -0,0 +1 @@ +Subproject commit 16ae908e49dad3dd1be1d536798a2b0ae39250df diff --git a/witnessBuilderBC.md b/witnessBuilderBC.md index 7b6d8940f..a5ed00619 100644 --- a/witnessBuilderBC.md +++ b/witnessBuilderBC.md @@ -1,5 +1,12 @@ witnessBuilderBC === +## bcBerlinToLondon +```diff ++ BerlinToLondonTransition.json OK ++ initialVal.json OK ++ londonUncles.json OK +``` +OK: 3/3 Fail: 0/3 Skip: 0/3 ## bcBlockGasLimitTest ```diff + BlockGasLimit2p63m1.json OK @@ -15,11 +22,39 @@ OK: 6/6 Fail: 0/6 Skip: 0/6 + ConstantinopleFixTransition.json OK ``` OK: 1/1 Fail: 0/1 Skip: 0/1 +## bcEIP1559 +```diff ++ badBlocks.json OK ++ badUncles.json OK ++ baseFee.json OK ++ besuBaseFeeBug.json OK ++ burnVerify.json OK ++ checkGasLimit.json OK ++ feeCap.json OK ++ gasLimit20m.json OK ++ gasLimit40m.json OK ++ highDemand.json OK ++ intrinsic.json OK ++ intrinsicOrFail.json OK ++ intrinsicTip.json OK ++ lowDemand.json OK ++ medDemand.json OK ++ tips.json OK ++ transFail.json OK ++ transType.json OK ++ valCausesOOF.json OK +``` +OK: 19/19 Fail: 0/19 Skip: 0/19 ## bcEIP158ToByzantium ```diff + ByzantiumTransition.json OK ``` OK: 1/1 Fail: 0/1 Skip: 0/1 +## bcExample +```diff ++ basefeeExample.json OK +``` +OK: 1/1 Fail: 0/1 Skip: 0/1 ## bcExploitTest ```diff + DelegateCallSpam.json OK @@ -88,6 +123,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + ExtraData33.json OK + GasLimitHigherThan2p63m1.json OK + GasLimitIsZero.json OK ++ badTimestamp.json OK + log1_wrongBlockNumber.json OK + log1_wrongBloom.json OK + timeDiff0.json OK @@ -104,7 +140,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + wrongTransactionsTrie.json OK + wrongUncleHash.json OK ``` -OK: 21/21 Fail: 0/21 Skip: 0/21 +OK: 22/22 Fail: 0/22 Skip: 0/22 ## bcMultiChainTest ```diff + CallContractFromNotBestBlock.json OK @@ -288,11 +324,26 @@ OK: 96/96 Fail: 0/96 Skip: 0/96 + suicideStorageCheckVCreate.json OK + suicideStorageCheckVCreate2.json OK + suicideThenCheckBalance.json OK -+ testOpcodes.json OK ++ testOpcode_00.json OK ++ testOpcode_10.json OK ++ testOpcode_20.json OK ++ testOpcode_30.json OK ++ testOpcode_40.json OK ++ testOpcode_50.json OK ++ testOpcode_60.json OK ++ testOpcode_70.json OK ++ testOpcode_80.json OK ++ testOpcode_90.json OK ++ testOpcode_A0.json OK ++ testOpcode_B0.json OK ++ testOpcode_C0.json OK ++ testOpcode_D0.json OK ++ testOpcode_E0.json OK ++ testOpcode_F0.json OK + transactionFromNotExistingAccount.json OK + txCost-sec73.json OK ``` -OK: 72/72 Fail: 0/72 Skip: 0/72 +OK: 87/87 Fail: 0/87 Skip: 0/87 ## bcTotalDifficultyTest ```diff + lotsOfBranchesOverrideAtTheEnd.json OK @@ -320,6 +371,7 @@ OK: 11/11 Fail: 0/11 Skip: 0/11 + gasLimitTooLow.json OK + gasLimitTooLowExactBound.json OK + gasLimitTooLowExactBound2.json OK ++ gasLimitTooLowExactBoundLondon.json OK + incorrectUncleNumber0.json OK + incorrectUncleNumber1.json OK + incorrectUncleNumber500.json OK @@ -335,7 +387,7 @@ OK: 11/11 Fail: 0/11 Skip: 0/11 + wrongParentHash.json OK + wrongStateRoot.json OK ``` -OK: 24/24 Fail: 0/24 Skip: 0/24 +OK: 25/25 Fail: 0/25 Skip: 0/25 ## bcUncleSpecialTests ```diff + futureUncleTimestamp2.json OK @@ -467,17 +519,135 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + badOpcodes.json OK + eip2315NotRemoved.json OK + invalidAddr.json OK ++ invalidDiffPlaces.json OK ++ measureGas.json OK ++ opc0CDiffPlaces.json OK ++ opc0DDiffPlaces.json OK ++ opc0EDiffPlaces.json OK ++ opc0FDiffPlaces.json OK ++ opc1EDiffPlaces.json OK ++ opc1FDiffPlaces.json OK ++ opc21DiffPlaces.json OK ++ opc22DiffPlaces.json OK ++ opc23DiffPlaces.json OK ++ opc24DiffPlaces.json OK ++ opc25DiffPlaces.json OK ++ opc26DiffPlaces.json OK ++ opc27DiffPlaces.json OK ++ opc28DiffPlaces.json OK ++ opc29DiffPlaces.json OK ++ opc2ADiffPlaces.json OK ++ opc2BDiffPlaces.json OK ++ opc2CDiffPlaces.json OK ++ opc2DDiffPlaces.json OK ++ opc2EDiffPlaces.json OK ++ opc2FDiffPlaces.json OK ++ opc49DiffPlaces.json OK ++ opc4ADiffPlaces.json OK ++ opc4BDiffPlaces.json OK ++ opc4CDiffPlaces.json OK ++ opc4DDiffPlaces.json OK ++ opc4EDiffPlaces.json OK ++ opc4FDiffPlaces.json OK ++ opc5CDiffPlaces.json OK ++ opc5DDiffPlaces.json OK ++ opc5EDiffPlaces.json OK ++ opc5FDiffPlaces.json OK ++ opcA5DiffPlaces.json OK ++ opcA6DiffPlaces.json OK ++ opcA7DiffPlaces.json OK ++ opcA8DiffPlaces.json OK ++ opcA9DiffPlaces.json OK ++ opcAADiffPlaces.json OK ++ opcABDiffPlaces.json OK ++ opcACDiffPlaces.json OK ++ opcADDiffPlaces.json OK ++ opcAEDiffPlaces.json OK ++ opcAFDiffPlaces.json OK ++ opcB0DiffPlaces.json OK ++ opcB1DiffPlaces.json OK ++ opcB2DiffPlaces.json OK ++ opcB3DiffPlaces.json OK ++ opcB4DiffPlaces.json OK ++ opcB5DiffPlaces.json OK ++ opcB6DiffPlaces.json OK ++ opcB7DiffPlaces.json OK ++ opcB8DiffPlaces.json OK ++ opcB9DiffPlaces.json OK ++ opcBADiffPlaces.json OK ++ opcBBDiffPlaces.json OK ++ opcBCDiffPlaces.json OK ++ opcBDDiffPlaces.json OK ++ opcBEDiffPlaces.json OK ++ opcBFDiffPlaces.json OK ++ opcC0DiffPlaces.json OK ++ opcC1DiffPlaces.json OK ++ opcC2DiffPlaces.json OK ++ opcC3DiffPlaces.json OK ++ opcC4DiffPlaces.json OK ++ opcC5DiffPlaces.json OK ++ opcC6DiffPlaces.json OK ++ opcC7DiffPlaces.json OK ++ opcC8DiffPlaces.json OK ++ opcC9DiffPlaces.json OK ++ opcCADiffPlaces.json OK ++ opcCBDiffPlaces.json OK ++ opcCCDiffPlaces.json OK ++ opcCDDiffPlaces.json OK ++ opcCEDiffPlaces.json OK ++ opcCFDiffPlaces.json OK ++ opcD0DiffPlaces.json OK ++ opcD1DiffPlaces.json OK ++ opcD2DiffPlaces.json OK ++ opcD3DiffPlaces.json OK ++ opcD4DiffPlaces.json OK ++ opcD5DiffPlaces.json OK ++ opcD6DiffPlaces.json OK ++ opcD7DiffPlaces.json OK ++ opcD8DiffPlaces.json OK ++ opcD9DiffPlaces.json OK ++ opcDADiffPlaces.json OK ++ opcDBDiffPlaces.json OK ++ opcDCDiffPlaces.json OK ++ opcDDDiffPlaces.json OK ++ opcDEDiffPlaces.json OK ++ opcDFDiffPlaces.json OK ++ opcE0DiffPlaces.json OK ++ opcE1DiffPlaces.json OK ++ opcE2DiffPlaces.json OK ++ opcE3DiffPlaces.json OK ++ opcE4DiffPlaces.json OK ++ opcE5DiffPlaces.json OK ++ opcE6DiffPlaces.json OK ++ opcE7DiffPlaces.json OK ++ opcE8DiffPlaces.json OK ++ opcE9DiffPlaces.json OK ++ opcEADiffPlaces.json OK ++ opcEBDiffPlaces.json OK ++ opcECDiffPlaces.json OK ++ opcEDDiffPlaces.json OK ++ opcEEDiffPlaces.json OK ++ opcEFDiffPlaces.json OK ++ opcF6DiffPlaces.json OK ++ opcF7DiffPlaces.json OK ++ opcF8DiffPlaces.json OK ++ opcF9DiffPlaces.json OK ++ opcFBDiffPlaces.json OK ++ opcFCDiffPlaces.json OK ++ opcFEDiffPlaces.json OK ++ operationDiffGas.json OK + undefinedOpcodeFirstByte.json OK ``` -OK: 4/4 Fail: 0/4 Skip: 0/4 +OK: 121/121 Fail: 0/121 Skip: 0/121 ## stBugs ```diff + evmBytecode.json OK + randomStatetestDEFAULT-Tue_07_58_41-15153-575192.json OK ++ randomStatetestDEFAULT-Tue_07_58_41-15153-575192_london.json OK + returndatacopyPythonBug_Tue_03_48_41-1432.json OK + staticcall_createfails.json OK ``` -OK: 4/4 Fail: 0/4 Skip: 0/4 +OK: 5/5 Fail: 0/5 Skip: 0/5 ## stCallCodes ```diff + call_OOG_additionalGasCosts1.json OK @@ -757,6 +927,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 + CREATE2_Bounds2.json OK + CREATE2_Bounds3.json OK + CREATE2_ContractSuicideDuringInit_ThenStoreThenReturn.json OK ++ CREATE2_EOF1.json OK + CREATE2_FirstByte_loop.json OK + CREATE2_Suicide.json OK + Create2OOGafterInitCode.json OK @@ -801,7 +972,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 + returndatacopy_following_successful_create.json OK + returndatasize_following_successful_create.json OK ``` -OK: 47/47 Fail: 0/47 Skip: 0/47 +OK: 48/48 Fail: 0/48 Skip: 0/48 ## stCreateTest ```diff + CREATE_AcreateB_BSuicide_BStore.json OK @@ -815,6 +986,7 @@ OK: 47/47 Fail: 0/47 Skip: 0/47 + CREATE_EContractCreateNEContractInInitOOG_Tr.json OK + CREATE_EContractCreateNEContractInInit_Tr.json OK + CREATE_EContract_ThenCALLToNonExistentAcc.json OK ++ CREATE_EOF1.json OK + CREATE_EmptyContract.json OK + CREATE_EmptyContractAndCallIt_0wei.json OK + CREATE_EmptyContractAndCallIt_1wei.json OK @@ -838,8 +1010,9 @@ OK: 47/47 Fail: 0/47 Skip: 0/47 + TransactionCollisionToEmpty.json OK + TransactionCollisionToEmptyButCode.json OK + TransactionCollisionToEmptyButNonce.json OK ++ createFailResult.json OK ``` -OK: 34/34 Fail: 0/34 Skip: 0/34 +OK: 36/36 Fail: 0/36 Skip: 0/36 ## stDelegatecallTestHomestead ```diff + Call1024BalanceTooLow.json OK @@ -933,6 +1106,22 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + gasCostReturn.json OK ``` OK: 40/40 Fail: 0/40 Skip: 0/40 +## stEIP1559 +```diff ++ baseFeeDiffPlaces.json OK ++ gasPriceDiffPlaces.json OK ++ intrinsic.json OK ++ lowFeeCap.json OK ++ lowGasLimit.json OK ++ lowGasPriceOldTypes.json OK ++ outOfFunds.json OK ++ outOfFundsOldTypes.json OK ++ tipTooHigh.json OK ++ transactionIntinsicBug.json OK ++ typeTwoBerlin.json OK ++ valCausesOOF.json OK +``` +OK: 12/12 Fail: 0/12 Skip: 0/12 ## stEIP158Specific ```diff + CALL_OneVCallSuicide.json OK @@ -947,23 +1136,28 @@ OK: 7/7 Fail: 0/7 Skip: 0/7 ## stEIP2930 ```diff + addressOpcodes.json OK ++ coinbaseT01.json OK ++ coinbaseT2.json OK + manualCreate.json OK + storageCosts.json OK + transactionCosts.json OK + variedContext.json OK ``` -OK: 5/5 Fail: 0/5 Skip: 0/5 +OK: 7/7 Fail: 0/7 Skip: 0/7 ## stExample ```diff + accessListExample.json OK + add11.json OK + add11_yml.json OK ++ basefeeExample.json OK ++ eip1559.json OK ++ invalidTr.json OK + labelsExample.json OK + rangesExample.json OK + solidityExample.json OK + yulExample.json OK ``` -OK: 7/7 Fail: 0/7 Skip: 0/7 +OK: 10/10 Fail: 0/10 Skip: 0/10 ## stExtCodeHash ```diff + callToNonExistent.json OK @@ -1190,6 +1384,7 @@ OK: 38/38 Fail: 0/38 Skip: 0/38 + mem64kb_singleByte-32.json OK + mem64kb_singleByte-33.json OK + mem64kb_singleByte.json OK ++ memCopySelf.json OK + memReturn.json OK + mload16bitBound.json OK + mload8bitBound.json OK @@ -1208,7 +1403,7 @@ OK: 38/38 Fail: 0/38 Skip: 0/38 + stackLimitPush32_1024.json OK + stackLimitPush32_1025.json OK ``` -OK: 70/70 Fail: 0/70 Skip: 0/70 +OK: 71/71 Fail: 0/71 Skip: 0/71 ## stNonZeroCallsTest ```diff + NonZeroValue_CALL.json OK @@ -1243,102 +1438,11 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 + identity_to_bigger.json OK + identity_to_smaller.json OK + modexp.json OK -+ modexp_0_0_0_1000000.json OK -+ modexp_0_0_0_155000.json OK -+ modexp_0_1_0_1000000.json OK -+ modexp_0_1_0_155000.json OK -+ modexp_0_1_0_20500.json OK -+ modexp_0_1_0_22000.json OK -+ modexp_0_1_0_25000.json OK -+ modexp_0_1_0_35000.json OK -+ modexp_0_3_100_1000000.json OK -+ modexp_0_3_100_155000.json OK -+ modexp_0_3_100_20500.json OK -+ modexp_0_3_100_22000.json OK -+ modexp_0_3_100_25000.json OK -+ modexp_0_3_100_35000.json OK -+ modexp_1_0_0_1000000.json OK -+ modexp_1_0_0_155000.json OK -+ modexp_1_0_0_20500.json OK -+ modexp_1_0_0_22000.json OK -+ modexp_1_0_0_25000.json OK -+ modexp_1_0_0_35000.json OK -+ modexp_1_0_1_1000000.json OK -+ modexp_1_0_1_155000.json OK -+ modexp_1_0_1_20500.json OK -+ modexp_1_0_1_22000.json OK -+ modexp_1_0_1_25000.json OK -+ modexp_1_0_1_35000.json OK -+ modexp_1_1_1_1000000.json OK -+ modexp_1_1_1_155000.json OK -+ modexp_1_1_1_20500.json OK -+ modexp_1_1_1_22000.json OK -+ modexp_1_1_1_25000.json OK -+ modexp_1_1_1_35000.json OK -+ modexp_37120_22411_22000.json OK -+ modexp_37120_37111_0_1000000.json OK -+ modexp_37120_37111_0_155000.json OK -+ modexp_37120_37111_0_20500.json OK -+ modexp_37120_37111_0_22000.json OK -+ modexp_37120_37111_0_25000.json OK -+ modexp_37120_37111_0_35000.json OK -+ modexp_37120_37111_1_1000000.json OK -+ modexp_37120_37111_1_155000.json OK -+ modexp_37120_37111_1_20500.json OK -+ modexp_37120_37111_1_25000.json OK -+ modexp_37120_37111_1_35000.json OK -+ modexp_37120_37111_37111_1000000.json OK -+ modexp_37120_37111_37111_155000.json OK -+ modexp_37120_37111_37111_20500.json OK -+ modexp_37120_37111_37111_22000.json OK -+ modexp_37120_37111_37111_25000.json OK -+ modexp_37120_37111_37111_35000.json OK -+ modexp_37120_37111_97_1000000.json OK -+ modexp_37120_37111_97_155000.json OK -+ modexp_37120_37111_97_20500.json OK -+ modexp_37120_37111_97_22000.json OK -+ modexp_37120_37111_97_25000.json OK -+ modexp_37120_37111_97_35000.json OK -+ modexp_39936_1_55201_1000000.json OK -+ modexp_39936_1_55201_155000.json OK -+ modexp_39936_1_55201_20500.json OK -+ modexp_39936_1_55201_22000.json OK -+ modexp_39936_1_55201_25000.json OK -+ modexp_39936_1_55201_35000.json OK -+ modexp_3_09984_39936_1000000.json OK -+ modexp_3_09984_39936_155000.json OK -+ modexp_3_09984_39936_22000.json OK -+ modexp_3_09984_39936_25000.json OK -+ modexp_3_09984_39936_35000.json OK -+ modexp_3_28948_11579_20500.json OK -+ modexp_3_5_100_1000000.json OK -+ modexp_3_5_100_155000.json OK -+ modexp_3_5_100_20500.json OK -+ modexp_3_5_100_22000.json OK -+ modexp_3_5_100_25000.json OK -+ modexp_3_5_100_35000.json OK -+ modexp_49_2401_2401_1000000.json OK -+ modexp_49_2401_2401_155000.json OK -+ modexp_49_2401_2401_20500.json OK -+ modexp_49_2401_2401_22000.json OK -+ modexp_49_2401_2401_25000.json OK -+ modexp_49_2401_2401_35000.json OK -+ modexp_55190_55190_42965_1000000.json OK -+ modexp_55190_55190_42965_155000.json OK -+ modexp_55190_55190_42965_20500.json OK -+ modexp_55190_55190_42965_22000.json OK -+ modexp_55190_55190_42965_25000.json OK -+ modexp_55190_55190_42965_35000.json OK -+ modexp_9_37111_37111_1000000.json OK -+ modexp_9_37111_37111_155000.json OK -+ modexp_9_37111_37111_20500.json OK -+ modexp_9_37111_37111_22000.json OK -+ modexp_9_37111_37111_35000.json OK -+ modexp_9_3711_37111_25000.json OK ++ modexpTests.json OK + precompsEIP2929.json OK + sec80.json OK ``` -OK: 98/98 Fail: 0/98 Skip: 0/98 +OK: 7/7 Fail: 0/7 Skip: 0/7 ## stPreCompiledContracts2 ```diff + CALLBlake2f.json OK @@ -2020,6 +2124,9 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + refund50_2.json OK + refund50percentCap.json OK + refund600.json OK ++ refundFF.json OK ++ refundMax.json OK ++ refundSSTORE.json OK + refundSuicide50procentCap.json OK + refund_CallA.json OK + refund_CallA_OOG.json OK @@ -2036,7 +2143,7 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + refund_multimpleSuicide.json OK + refund_singleSuicide.json OK ``` -OK: 19/19 Fail: 0/19 Skip: 0/19 +OK: 22/22 Fail: 0/22 Skip: 0/22 ## stReturnDataTest ```diff + call_ecrec_success_empty_then_returndatasize.json OK @@ -2140,6 +2247,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + InitCollision.json OK + InitCollisionNonZeroNonce.json OK + SstoreCallToSelfSubRefundBelowZero.json OK ++ sstoreGas.json OK + sstore_0to0.json OK + sstore_0to0to0.json OK + sstore_0to0toX.json OK @@ -2165,16 +2273,17 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + sstore_changeFromExternalCallInInitCode.json OK + sstore_gasLeft.json OK ``` -OK: 27/27 Fail: 0/27 Skip: 0/27 +OK: 28/28 Fail: 0/28 Skip: 0/28 ## stSelfBalance ```diff ++ diffPlaces.json OK + selfBalance.json OK + selfBalanceCallTypes.json OK + selfBalanceEqualsBalance.json OK + selfBalanceGasCost.json OK + selfBalanceUpdate.json OK ``` -OK: 5/5 Fail: 0/5 Skip: 0/5 +OK: 6/6 Fail: 0/6 Skip: 0/6 ## stShift ```diff + sar00.json OK @@ -2675,6 +2784,7 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + ContractStoreClearsSuccess.json OK + CreateMessageReverted.json OK + CreateMessageSuccess.json OK ++ CreateTransactionEOF1.json OK + CreateTransactionSuccess.json OK + EmptyTransaction3.json OK + HighGasLimit.json OK @@ -2700,7 +2810,7 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + TransactionToAddressh160minusOne.json OK + TransactionToItself.json OK ``` -OK: 28/28 Fail: 0/28 Skip: 0/28 +OK: 29/29 Fail: 0/29 Skip: 0/29 ## stTransitionTest ```diff + createNameRegistratorPerTxsAfter.json OK @@ -3165,4 +3275,4 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 OK: 11/11 Fail: 0/11 Skip: 0/11 ---TOTAL--- -OK: 2843/2843 Fail: 0/2843 Skip: 0/2843 +OK: 2937/2937 Fail: 0/2937 Skip: 0/2937 diff --git a/witnessBuilderGST.md b/witnessBuilderGST.md index f9e9d65d3..2b1b95051 100644 --- a/witnessBuilderGST.md +++ b/witnessBuilderGST.md @@ -61,17 +61,135 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + badOpcodes.json OK + eip2315NotRemoved.json OK + invalidAddr.json OK ++ invalidDiffPlaces.json OK ++ measureGas.json OK ++ opc0CDiffPlaces.json OK ++ opc0DDiffPlaces.json OK ++ opc0EDiffPlaces.json OK ++ opc0FDiffPlaces.json OK ++ opc1EDiffPlaces.json OK ++ opc1FDiffPlaces.json OK ++ opc21DiffPlaces.json OK ++ opc22DiffPlaces.json OK ++ opc23DiffPlaces.json OK ++ opc24DiffPlaces.json OK ++ opc25DiffPlaces.json OK ++ opc26DiffPlaces.json OK ++ opc27DiffPlaces.json OK ++ opc28DiffPlaces.json OK ++ opc29DiffPlaces.json OK ++ opc2ADiffPlaces.json OK ++ opc2BDiffPlaces.json OK ++ opc2CDiffPlaces.json OK ++ opc2DDiffPlaces.json OK ++ opc2EDiffPlaces.json OK ++ opc2FDiffPlaces.json OK ++ opc49DiffPlaces.json OK ++ opc4ADiffPlaces.json OK ++ opc4BDiffPlaces.json OK ++ opc4CDiffPlaces.json OK ++ opc4DDiffPlaces.json OK ++ opc4EDiffPlaces.json OK ++ opc4FDiffPlaces.json OK ++ opc5CDiffPlaces.json OK ++ opc5DDiffPlaces.json OK ++ opc5EDiffPlaces.json OK ++ opc5FDiffPlaces.json OK ++ opcA5DiffPlaces.json OK ++ opcA6DiffPlaces.json OK ++ opcA7DiffPlaces.json OK ++ opcA8DiffPlaces.json OK ++ opcA9DiffPlaces.json OK ++ opcAADiffPlaces.json OK ++ opcABDiffPlaces.json OK ++ opcACDiffPlaces.json OK ++ opcADDiffPlaces.json OK ++ opcAEDiffPlaces.json OK ++ opcAFDiffPlaces.json OK ++ opcB0DiffPlaces.json OK ++ opcB1DiffPlaces.json OK ++ opcB2DiffPlaces.json OK ++ opcB3DiffPlaces.json OK ++ opcB4DiffPlaces.json OK ++ opcB5DiffPlaces.json OK ++ opcB6DiffPlaces.json OK ++ opcB7DiffPlaces.json OK ++ opcB8DiffPlaces.json OK ++ opcB9DiffPlaces.json OK ++ opcBADiffPlaces.json OK ++ opcBBDiffPlaces.json OK ++ opcBCDiffPlaces.json OK ++ opcBDDiffPlaces.json OK ++ opcBEDiffPlaces.json OK ++ opcBFDiffPlaces.json OK ++ opcC0DiffPlaces.json OK ++ opcC1DiffPlaces.json OK ++ opcC2DiffPlaces.json OK ++ opcC3DiffPlaces.json OK ++ opcC4DiffPlaces.json OK ++ opcC5DiffPlaces.json OK ++ opcC6DiffPlaces.json OK ++ opcC7DiffPlaces.json OK ++ opcC8DiffPlaces.json OK ++ opcC9DiffPlaces.json OK ++ opcCADiffPlaces.json OK ++ opcCBDiffPlaces.json OK ++ opcCCDiffPlaces.json OK ++ opcCDDiffPlaces.json OK ++ opcCEDiffPlaces.json OK ++ opcCFDiffPlaces.json OK ++ opcD0DiffPlaces.json OK ++ opcD1DiffPlaces.json OK ++ opcD2DiffPlaces.json OK ++ opcD3DiffPlaces.json OK ++ opcD4DiffPlaces.json OK ++ opcD5DiffPlaces.json OK ++ opcD6DiffPlaces.json OK ++ opcD7DiffPlaces.json OK ++ opcD8DiffPlaces.json OK ++ opcD9DiffPlaces.json OK ++ opcDADiffPlaces.json OK ++ opcDBDiffPlaces.json OK ++ opcDCDiffPlaces.json OK ++ opcDDDiffPlaces.json OK ++ opcDEDiffPlaces.json OK ++ opcDFDiffPlaces.json OK ++ opcE0DiffPlaces.json OK ++ opcE1DiffPlaces.json OK ++ opcE2DiffPlaces.json OK ++ opcE3DiffPlaces.json OK ++ opcE4DiffPlaces.json OK ++ opcE5DiffPlaces.json OK ++ opcE6DiffPlaces.json OK ++ opcE7DiffPlaces.json OK ++ opcE8DiffPlaces.json OK ++ opcE9DiffPlaces.json OK ++ opcEADiffPlaces.json OK ++ opcEBDiffPlaces.json OK ++ opcECDiffPlaces.json OK ++ opcEDDiffPlaces.json OK ++ opcEEDiffPlaces.json OK ++ opcEFDiffPlaces.json OK ++ opcF6DiffPlaces.json OK ++ opcF7DiffPlaces.json OK ++ opcF8DiffPlaces.json OK ++ opcF9DiffPlaces.json OK ++ opcFBDiffPlaces.json OK ++ opcFCDiffPlaces.json OK ++ opcFEDiffPlaces.json OK ++ operationDiffGas.json OK + undefinedOpcodeFirstByte.json OK ``` -OK: 4/4 Fail: 0/4 Skip: 0/4 +OK: 121/121 Fail: 0/121 Skip: 0/121 ## stBugs ```diff + evmBytecode.json OK + randomStatetestDEFAULT-Tue_07_58_41-15153-575192.json OK ++ randomStatetestDEFAULT-Tue_07_58_41-15153-575192_london.json OK + returndatacopyPythonBug_Tue_03_48_41-1432.json OK + staticcall_createfails.json OK ``` -OK: 4/4 Fail: 0/4 Skip: 0/4 +OK: 5/5 Fail: 0/5 Skip: 0/5 ## stCallCodes ```diff + call_OOG_additionalGasCosts1.json OK @@ -351,6 +469,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 + CREATE2_Bounds2.json OK + CREATE2_Bounds3.json OK + CREATE2_ContractSuicideDuringInit_ThenStoreThenReturn.json OK ++ CREATE2_EOF1.json OK + CREATE2_FirstByte_loop.json OK + CREATE2_Suicide.json OK + Create2OOGafterInitCode.json OK @@ -395,7 +514,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 + returndatacopy_following_successful_create.json OK + returndatasize_following_successful_create.json OK ``` -OK: 47/47 Fail: 0/47 Skip: 0/47 +OK: 48/48 Fail: 0/48 Skip: 0/48 ## stCreateTest ```diff + CREATE_AcreateB_BSuicide_BStore.json OK @@ -409,6 +528,7 @@ OK: 47/47 Fail: 0/47 Skip: 0/47 + CREATE_EContractCreateNEContractInInitOOG_Tr.json OK + CREATE_EContractCreateNEContractInInit_Tr.json OK + CREATE_EContract_ThenCALLToNonExistentAcc.json OK ++ CREATE_EOF1.json OK + CREATE_EmptyContract.json OK + CREATE_EmptyContractAndCallIt_0wei.json OK + CREATE_EmptyContractAndCallIt_1wei.json OK @@ -432,8 +552,9 @@ OK: 47/47 Fail: 0/47 Skip: 0/47 + TransactionCollisionToEmpty.json OK + TransactionCollisionToEmptyButCode.json OK + TransactionCollisionToEmptyButNonce.json OK ++ createFailResult.json OK ``` -OK: 34/34 Fail: 0/34 Skip: 0/34 +OK: 36/36 Fail: 0/36 Skip: 0/36 ## stDelegatecallTestHomestead ```diff + Call1024BalanceTooLow.json OK @@ -527,6 +648,22 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + gasCostReturn.json OK ``` OK: 40/40 Fail: 0/40 Skip: 0/40 +## stEIP1559 +```diff ++ baseFeeDiffPlaces.json OK ++ gasPriceDiffPlaces.json OK ++ intrinsic.json OK ++ lowFeeCap.json OK ++ lowGasLimit.json OK ++ lowGasPriceOldTypes.json OK ++ outOfFunds.json OK ++ outOfFundsOldTypes.json OK ++ tipTooHigh.json OK ++ transactionIntinsicBug.json OK ++ typeTwoBerlin.json OK ++ valCausesOOF.json OK +``` +OK: 12/12 Fail: 0/12 Skip: 0/12 ## stEIP158Specific ```diff + CALL_OneVCallSuicide.json OK @@ -541,23 +678,28 @@ OK: 7/7 Fail: 0/7 Skip: 0/7 ## stEIP2930 ```diff + addressOpcodes.json OK ++ coinbaseT01.json OK ++ coinbaseT2.json OK + manualCreate.json OK + storageCosts.json OK + transactionCosts.json OK + variedContext.json OK ``` -OK: 5/5 Fail: 0/5 Skip: 0/5 +OK: 7/7 Fail: 0/7 Skip: 0/7 ## stExample ```diff + accessListExample.json OK + add11.json OK + add11_yml.json OK ++ basefeeExample.json OK ++ eip1559.json OK ++ invalidTr.json OK + labelsExample.json OK + rangesExample.json OK + solidityExample.json OK + yulExample.json OK ``` -OK: 7/7 Fail: 0/7 Skip: 0/7 +OK: 10/10 Fail: 0/10 Skip: 0/10 ## stExtCodeHash ```diff + callToNonExistent.json OK @@ -784,6 +926,7 @@ OK: 38/38 Fail: 0/38 Skip: 0/38 + mem64kb_singleByte-32.json OK + mem64kb_singleByte-33.json OK + mem64kb_singleByte.json OK ++ memCopySelf.json OK + memReturn.json OK + mload16bitBound.json OK + mload8bitBound.json OK @@ -802,7 +945,7 @@ OK: 38/38 Fail: 0/38 Skip: 0/38 + stackLimitPush32_1024.json OK + stackLimitPush32_1025.json OK ``` -OK: 70/70 Fail: 0/70 Skip: 0/70 +OK: 71/71 Fail: 0/71 Skip: 0/71 ## stNonZeroCallsTest ```diff + NonZeroValue_CALL.json OK @@ -837,102 +980,11 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 + identity_to_bigger.json OK + identity_to_smaller.json OK + modexp.json OK -+ modexp_0_0_0_1000000.json OK -+ modexp_0_0_0_155000.json OK -+ modexp_0_1_0_1000000.json OK -+ modexp_0_1_0_155000.json OK -+ modexp_0_1_0_20500.json OK -+ modexp_0_1_0_22000.json OK -+ modexp_0_1_0_25000.json OK -+ modexp_0_1_0_35000.json OK -+ modexp_0_3_100_1000000.json OK -+ modexp_0_3_100_155000.json OK -+ modexp_0_3_100_20500.json OK -+ modexp_0_3_100_22000.json OK -+ modexp_0_3_100_25000.json OK -+ modexp_0_3_100_35000.json OK -+ modexp_1_0_0_1000000.json OK -+ modexp_1_0_0_155000.json OK -+ modexp_1_0_0_20500.json OK -+ modexp_1_0_0_22000.json OK -+ modexp_1_0_0_25000.json OK -+ modexp_1_0_0_35000.json OK -+ modexp_1_0_1_1000000.json OK -+ modexp_1_0_1_155000.json OK -+ modexp_1_0_1_20500.json OK -+ modexp_1_0_1_22000.json OK -+ modexp_1_0_1_25000.json OK -+ modexp_1_0_1_35000.json OK -+ modexp_1_1_1_1000000.json OK -+ modexp_1_1_1_155000.json OK -+ modexp_1_1_1_20500.json OK -+ modexp_1_1_1_22000.json OK -+ modexp_1_1_1_25000.json OK -+ modexp_1_1_1_35000.json OK -+ modexp_37120_22411_22000.json OK -+ modexp_37120_37111_0_1000000.json OK -+ modexp_37120_37111_0_155000.json OK -+ modexp_37120_37111_0_20500.json OK -+ modexp_37120_37111_0_22000.json OK -+ modexp_37120_37111_0_25000.json OK -+ modexp_37120_37111_0_35000.json OK -+ modexp_37120_37111_1_1000000.json OK -+ modexp_37120_37111_1_155000.json OK -+ modexp_37120_37111_1_20500.json OK -+ modexp_37120_37111_1_25000.json OK -+ modexp_37120_37111_1_35000.json OK -+ modexp_37120_37111_37111_1000000.json OK -+ modexp_37120_37111_37111_155000.json OK -+ modexp_37120_37111_37111_20500.json OK -+ modexp_37120_37111_37111_22000.json OK -+ modexp_37120_37111_37111_25000.json OK -+ modexp_37120_37111_37111_35000.json OK -+ modexp_37120_37111_97_1000000.json OK -+ modexp_37120_37111_97_155000.json OK -+ modexp_37120_37111_97_20500.json OK -+ modexp_37120_37111_97_22000.json OK -+ modexp_37120_37111_97_25000.json OK -+ modexp_37120_37111_97_35000.json OK -+ modexp_39936_1_55201_1000000.json OK -+ modexp_39936_1_55201_155000.json OK -+ modexp_39936_1_55201_20500.json OK -+ modexp_39936_1_55201_22000.json OK -+ modexp_39936_1_55201_25000.json OK -+ modexp_39936_1_55201_35000.json OK -+ modexp_3_09984_39936_1000000.json OK -+ modexp_3_09984_39936_155000.json OK -+ modexp_3_09984_39936_22000.json OK -+ modexp_3_09984_39936_25000.json OK -+ modexp_3_09984_39936_35000.json OK -+ modexp_3_28948_11579_20500.json OK -+ modexp_3_5_100_1000000.json OK -+ modexp_3_5_100_155000.json OK -+ modexp_3_5_100_20500.json OK -+ modexp_3_5_100_22000.json OK -+ modexp_3_5_100_25000.json OK -+ modexp_3_5_100_35000.json OK -+ modexp_49_2401_2401_1000000.json OK -+ modexp_49_2401_2401_155000.json OK -+ modexp_49_2401_2401_20500.json OK -+ modexp_49_2401_2401_22000.json OK -+ modexp_49_2401_2401_25000.json OK -+ modexp_49_2401_2401_35000.json OK -+ modexp_55190_55190_42965_1000000.json OK -+ modexp_55190_55190_42965_155000.json OK -+ modexp_55190_55190_42965_20500.json OK -+ modexp_55190_55190_42965_22000.json OK -+ modexp_55190_55190_42965_25000.json OK -+ modexp_55190_55190_42965_35000.json OK -+ modexp_9_37111_37111_1000000.json OK -+ modexp_9_37111_37111_155000.json OK -+ modexp_9_37111_37111_20500.json OK -+ modexp_9_37111_37111_22000.json OK -+ modexp_9_37111_37111_35000.json OK -+ modexp_9_3711_37111_25000.json OK ++ modexpTests.json OK + precompsEIP2929.json OK + sec80.json OK ``` -OK: 98/98 Fail: 0/98 Skip: 0/98 +OK: 7/7 Fail: 0/7 Skip: 0/7 ## stPreCompiledContracts2 ```diff + CALLBlake2f.json OK @@ -1614,6 +1666,9 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + refund50_2.json OK + refund50percentCap.json OK + refund600.json OK ++ refundFF.json OK ++ refundMax.json OK ++ refundSSTORE.json OK + refundSuicide50procentCap.json OK + refund_CallA.json OK + refund_CallA_OOG.json OK @@ -1630,7 +1685,7 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 + refund_multimpleSuicide.json OK + refund_singleSuicide.json OK ``` -OK: 19/19 Fail: 0/19 Skip: 0/19 +OK: 22/22 Fail: 0/22 Skip: 0/22 ## stReturnDataTest ```diff + call_ecrec_success_empty_then_returndatasize.json OK @@ -1734,6 +1789,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + InitCollision.json OK + InitCollisionNonZeroNonce.json OK + SstoreCallToSelfSubRefundBelowZero.json OK ++ sstoreGas.json OK + sstore_0to0.json OK + sstore_0to0to0.json OK + sstore_0to0toX.json OK @@ -1759,16 +1815,17 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + sstore_changeFromExternalCallInInitCode.json OK + sstore_gasLeft.json OK ``` -OK: 27/27 Fail: 0/27 Skip: 0/27 +OK: 28/28 Fail: 0/28 Skip: 0/28 ## stSelfBalance ```diff ++ diffPlaces.json OK + selfBalance.json OK + selfBalanceCallTypes.json OK + selfBalanceEqualsBalance.json OK + selfBalanceGasCost.json OK + selfBalanceUpdate.json OK ``` -OK: 5/5 Fail: 0/5 Skip: 0/5 +OK: 6/6 Fail: 0/6 Skip: 0/6 ## stShift ```diff + sar00.json OK @@ -2269,6 +2326,7 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + ContractStoreClearsSuccess.json OK + CreateMessageReverted.json OK + CreateMessageSuccess.json OK ++ CreateTransactionEOF1.json OK + CreateTransactionSuccess.json OK + EmptyTransaction3.json OK + HighGasLimit.json OK @@ -2294,7 +2352,7 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + TransactionToAddressh160minusOne.json OK + TransactionToItself.json OK ``` -OK: 28/28 Fail: 0/28 Skip: 0/28 +OK: 29/29 Fail: 0/29 Skip: 0/29 ## stTransitionTest ```diff + createNameRegistratorPerTxsAfter.json OK @@ -2759,4 +2817,4 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 OK: 11/11 Fail: 0/11 Skip: 0/11 ---TOTAL--- -OK: 2517/2517 Fail: 0/2517 Skip: 0/2517 +OK: 2571/2571 Fail: 0/2571 Skip: 0/2571