diff --git a/nimbus/evm/code_bytes.nim b/nimbus/evm/code_bytes.nim index 78cb2659e..46ba0e38e 100644 --- a/nimbus/evm/code_bytes.nim +++ b/nimbus/evm/code_bytes.nim @@ -64,7 +64,7 @@ func isValidOpcode*(c: CodeBytesRef, position: int): bool = var opcode = Op(c.bytes[i]) if opcode >= Op.Push1 and opcode <= Op.Push32: var leftBound = (i + 1) - var rightBound = leftBound + (opcode.int - 95) + var rightBound = min(leftBound + (opcode.int - 95), c.bytes.len) for z in leftBound ..< rightBound: let (bpos, bbit) = bitpos(z) c.invalidPositions[bpos] = c.invalidPositions[bpos] or bbit diff --git a/nimbus/evm/code_stream.nim b/nimbus/evm/code_stream.nim index b5476997a..f0553af20 100644 --- a/nimbus/evm/code_stream.nim +++ b/nimbus/evm/code_stream.nim @@ -6,7 +6,11 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - std/[sequtils, strutils], chronicles, eth/common, ./interpreter/op_codes, ./code_bytes + chronicles, + eth/common, + stew/byteutils, + ./interpreter/op_codes, + ./code_bytes export code_bytes @@ -80,24 +84,23 @@ func isValidOpcode*(c: CodeStream, position: int): bool = func bytes*(c: CodeStream): lent seq[byte] = c.code.bytes() +func atEnd*(c: CodeStream): bool = + c.pc >= c.code.bytes.len + proc decompile*(original: CodeStream): seq[(int, Op, string)] = # behave as https://etherscan.io/opcode-tool var c = CodeStream.init(original.bytes) - while true: + while not c.atEnd: var op = c.next if op >= Push1 and op <= Push32: result.add( ( c.pc - 1, op, - "0x" & c.read(op.int - 95).mapIt($(it.BiggestInt.toHex(2))).join(""), + "0x" & c.read(op.int - 95).toHex, ) ) elif op != Op.Stop: result.add((c.pc - 1, op, "")) else: result.add((-1, Op.Stop, "")) - break - -func atEnd*(c: CodeStream): bool = - c.pc >= c.code.bytes.len diff --git a/tests/test_op_memory.nim b/tests/test_op_memory.nim index 7475955e8..692a94056 100644 --- a/tests/test_op_memory.nim +++ b/tests/test_op_memory.nim @@ -953,5 +953,14 @@ proc opMemoryMain*() = success: false fork: Cancun + assembler: + title: "Code bytes: invalidPositions out of bound crash issue #2522" + code: + Push1 "0x01" # 0: ok to jump + Push1 "0x06" # 2: jump to pc 6 + JumpI # 4 + "0x695b00" # 5: PUSH10 First byte is jumpDestOp but operand is too short + success: false + when isMainModule: opMemoryMain() diff --git a/tools/evmstate/evmstate.nim b/tools/evmstate/evmstate.nim index 32afd7f59..3428558bb 100644 --- a/tools/evmstate/evmstate.nim +++ b/tools/evmstate/evmstate.nim @@ -67,9 +67,8 @@ proc toBytes(x: string): seq[byte] = method getAncestorHash(vmState: TestVMState; blockNumber: BlockNumber): Hash256 = keccakHash(toBytes($blockNumber)) -proc verifyResult(ctx: var StateContext, vmState: BaseVMState) = - ctx.error = "" - let obtainedHash = vmState.readOnlyStateDB.rootHash +proc verifyResult(ctx: var StateContext, vmState: BaseVMState, obtainedHash: Hash256) = + ctx.error = "" if obtainedHash != ctx.expectedHash: ctx.error = "post state root mismatch: got $1, want $2" % [($obtainedHash).toLowerAscii, $ctx.expectedHash] @@ -99,31 +98,9 @@ proc writeResultToStdout(stateRes: seq[StateResult]) = stdout.write(n.pretty) stdout.write("\n") -when false: - proc dumpAccounts(db: LedgerRef): Table[EthAddress, DumpAccount] = - for accAddr in db.addresses(): - let acc = DumpAccount( - balance : db.getBalance(accAddr), - nonce : db.getNonce(accAddr), - root : db.getStorageRoot(accAddr), - codeHash: db.getCodeHash(accAddr), - code : db.getCode(accAddr), - key : keccakHash(accAddr) - ) - for k, v in db.storage(accAddr): - acc.storage[k] = v - result[accAddr] = acc - - - proc dumpState(vmState: BaseVMState): StateDump = - StateDump( - root: vmState.readOnlyStateDB.rootHash, - accounts: dumpAccounts(vmState.stateDB) - ) - -proc writeRootHashToStderr(vmState: BaseVMState) = +proc writeRootHashToStderr(stateRoot: Hash256) = let stateRoot = %{ - "stateRoot": %(vmState.readOnlyStateDB.rootHash) + "stateRoot": %(stateRoot) } stderr.writeLine($stateRoot) @@ -159,18 +136,19 @@ proc runExecution(ctx: var StateContext, conf: StateConf, pre: JsonNode): StateR db.persist(clearEmptyAccount = false) # settle accounts storage defer: - ctx.verifyResult(vmState) + let stateRoot = vmState.readOnlyStateDB.rootHash + ctx.verifyResult(vmState, stateRoot) result = StateResult( name : ctx.name, pass : ctx.error.len == 0, - root : vmState.readOnlyStateDB.rootHash, + root : stateRoot, fork : ctx.forkStr, error: ctx.error ) if conf.dumpEnabled: result.state = dumpState(vmState.stateDB) if conf.jsonEnabled: - writeRootHashToStderr(vmState) + writeRootHashToStderr(stateRoot) try: let rc = vmState.processTransaction( diff --git a/tools/evmstate/testdata/01400578-mixed-11.json b/tools/evmstate/testdata/01400578-mixed-11.json new file mode 100644 index 000000000..82c5e4432 --- /dev/null +++ b/tools/evmstate/testdata/01400578-mixed-11.json @@ -0,0 +1,58 @@ +{ + "01400578-mixed-11": { + "env": { + "currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": "0x200000", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000200000", + "currentGasLimit": "0x26e1f476fe1e22", + "currentNumber": "0x1", + "currentTimestamp": "0x3e8", + "previousHash": "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "currentBaseFee": "0x10" + }, + "pre": { + "0x00000000000000000000000000000000000000f1": { + "code": "0x605e607f6084600c60f760da603f4257527a7f995050406839323e027077853c6a3330146282387532923e0993618743475b10018e09179e66407c48198ef5349e8e898183740080781d5b308a1189473617771660588c96639c4610643d17741b117734429e81198f5307737981fda26448436303577d312020015a0a9e035a75865576869d895774736dfd656e518e895643346b4392325697483f39637c699d93868b32035562419459550b5a416b647510455134fe47823a085369737f6d6e88387e8d055686771478fd3877351868a082656199857940605411351a09050b123b37517c9e74504376848814727c04483f361b6a61396c7a7f010b72338e358b5b348b8542118d148d7266f21578a033475a523e717f8d31a3fda01257a1898d6f82401b583b514883368c5b62845044107c5a6e637f09868a818564203f14086e6085168832906d0896793c113e973d3348020594718385533082029a8b65026e4858391a901a557c5783081aa358f339147c85029a3240f30b77029d91f13e6f179c31784704606f07524486159452060656ff4515500a7d8a8d3f98768a3e68053b91628d1d38036907587d585b9c32601c6d3b40076efd39168b931c151b6e73041b930a7640764568794030070881548b86101000ff30567884045504468a1d6e2016098e2008141877831c3b3d7556815983917a061242186c98739a087d01603ffe03689d805b064492a11212039b40146d67200902fd44088f94867a916a008079a4366e31601890f3153f6c0a611d023177783e19f53f408509885064a159046388863e82173a599c095b9864449456305030518ea341691ba37f7442f1038ef206578a3d860b67959d18879e8d8418596e70899b016c817310ff42307c3006788c3f32546f6e63364320593e3c356814677492117d653b61933c8b45a06677105b0a541c99115856983774037c801553a0806f423b508f1c3368716809557c3676105143617e6207606f07897b634833203c17609f7467823042763f1431005267705417836c8f951b458b3d50806b806d141530830611a372511575636260613082ff185180597a8054f346811201733b771d898f07745734816bfd1b41411d0964575b110405204472075b6d5b7955a11084f0a460849e3b371c81695b9a3e30607866f19b097d5954651a595257446010840402578643351a15778c84f35231090b9544f035155242593d7e04a3327462417c9d7271849f64643843156d04f5811c620987350b50596c7f947b38778f3d431482856f97809d068d46658d31468b887e350a7a7815966984437432343a6a6803080645f272581690013e7d1132734167761807711dfa8d9d563c388b8246684174f487404170369d44387e47925b886f3c380b131d10fe1af06e4873123634a2007d93656b", + "storage": {}, + "balance": "0x0", + "nonce": "0x0" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "code": "0x", + "storage": {}, + "balance": "0xffffffffff", + "nonce": "0x0" + } + }, + "transaction": { + "gasPrice": "0x10", + "nonce": "0x0", + "to": "0x00000000000000000000000000000000000000f1", + "data": [ + "0xa789e12ba04bb2" + ], + "gasLimit": [ + "0x5299" + ], + "value": [ + "0x" + ], + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + "out": "0x", + "post": { + "Merge": [ + { + "hash": "0xb2cde3c1decab7a146fe0442ed7a8f16e1b044dab737d1196b107c769f86e034", + "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "indexes": { + "data": 0, + "gas": 0, + "value": 0 + } + } + ] + } + } +}