diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/EqOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/EqOperationV2.java new file mode 100644 index 00000000000..21c32ce2978 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/EqOperationV2.java @@ -0,0 +1,67 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** EVM v2 EQ operation using long[] stack representation. */ +public class EqOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult EQ_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new Eq operation. + * + * @param gasCalculator the gas calculator + */ + public EqOperationV2(final GasCalculator gasCalculator) { + super(0x14, "EQ", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs EQ on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + final boolean eq = + s[a] == s[b] && s[a + 1] == s[b + 1] && s[a + 2] == s[b + 2] && s[a + 3] == s[b + 3]; + + s[b] = 0L; + s[b + 1] = 0L; + s[b + 2] = 0L; + s[b + 3] = eq ? 1L : 0L; + + frame.setTopV2(top - 1); + return EQ_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/GtOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/GtOperationV2.java new file mode 100644 index 00000000000..b893760bad0 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/GtOperationV2.java @@ -0,0 +1,75 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** EVM v2 GT operation using long[] stack representation. */ +public class GtOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult GT_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new Gt operation. + * + * @param gasCalculator the gas calculator + */ + public GtOperationV2(final GasCalculator gasCalculator) { + super(0x11, "GT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs unsigned GT on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + int cmp = Long.compareUnsigned(s[a], s[b]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 1], s[b + 1]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 2], s[b + 2]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 3], s[b + 3]); + } + } + } + + s[b] = 0L; + s[b + 1] = 0L; + s[b + 2] = 0L; + s[b + 3] = cmp > 0 ? 1L : 0L; + + frame.setTopV2(top - 1); + return GT_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/IsZeroOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/IsZeroOperationV2.java new file mode 100644 index 00000000000..c53a06a610a --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/IsZeroOperationV2.java @@ -0,0 +1,64 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** EVM v2 ISZERO operation using long[] stack representation. */ +public class IsZeroOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult ISZERO_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new IsZero operation. + * + * @param gasCalculator the gas calculator + */ + public IsZeroOperationV2(final GasCalculator gasCalculator) { + super(0x15, "ISZERO", 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs ISZERO on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + + final boolean isZero = s[a] == 0L && s[a + 1] == 0L && s[a + 2] == 0L && s[a + 3] == 0L; + + s[a] = 0L; + s[a + 1] = 0L; + s[a + 2] = 0L; + s[a + 3] = isZero ? 1L : 0L; + + return ISZERO_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/LtOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/LtOperationV2.java new file mode 100644 index 00000000000..1d790acd512 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/LtOperationV2.java @@ -0,0 +1,75 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** EVM v2 LT operation using long[] stack representation. */ +public class LtOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult LT_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new Lt operation. + * + * @param gasCalculator the gas calculator + */ + public LtOperationV2(final GasCalculator gasCalculator) { + super(0x10, "LT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs unsigned LT on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + int cmp = Long.compareUnsigned(s[a], s[b]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 1], s[b + 1]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 2], s[b + 2]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 3], s[b + 3]); + } + } + } + + s[b] = 0L; + s[b + 1] = 0L; + s[b + 2] = 0L; + s[b + 3] = cmp < 0 ? 1L : 0L; + + frame.setTopV2(top - 1); + return LT_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SGtOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SGtOperationV2.java new file mode 100644 index 00000000000..7b6f6b7eb24 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SGtOperationV2.java @@ -0,0 +1,89 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** + * EVM v2 SGT (signed greater than) operation using long[] stack representation. + * + *
Values are interpreted as two's complement signed 256-bit integers. The sign is determined by + * the most significant bit of limb 0. + */ +public class SGtOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult SGT_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new SGt operation. + * + * @param gasCalculator the gas calculator + */ + public SGtOperationV2(final GasCalculator gasCalculator) { + super(0x13, "SGT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs signed GT on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + final boolean aNeg = s[a] < 0; + final boolean bNeg = s[b] < 0; + + boolean gt; + if (aNeg != bNeg) { + gt = bNeg; + } else { + int cmp = Long.compareUnsigned(s[a], s[b]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 1], s[b + 1]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 2], s[b + 2]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 3], s[b + 3]); + } + } + } + gt = cmp > 0; + } + + s[b] = 0L; + s[b + 1] = 0L; + s[b + 2] = 0L; + s[b + 3] = gt ? 1L : 0L; + + frame.setTopV2(top - 1); + return SGT_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SLtOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SLtOperationV2.java new file mode 100644 index 00000000000..466f5e2fdb4 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SLtOperationV2.java @@ -0,0 +1,89 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** + * EVM v2 SLT (signed less than) operation using long[] stack representation. + * + *
Values are interpreted as two's complement signed 256-bit integers. The sign is determined by + * the most significant bit of limb 0. + */ +public class SLtOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult SLT_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new SLt operation. + * + * @param gasCalculator the gas calculator + */ + public SLtOperationV2(final GasCalculator gasCalculator) { + super(0x12, "SLT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs signed LT on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + final boolean aNeg = s[a] < 0; + final boolean bNeg = s[b] < 0; + + boolean lt; + if (aNeg != bNeg) { + lt = aNeg; + } else { + int cmp = Long.compareUnsigned(s[a], s[b]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 1], s[b + 1]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 2], s[b + 2]); + if (cmp == 0) { + cmp = Long.compareUnsigned(s[a + 3], s[b + 3]); + } + } + } + lt = cmp < 0; + } + + s[b] = 0L; + s[b + 1] = 0L; + s[b + 2] = 0L; + s[b + 3] = lt ? 1L : 0L; + + frame.setTopV2(top - 1); + return SLT_SUCCESS; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SubOperationV2.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SubOperationV2.java new file mode 100644 index 00000000000..69f3de4f7a0 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/v2/SubOperationV2.java @@ -0,0 +1,85 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.operation.v2; + +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.operation.Operation; + +/** + * EVM v2 SUB operation using long[] stack representation. + * + *
Each 256-bit word is stored as four longs: index 0 = most significant 64 bits, index 3 = least + * significant 64 bits. Subtraction is performed with borrow propagation from least to most + * significant word, with underflow silently wrapping (mod 2^256). + */ +public class SubOperationV2 extends AbstractFixedCostOperationV2 { + + private static final Operation.OperationResult SUB_SUCCESS = + new Operation.OperationResult(3, null); + + /** + * Instantiates a new Sub operation. + * + * @param gasCalculator the gas calculator + */ + public SubOperationV2(final GasCalculator gasCalculator) { + super(0x03, "SUB", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); + } + + @Override + public Operation.OperationResult executeFixedCostOperation( + final MessageFrame frame, final EVM evm) { + return staticOperation(frame, frame.stackDataV2()); + } + + /** + * Performs SUB on the v2 long[] stack. + * + * @param frame the message frame + * @param s the stack data as a long[] array + * @return the operation result + */ + public static Operation.OperationResult staticOperation( + final MessageFrame frame, final long[] s) { + final int top = frame.stackTopV2(); + final int a = (top - 1) * 4; + final int b = (top - 2) * 4; + + long diff3 = s[a + 3] - s[b + 3]; + long bw3 = Long.compareUnsigned(s[a + 3], s[b + 3]) < 0 ? 1L : 0L; + + long partial2 = s[a + 2] - s[b + 2]; + long bw2 = Long.compareUnsigned(s[a + 2], s[b + 2]) < 0 ? 1L : 0L; + long diff2 = partial2 - bw3; + bw2 |= Long.compareUnsigned(partial2, bw3) < 0 ? 1L : 0L; + + long partial1 = s[a + 1] - s[b + 1]; + long bw1 = Long.compareUnsigned(s[a + 1], s[b + 1]) < 0 ? 1L : 0L; + long diff1 = partial1 - bw2; + bw1 |= Long.compareUnsigned(partial1, bw2) < 0 ? 1L : 0L; + + long diff0 = s[a] - s[b] - bw1; + + s[b] = diff0; + s[b + 1] = diff1; + s[b + 2] = diff2; + s[b + 3] = diff3; + + frame.setTopV2(top - 1); + return SUB_SUCCESS; + } +}