Skip to content

Commit

Permalink
Merge pull request #2068 from rsksmart/add-push0-instruction
Browse files Browse the repository at this point in the history
Implement EIP-3855: PUSH0 instruction
  • Loading branch information
Vovchyk authored Aug 28, 2023
2 parents 8844f20 + 972b3ed commit 98a8455
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public enum ConsensusRule {
RSKIP377("rskip377"),
RSKIP383("rskip383"),
RSKIP385("rskip385"),
RSKIP398("rskip398"),
;

private String configKey;
Expand Down
5 changes: 4 additions & 1 deletion rskj-core/src/main/java/org/ethereum/vm/OpCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ public enum OpCode {


/* Push Operations */

/**
* (0x5f) Pushes the constant value 0 onto the stack.
*/
PUSH0(0x5f, 0, 1, BASE_TIER),
/**
* (0x60) Place 1-byte item on stack
*/
Expand Down
5 changes: 4 additions & 1 deletion rskj-core/src/main/java/org/ethereum/vm/OpCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,10 @@ private OpCodes() {
static final byte OP_JUMPDEST =0x5b ;

/* Push Operations */

/**
* (0x5f) Pushes the constant value 0 onto the stack.
*/
public static final byte OP_PUSH_0 =0x5f ;
/**
* (0x60) Place 1-byte item on stack
*/
Expand Down
21 changes: 21 additions & 0 deletions rskj-core/src/main/java/org/ethereum/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,20 @@ protected void doPUSH(){
program.stackPush(data);
}

protected void doPUSH0(){
spendOpCodeGas();
// EXECUTION PHASE
program.step();

DataWord zero = DataWord.ZERO;

if (isLogEnabled) {
hint = "" + ByteUtil.toHexString(zero.getData());
}

program.stackPush(zero);
}

protected void doJUMPDEST()
{
spendOpCodeGas();
Expand Down Expand Up @@ -1913,6 +1927,13 @@ protected void executeOpcode() {
case OpCodes.OP_GAS: doGAS();
break;

case OpCodes.OP_PUSH_0:
if (!activations.isActive(RSKIP398)) {
throw Program.ExceptionHelper.invalidOpCode(program);
}
doPUSH0();
break;

case OpCodes.OP_PUSH_1:
case OpCodes.OP_PUSH_2:
case OpCodes.OP_PUSH_3:
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/expected.conf
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ blockchain = {
rskip377 = <hardforkName>
rskip383 = <hardforkName>
rskip385 = <hardforkName>
rskip398 = <hardforkName>
}
}
gc = {
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ blockchain = {
rskip377 = fingerroot500
rskip383 = fingerroot500
rskip385 = fingerroot500
rskip398 = tbd600
}
}
gc = {
Expand Down
26 changes: 26 additions & 0 deletions rskj-core/src/test/java/co/rsk/vm/VMExecutionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -893,4 +893,30 @@ private Program playCodeWithActivationConfig(byte[] code, ActivationConfig.ForBl

return program;
}

private void executePush0(ActivationConfig.ForBlock activations){
Program program = executeCodeWithActivationConfig("PUSH0", 1, activations);
Stack stack = program.getStack();

Assertions.assertEquals(1, stack.size());
Assertions.assertEquals(DataWord.valueFromHex("0000000000000000000000000000000000000000000000000000000000000000"), stack.peek());
}
@Test
void testPUSH0Activation() {
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
when(activations.isActive(RSKIP398)).thenReturn(true);

executePush0(activations);
}

@Test
void testPUSH0NoActivation() {
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
when(activations.isActive(RSKIP398)).thenReturn(false);

Assertions.assertThrows(Program.IllegalOperationException.class, () -> {
executePush0(activations);
});

}
}
61 changes: 61 additions & 0 deletions rskj-core/src/test/java/co/rsk/vm/VmDslTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.junit.jupiter.api.Test;

import java.io.FileNotFoundException;
import java.nio.ByteBuffer;

/**
* Created by ajlopez on 15/04/2020.
Expand Down Expand Up @@ -106,4 +107,64 @@ void invokeRecursiveContractsUsing401Levels() throws FileNotFoundException, DslP
Assertions.assertNotNull(status);
Assertions.assertEquals(0, status.length);
}

@Test
void testPush0() throws FileNotFoundException, DslProcessorException {
DslParser parser = DslParser.fromResource("dsl/push0test.txt");
World world = new World();

WorldDslProcessor processor = new WorldDslProcessor(world);

processor.processCommands(parser);

Block block2 = world.getBlockByName("b02");
Assertions.assertNotNull(block2);
Assertions.assertEquals(1, block2.getTransactionsList().size());

Transaction creationTransactionNew = world.getTransactionByName("txCreateNew");
Assertions.assertNotNull(creationTransactionNew);
TransactionReceipt creationTransactionReceiptNew = world.getTransactionReceiptByName("txCallNew");
Assertions.assertNotNull(creationTransactionReceiptNew);
byte[] statusCreationNew = creationTransactionReceiptNew.getStatus();
Assertions.assertNotNull(statusCreationNew);
Assertions.assertEquals(1, statusCreationNew.length);
Assertions.assertEquals(1, statusCreationNew[0]);

Transaction callTransactionNew = world.getTransactionByName("txCallNew");
Assertions.assertNotNull(callTransactionNew);
TransactionReceipt callTransactionReceiptNew = world.getTransactionReceiptByName("txCallNew");
Assertions.assertNotNull(callTransactionReceiptNew);
byte[] statusCallNew = callTransactionReceiptNew.getStatus();
Assertions.assertNotNull(statusCallNew);
Assertions.assertEquals(1, statusCallNew.length);
Assertions.assertEquals(1, statusCallNew[0]);

short newGas = ByteBuffer.wrap(callTransactionReceiptNew.getGasUsed()).getShort();

Block block4 = world.getBlockByName("b04");
Assertions.assertNotNull(block4);
Assertions.assertEquals(1, block4.getTransactionsList().size());


Transaction creationTransactionOld = world.getTransactionByName("txCreateOld");
Assertions.assertNotNull(creationTransactionOld);
TransactionReceipt creationTransactionReceiptOld = world.getTransactionReceiptByName("txCreateOld");
Assertions.assertNotNull(creationTransactionReceiptOld);
byte[] statusCreationOld = creationTransactionReceiptNew.getStatus();
Assertions.assertNotNull(statusCreationOld);
Assertions.assertEquals(1, statusCreationOld.length);
Assertions.assertEquals(1, statusCreationOld[0]);

Transaction callTransactionOld = world.getTransactionByName("txCallOld");
Assertions.assertNotNull(callTransactionOld);
TransactionReceipt callTransactionReceiptOld = world.getTransactionReceiptByName("txCallOld");
Assertions.assertNotNull(callTransactionReceiptOld);
byte[] statusCallOld = callTransactionReceiptOld.getStatus();
Assertions.assertNotNull(statusCallOld);
Assertions.assertEquals(1, statusCallOld.length);
Assertions.assertEquals(1, statusCallOld[0]);

short oldGas = ByteBuffer.wrap(callTransactionReceiptOld.getGasUsed()).getShort();
Assertions.assertTrue(newGas < oldGas);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class ActivationConfigTest {
" rskip377: fingerroot500",
" rskip383: fingerroot500",
" rskip385: fingerroot500",
" rskip398: tbd600",
"}"
));

Expand Down
11 changes: 11 additions & 0 deletions rskj-core/src/test/java/org/ethereum/vm/VMTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,16 @@ void testSTATICCALLWithStatusOneAndAdditionalValueInStackUsingFixStaticCallLeave
assertEquals(DataWord.valueOf(42), program.getStack().pop());
}

@Test // PUSH0 OP
void testPUSH0() {
program = getProgram(compile("PUSH0"));
String expected = "0000000000000000000000000000000000000000000000000000000000000000";

program.fullTrace();
vm.step(program);

assertEquals(expected, ByteUtil.toHexString(program.getStack().peek().getData()).toUpperCase());
}
@Test // PUSH1 OP
void testPUSH1() {

Expand Down Expand Up @@ -3381,6 +3391,7 @@ private ActivationConfig.ForBlock getBlockchainConfig(boolean preFixStaticCall)
when(activations.isActive(ConsensusRule.RSKIP90)).thenReturn(true);
when(activations.isActive(ConsensusRule.RSKIP89)).thenReturn(true);
when(activations.isActive(ConsensusRule.RSKIP150)).thenReturn(true);
when(activations.isActive(ConsensusRule.RSKIP398)).thenReturn(true);
return activations;
}

Expand Down
98 changes: 98 additions & 0 deletions rskj-core/src/test/resources/dsl/push0test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
comment

// Contracts compiled using 0.8.20 (txCreateNew) and 0.8.17 (txCreateOld)
// the contract source code

contract PushZero {
function add(uint256 a, uint256 b) external returns (uint256) {
unchecked {
return a + b;
}
}
}

end

account_new acc1 10000000

# deploy contract compiled with 0.8.20 (generates PUSH0)
transaction_build txCreateNew
sender acc1
receiverAddress 00
value 0
data 608060405234801561000f575f80fd5b506101238061001d5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063771602f714602a575b5f80fd5b60406004803603810190603c91906092565b6054565b604051604b919060d6565b60405180910390f35b5f818301905092915050565b5f80fd5b5f819050919050565b6074816064565b8114607d575f80fd5b50565b5f81359050608c81606d565b92915050565b5f806040838503121560a55760a46060565b5b5f60b0858286016080565b925050602060bf858286016080565b9150509250929050565b60d0816064565b82525050565b5f60208201905060e75f83018460c9565b9291505056fea264697066735822122045ed7bb05dd9f1947b2804a8d76b6b7336f31495e814ca7c00a1c4bf60828d8364736f6c63430008140033
gas 1200000
build

block_build b01
parent g00
transactions txCreateNew
build

block_connect b01

# Assert best block
assert_best b01

# call add(0,3)
transaction_build txCallNew
sender acc1
nonce 1
contract txCreateNew # created in txCreateNew
value 0
data 771602f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003
gas 30000
build

block_build b02
parent b01
transactions txCallNew
gasLimit 6500000
build

block_connect b02

# Assert best block
assert_best b02

# deploy contract compiled with 0.8.17 (does not generate PUSH0)
transaction_build txCreateOld
sender acc1
receiverAddress 00
nonce 2
value 0
data 608060405234801561001057600080fd5b5061012f806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063771602f714602d575b600080fd5b60436004803603810190603f9190609a565b6057565b604051604e919060e0565b60405180910390f35b6000818301905092915050565b600080fd5b6000819050919050565b607a816069565b8114608457600080fd5b50565b6000813590506094816073565b92915050565b6000806040838503121560ae5760ad6064565b5b600060ba858286016087565b925050602060c9858286016087565b9150509250929050565b60da816069565b82525050565b600060208201905060f3600083018460d3565b9291505056fea2646970667358221220b386c5fbaa1f4fa300a7ba86a498ed9bdf2b01bffc7263abc34cc285d973482264736f6c63430008110033
gas 1200000
build

block_build b03
parent b02
transactions txCreateOld
gasLimit 6500000
build

block_connect b03

# Assert best block
assert_best b03

# call add(0,3)
transaction_build txCallOld
sender acc1
nonce 3
contract txCreateOld # created in txCreateOld
value 0
data 771602f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003
gas 30000
build

block_build b04
parent b03
transactions txCallOld
gasLimit 6500000
build

block_connect b04

# Assert best block
assert_best b04

0 comments on commit 98a8455

Please sign in to comment.