diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/BasefeeDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/BasefeeDslTest.java new file mode 100644 index 00000000000..bb52b96c9ef --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/BasefeeDslTest.java @@ -0,0 +1,179 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ +package co.rsk.vm.opcode; + +import co.rsk.config.TestSystemProperties; +import co.rsk.test.World; +import co.rsk.test.dsl.DslParser; +import co.rsk.test.dsl.DslProcessorException; +import co.rsk.test.dsl.WorldDslProcessor; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.core.TransactionReceipt; +import org.ethereum.core.util.TransactionReceiptUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.FileNotFoundException; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +public class BasefeeDslTest { + + @Test + void testBASEFEE_whenActivated_behavesAsExpected() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/opcode/basefee/baseFeeActivatedTest.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + // Assertions + + // There's one block (b01) containing only 1 transaction + Block block1 = world.getBlockByName("b01"); + Assertions.assertNotNull(block1); + Assertions.assertEquals(1, block1.getTransactionsList().size()); + + // There's a transaction called txTestBasefee + Transaction txTestBasefee = world.getTransactionByName("txTestBasefee"); + Assertions.assertNotNull(txTestBasefee); + + // Transaction txTestBasefee has a transaction receipt + TransactionReceipt txTestBasefeeReceipt = world.getTransactionReceiptByName("txTestBasefee"); + Assertions.assertNotNull(txTestBasefeeReceipt); + + // Transaction txTestBasefee has been processed correctly + byte[] creationStatus = txTestBasefeeReceipt.getStatus(); + Assertions.assertNotNull(creationStatus); + Assertions.assertEquals(1, creationStatus.length); + Assertions.assertEquals(1, creationStatus[0]); + + // There's one block (b02) containing only 1 transaction + Block block2 = world.getBlockByName("b02"); + Assertions.assertNotNull(block2); + Assertions.assertEquals(1, block2.getTransactionsList().size()); + + // There's a transaction called txTestBasefeeOKCall + Transaction txTestBasefeeOKCall = world.getTransactionByName("txTestBasefeeOKCall"); + Assertions.assertNotNull(txTestBasefeeOKCall); + + // Transaction txTestBasefeeOKCall has a transaction receipt + TransactionReceipt txTestBasefeeOKCallReceipt = world.getTransactionReceiptByName("txTestBasefeeOKCall"); + Assertions.assertNotNull(txTestBasefeeOKCallReceipt); + + // Transaction txTestBasefeeOKCall has been processed correctly + byte[] txTestBasefeeOKCallCreationStatus = txTestBasefeeOKCallReceipt.getStatus(); + Assertions.assertNotNull(txTestBasefeeOKCallCreationStatus); + Assertions.assertEquals(1, txTestBasefeeOKCallCreationStatus.length); + Assertions.assertEquals(1, txTestBasefeeOKCallCreationStatus[0]); + + // Check events + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txTestBasefeeOKCallReceipt, "OK", null)); + Assertions.assertEquals(0, TransactionReceiptUtil.getEventCount(txTestBasefeeOKCallReceipt, "ERROR", null)); + + // There's one block (b03) containing only 1 transaction + Block block3 = world.getBlockByName("b03"); + Assertions.assertNotNull(block3); + Assertions.assertEquals(1, block3.getTransactionsList().size()); + + // There's a transaction called txTestBasefeeErrorCall + Transaction txTestBasefeeErrorCall = world.getTransactionByName("txTestBasefeeErrorCall"); + Assertions.assertNotNull(txTestBasefeeErrorCall); + + // Transaction txTestBasefeeErrorCall has a transaction receipt + TransactionReceipt txTestBasefeeErrorCallReceipt = world.getTransactionReceiptByName("txTestBasefeeErrorCall"); + Assertions.assertNotNull(txTestBasefeeErrorCallReceipt); + + // Transaction txTestBasefeeErrorCall has been processed correctly + byte[] txTestBasefeeErrorCallCreationStatus = txTestBasefeeErrorCallReceipt.getStatus(); + Assertions.assertNotNull(txTestBasefeeErrorCallCreationStatus); + Assertions.assertEquals(1, txTestBasefeeErrorCallCreationStatus.length); + Assertions.assertEquals(1, txTestBasefeeErrorCallCreationStatus[0]); + + // Check events + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txTestBasefeeErrorCallReceipt, "ERROR", null)); + Assertions.assertEquals(0, TransactionReceiptUtil.getEventCount(txTestBasefeeErrorCallReceipt, "OK", null)); + } + + @Test + void testBASEFEE_whenNotActivated_BehavesAsExpected() throws FileNotFoundException, DslProcessorException { + + // Config Spies Setup + + TestSystemProperties config = new TestSystemProperties(); + ActivationConfig activationConfig = config.getActivationConfig(); + + TestSystemProperties configSpy = spy(config); + ActivationConfig activationConfigSpy = spy(activationConfig); + + doReturn(activationConfigSpy).when(configSpy).getActivationConfig(); + doReturn(false).when(activationConfigSpy).isActive(eq(ConsensusRule.RSKIP412), anyLong()); + + // Test Setup + + DslParser parser = DslParser.fromResource("dsl/opcode/basefee/baseFeeNotActivatedTest.txt"); + World world = new World(configSpy); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + // Assertions + + // There's one block (b01) containing only 1 transaction + Block block1 = world.getBlockByName("b01"); + Assertions.assertNotNull(block1); + Assertions.assertEquals(1, block1.getTransactionsList().size()); + + // There's a transaction called txTestBasefee + Transaction txTestBasefee = world.getTransactionByName("txTestBasefee"); + Assertions.assertNotNull(txTestBasefee); + + // Transaction txTestBasefee has a transaction receipt + TransactionReceipt txTestBasefeeReceipt = world.getTransactionReceiptByName("txTestBasefee"); + Assertions.assertNotNull(txTestBasefeeReceipt); + + // Transaction txTestBasefee has been processed correctly + byte[] creationStatus = txTestBasefeeReceipt.getStatus(); + Assertions.assertNotNull(creationStatus); + Assertions.assertEquals(1, creationStatus.length); + Assertions.assertEquals(1, creationStatus[0]); + + verify(activationConfigSpy, atLeast(1)).isActive(eq(ConsensusRule.RSKIP412), eq(2L)); + + // There's one block (b02) containing only 1 transaction + Block block2 = world.getBlockByName("b02"); + Assertions.assertNotNull(block2); + Assertions.assertEquals(1, block2.getTransactionsList().size()); + + // There's a transaction called txTestBasefeeNotActivated + Transaction txTestBasefeeNotActivated = world.getTransactionByName("txTestBasefeeNotActivated"); + Assertions.assertNotNull(txTestBasefeeNotActivated); + + // Transaction txTestBasefeeNotActivated has a transaction receipt + TransactionReceipt txTestBasefeeNotActivatedReceipt = world.getTransactionReceiptByName("txTestBasefeeNotActivated"); + Assertions.assertNotNull(txTestBasefeeNotActivatedReceipt); + + // Transaction txTestBasefeeNotActivated has failed + byte[] txTestBasefeeNotActivatedCreationStatus = txTestBasefeeNotActivatedReceipt.getStatus(); + Assertions.assertNotNull(txTestBasefeeNotActivatedCreationStatus); + Assertions.assertEquals(0, txTestBasefeeNotActivatedCreationStatus.length); + } + +} diff --git a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt new file mode 100644 index 00000000000..5cc27c797c6 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt @@ -0,0 +1,122 @@ +comment + +// CONTRACT CODE + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +contract TestBasefee { + constructor() {} + + event OK(); + event ERROR(); + + function checkBasefee(uint256 expected) external { + if (block.basefee == expected) { + emit OK(); + } else { + emit ERROR(); + } + } +} + +// DESCRIPTION + +This contract compares an expected value against the block basefee: + - If block basefee matches the expected value, then the OK event is emmited + - ERROR event is emmited otherwise. + +// CONTRACT BYTECODE + +608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 + +// CONTRACT CALLS + +- checkBasefee(0) // Should emit "OK" as this is the minimum gas price on test + + 6b11a75f0000000000000000000000000000000000000000000000000000000000000000 + +- checkBasefee(1) // Should emit "ERROR" as it is not the minimum gas price + + 6b11a75f0000000000000000000000000000000000000000000000000000000000000001 + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestBasefee contract +transaction_build txTestBasefee + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 + gas 1200000 + build + +# Create block to hold txTestBasefee transaction +block_build b01 + parent g00 + transactions txTestBasefee + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Check txTestBasefee succeded +assert_tx_success txTestBasefee + +# Create transaction to execute testBasefee(0) method +transaction_build txTestBasefeeOKCall + sender acc1 + nonce 1 + contract txTestBasefee + value 0 + data 6b11a75f0000000000000000000000000000000000000000000000000000000000000000 + gas 30000 + build + +# Create block to hold txTestBasefeeOKCall transaction +block_build b02 + parent b01 + transactions txTestBasefeeOKCall + gasLimit 6500000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Check txTestBasefeeOKCall succeded +assert_tx_success txTestBasefeeOKCall + +# Create transaction to execute testBasefee(1) method +transaction_build txTestBasefeeErrorCall + sender acc1 + nonce 2 + contract txTestBasefee + value 0 + data 6b11a75f0000000000000000000000000000000000000000000000000000000000000001 + gas 30000 + build + +# Create block to hold txTestBasefeeErrorCall transaction +block_build b03 + parent b02 + transactions txTestBasefeeErrorCall + gasLimit 6500000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 + +# Check txTestBasefeeErrorCall succeded +assert_tx_success txTestBasefeeErrorCall \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt new file mode 100644 index 00000000000..6ce240f312e --- /dev/null +++ b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt @@ -0,0 +1,89 @@ +comment + +// CONTRACT CODE + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +contract TestBasefee { + constructor() {} + + event OK(); + event ERROR(); + + function checkBasefee(uint256 expected) external { + if (block.basefee == expected) { + emit OK(); + } else { + emit ERROR(); + } + } +} + +// DESCRIPTION + +This contract compares an expected value against the block basefee: + - If block basefee matches the expected value, then the OK event is emmited + - ERROR event is emmited otherwise. + +// CONTRACT BYTECODE + +608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 + +// CONTRACT CALL + +- checkBasefee(0) // Param doesn't matter in this case, so we picked 0 (lazy? XD) + + 6b11a75f0000000000000000000000000000000000000000000000000000000000000000 + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestBasefee contract +transaction_build txTestBasefee + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 + gas 1200000 + build + +# Create block to hold txTestBasefee transaction +block_build b01 + parent g00 + transactions txTestBasefee + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Check txTestBasefee succeded +assert_tx_success txTestBasefee + +# Create transaction to execute testBasefee(0) method +transaction_build txTestBasefeeNotActivated + sender acc1 + nonce 1 + contract txTestBasefee + value 0 + data 6b11a75f0000000000000000000000000000000000000000000000000000000000000000 + gas 30000 + build + +# Create block to hold txTestBasefeeNotActivated transaction +block_build b02 + parent b01 + transactions txTestBasefeeNotActivated + gasLimit 6500000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file