diff --git a/pyevmasm/__main__.py b/pyevmasm/__main__.py index ebc8dc5..c8ffe74 100755 --- a/pyevmasm/__main__.py +++ b/pyevmasm/__main__.py @@ -64,8 +64,8 @@ def main(): "--fork", default=DEFAULT_FORK, type=str, - help="Fork, default: london. " - "Possible: frontier, homestead, tangerine_whistle, spurious_dragon, byzantium, constantinople, istanbul, london, serenity. " + help="Fork, default: cancun. " + "Possible: frontier, homestead, tangerine_whistle, spurious_dragon, byzantium, constantinople, istanbul, london, shanghai, cancun, serenity. " "Also an unsigned block number is accepted to select the fork.", ) diff --git a/pyevmasm/evmasm.py b/pyevmasm/evmasm.py index 668b4ba..816ed6d 100644 --- a/pyevmasm/evmasm.py +++ b/pyevmasm/evmasm.py @@ -5,7 +5,7 @@ from future.builtins import next, bytes # type: ignore import copy -DEFAULT_FORK = "shanghai" +DEFAULT_FORK = "cancun" """ Example use:: @@ -299,6 +299,7 @@ def writes_to_stack(self): def writes_to_memory(self): """True if the instruction writes to memory""" return self.semantics in { + "MCOPY", "MSTORE", "MSTORE8", "CALLDATACOPY", @@ -316,6 +317,7 @@ def reads_from_memory(self): """True if the instruction reads from memory""" return self.semantics in { "SHA3", + "MCOPY", "MLOAD", "CREATE", "CALL", @@ -336,6 +338,16 @@ def reads_from_storage(self): """True if the instruction reads from the storage""" return self.semantics == "SLOAD" + @property + def writes_to_transient_storage(self): + """True if the instruction writes to the transient storage""" + return self.semantics == "TSTORE" + + @property + def reads_from_transient_storage(self): + """True if the instruction reads from the transient storage""" + return self.semantics == "TLOAD" + @property def is_terminator(self): """True if the instruction is a basic block terminator""" @@ -1101,6 +1113,25 @@ def __repr__(self): shanghai_instruction_table, previous_fork=london_instruction_table ) +cancun_instruction_table = { + 0x49: ("BLOBHASH", 0, 1, 1, 3, "Get versioned hashes"), + 0x4A: ( + "BLOBBASEFEE", + 0, + 0, + 1, + 2, + "Returns the value of the blob base-fee of the current block", + ), + 0x5C: ("TLOAD", 0, 1, 1, 100, "Load word from transient storage"), + 0x5D: ("TSTORE", 0, 2, 0, 100, "Save word to transient storage"), + 0x5E: ("MCOPY", 0, 3, 0, 3, "Copy memory areas"), +} + +cancun_instruction_table = InstructionTable( # type: ignore + cancun_instruction_table, previous_fork=shanghai_instruction_table +) + accepted_forks = ( "frontier", "homestead", @@ -1112,7 +1143,8 @@ def __repr__(self): "serenity", "istanbul", "london", - "shanghai" + "shanghai", + "cancun", ) @@ -1128,6 +1160,7 @@ def __repr__(self): "istanbul": istanbul_instruction_table, "london": london_instruction_table, "shanghai": shanghai_instruction_table, + "cancun": cancun_instruction_table, } @@ -1163,6 +1196,7 @@ def block_to_fork(block_number): 9069000: "istanbul", 12965000: "london", 17034870: "shanghai", + 19426587: "cancun", 99999999: "serenity", # to be replaced after Serenity launch } fork_names = list(forks_by_block.values()) diff --git a/tests/test_EVMAssembler.py b/tests/test_EVMAssembler.py index 1a44b68..43ab08a 100644 --- a/tests/test_EVMAssembler.py +++ b/tests/test_EVMAssembler.py @@ -136,6 +136,33 @@ def test_shanghai_fork(self): self.assertTrue(insn.pushes == 1) self.assertTrue(insn.operand_size == 0) + def test_cancun_fork(self): + insn = EVMAsm.disassemble_one(b"\x49", fork="cancun") + self.assertTrue(insn.mnemonic == "BLOBHASH") + self.assertTrue(insn.fee == 3) + self.assertTrue(insn.pops == 1) + self.assertTrue(insn.pushes == 1) + insn = EVMAsm.disassemble_one(b"\x4a", fork="cancun") + self.assertTrue(insn.mnemonic == "BLOBBASEFEE") + self.assertTrue(insn.fee == 2) + self.assertTrue(insn.pops == 0) + self.assertTrue(insn.pushes == 1) + insn = EVMAsm.disassemble_one(b"\x5c", fork="cancun") + self.assertTrue(insn.mnemonic == "TLOAD") + self.assertTrue(insn.fee == 100) + self.assertTrue(insn.pops == 1) + self.assertTrue(insn.pushes == 1) + insn = EVMAsm.disassemble_one(b"\x5d", fork="cancun") + self.assertTrue(insn.mnemonic == "TSTORE") + self.assertTrue(insn.fee == 100) + self.assertTrue(insn.pops == 2) + self.assertTrue(insn.pushes == 0) + insn = EVMAsm.disassemble_one(b"\x5e", fork="cancun") + self.assertTrue(insn.mnemonic == "MCOPY") + self.assertTrue(insn.fee == 3) + self.assertTrue(insn.pops == 3) + self.assertTrue(insn.pushes == 0) + def test_assemble_DUP1_regression(self): insn = EVMAsm.assemble_one("DUP1") self.assertEqual(insn.mnemonic, "DUP1")