Skip to content

Commit ba00ae6

Browse files
shemnoneum602
authored andcommitted
Test updates for cancun execution-spec-tests (hyperledger#5670)
- support legacy V values (larger V value) and type 1+ (v is recId only) - new fields - shared transaction extraction - rejection detection Signed-off-by: Danno Ferrin <[email protected]>
1 parent 60b9475 commit ba00ae6

17 files changed

+325
-210
lines changed

ethereum/evmtool/build.gradle

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ dependencies {
5656
implementation 'info.picocli:picocli'
5757
implementation 'io.vertx:vertx-core'
5858

59-
runtimeOnly 'org.slf4j:slf4j-nop'
60-
6159
annotationProcessor 'com.google.dagger:dagger-compiler'
6260
annotationProcessor 'info.picocli:picocli-codegen'
6361

@@ -67,6 +65,9 @@ dependencies {
6765
testImplementation 'org.mockito:mockito-core'
6866

6967
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
68+
69+
// No logging in grallvm EvmTool
70+
nativeImageClasspath 'org.slf4j:slf4j-nop'
7071
}
7172

7273
mainClassName = 'org.hyperledger.besu.evmtool.EvmTool'

ethereum/evmtool/src/main/graal/reflection-config.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
"unsafeAllocated": true
103103
},
104104
{
105-
"name": "org.hyperledger.besu.evmtool.T8nSubCommand$RejectedTransaction",
105+
"name": "org.hyperledger.besu.evmtool.T8nExecutor$RejectedTransaction",
106106
"queryAllPublicConstructors": true,
107107
"queryAllPublicMethods": true,
108108
"allDeclaredConstructors": true,

ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java

+158-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts;
1919

2020
import org.hyperledger.besu.config.StubGenesisConfigOptions;
21+
import org.hyperledger.besu.crypto.KeyPair;
22+
import org.hyperledger.besu.crypto.SignatureAlgorithm;
23+
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
2124
import org.hyperledger.besu.datatypes.Address;
2225
import org.hyperledger.besu.datatypes.DataGas;
2326
import org.hyperledger.besu.datatypes.Hash;
@@ -36,24 +39,33 @@
3639
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain;
3740
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv;
3841
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
42+
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
3943
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
4044
import org.hyperledger.besu.ethereum.rlp.RLP;
4145
import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState;
46+
import org.hyperledger.besu.evm.AccessListEntry;
4247
import org.hyperledger.besu.evm.account.Account;
4348
import org.hyperledger.besu.evm.account.AccountStorageEntry;
4449
import org.hyperledger.besu.evm.log.Log;
4550
import org.hyperledger.besu.evm.tracing.OperationTracer;
4651
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
4752
import org.hyperledger.besu.evmtool.exception.UnsupportedForkException;
53+
import org.hyperledger.besu.plugin.data.TransactionType;
4854

4955
import java.io.IOException;
56+
import java.io.PrintWriter;
5057
import java.math.BigInteger;
5158
import java.util.ArrayList;
5259
import java.util.Comparator;
60+
import java.util.Iterator;
5361
import java.util.List;
5462
import java.util.NavigableMap;
63+
import java.util.Spliterator;
64+
import java.util.Spliterators;
5565
import java.util.concurrent.TimeUnit;
66+
import java.util.stream.StreamSupport;
5667

68+
import com.fasterxml.jackson.databind.JsonNode;
5769
import com.fasterxml.jackson.databind.ObjectMapper;
5870
import com.fasterxml.jackson.databind.node.ArrayNode;
5971
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -64,6 +76,149 @@
6476
import org.apache.tuweni.units.bigints.UInt256;
6577

6678
public class T8nExecutor {
79+
80+
record RejectedTransaction(int index, String error) {}
81+
82+
protected static List<Transaction> extractTransactions(
83+
final PrintWriter out,
84+
final Iterator<JsonNode> it,
85+
final List<Transaction> transactions,
86+
final List<RejectedTransaction> rejections) {
87+
int i = 0;
88+
while (it.hasNext()) {
89+
try {
90+
JsonNode txNode = it.next();
91+
if (txNode.isTextual()) {
92+
BytesValueRLPInput rlpInput =
93+
new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false);
94+
rlpInput.enterList();
95+
while (!rlpInput.isEndOfCurrentList()) {
96+
Transaction tx = Transaction.readFrom(rlpInput);
97+
transactions.add(tx);
98+
}
99+
} else if (txNode.isObject()) {
100+
if (txNode.has("txBytes")) {
101+
Transaction tx =
102+
Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText()));
103+
transactions.add(tx);
104+
} else {
105+
Transaction.Builder builder = Transaction.builder();
106+
int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt();
107+
TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type);
108+
builder.type(transactionType);
109+
builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong());
110+
builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong());
111+
builder.value(Wei.fromHexString(txNode.get("value").textValue()));
112+
builder.payload(Bytes.fromHexString(txNode.get("input").textValue()));
113+
114+
if (txNode.has("gasPrice")) {
115+
builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue()));
116+
}
117+
if (txNode.has("maxPriorityFeePerGas")) {
118+
builder.maxPriorityFeePerGas(
119+
Wei.fromHexString(txNode.get("maxPriorityFeePerGas").textValue()));
120+
}
121+
if (txNode.has("maxFeePerGas")) {
122+
builder.maxFeePerGas(Wei.fromHexString(txNode.get("maxFeePerGas").textValue()));
123+
}
124+
if (txNode.has("maxFeePerDataGas")) {
125+
builder.maxFeePerDataGas(
126+
Wei.fromHexString(txNode.get("maxFeePerDataGas").textValue()));
127+
}
128+
129+
if (txNode.has("to")) {
130+
builder.to(Address.fromHexString(txNode.get("to").textValue()));
131+
}
132+
133+
if (transactionType.requiresChainId()
134+
|| !txNode.has("protected")
135+
|| txNode.get("protected").booleanValue()) {
136+
// chainid if protected
137+
builder.chainId(
138+
new BigInteger(
139+
1,
140+
Bytes.fromHexStringLenient(txNode.get("chainId").textValue())
141+
.toArrayUnsafe()));
142+
}
143+
144+
if (txNode.has("accessList")) {
145+
JsonNode accessList = txNode.get("accessList");
146+
if (!accessList.isArray()) {
147+
out.printf(
148+
"TX json node unparseable: expected accessList to be an array - %s%n", txNode);
149+
continue;
150+
}
151+
List<AccessListEntry> entries = new ArrayList<>(accessList.size());
152+
for (JsonNode entryAsJson : accessList) {
153+
Address address = Address.fromHexString(entryAsJson.get("address").textValue());
154+
List<String> storageKeys =
155+
StreamSupport.stream(
156+
Spliterators.spliteratorUnknownSize(
157+
entryAsJson.get("storageKeys").elements(), Spliterator.ORDERED),
158+
false)
159+
.map(JsonNode::textValue)
160+
.toList();
161+
var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys);
162+
entries.add(accessListEntry);
163+
}
164+
builder.accessList(entries);
165+
}
166+
167+
if (txNode.has("blobVersionedHashes")) {
168+
JsonNode blobVersionedHashes = txNode.get("blobVersionedHashes");
169+
if (!blobVersionedHashes.isArray()) {
170+
out.printf(
171+
"TX json node unparseable: expected blobVersionedHashes to be an array - %s%n",
172+
txNode);
173+
continue;
174+
}
175+
// FUTURE: placeholder code until 4844 PR merges
176+
// List<VersionedHash> entries = new ArrayList<>(blobVersionedHashes.size());
177+
// for (JsonNode versionedHashNode : blobVersionedHashes) {
178+
// entries.add(
179+
// new VersionedHash(Bytes32.fromHexString(versionedHashNode.textValue())));
180+
// }
181+
// builder.versionedHashes(entries);
182+
}
183+
184+
if (txNode.has("secretKey")) {
185+
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
186+
KeyPair keys =
187+
signatureAlgorithm.createKeyPair(
188+
signatureAlgorithm.createPrivateKey(
189+
Bytes32.fromHexString(txNode.get("secretKey").textValue())));
190+
191+
transactions.add(builder.signAndBuild(keys));
192+
} else {
193+
BigInteger v =
194+
Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger();
195+
if (v.compareTo(BigInteger.valueOf(35)) >= 0) {
196+
v = v.subtract(BigInteger.valueOf(35)).mod(BigInteger.TWO);
197+
} else if (v.compareTo(BigInteger.valueOf(27)) >= 0) {
198+
v = v.subtract(BigInteger.valueOf(27)).mod(BigInteger.TWO);
199+
}
200+
builder.signature(
201+
SignatureAlgorithmFactory.getInstance()
202+
.createSignature(
203+
Bytes.fromHexStringLenient(txNode.get("r").textValue())
204+
.toUnsignedBigInteger(),
205+
Bytes.fromHexStringLenient(txNode.get("s").textValue())
206+
.toUnsignedBigInteger(),
207+
v.byteValueExact()));
208+
transactions.add(builder.build());
209+
}
210+
}
211+
} else {
212+
out.printf("TX json node unparseable: %s%n", txNode);
213+
}
214+
} catch (IllegalArgumentException iae) {
215+
rejections.add(new RejectedTransaction(i, iae.getMessage()));
216+
}
217+
i++;
218+
}
219+
return transactions;
220+
}
221+
67222
static T8nResult runTest(
68223
final Long chainId,
69224
final String fork,
@@ -72,6 +227,7 @@ static T8nResult runTest(
72227
final ReferenceTestEnv referenceTestEnv,
73228
final MutableWorldState initialWorldState,
74229
final List<Transaction> transactions,
230+
final List<RejectedTransaction> rejections,
75231
final TracerManager tracerManager) {
76232

77233
final ReferenceTestProtocolSchedules referenceTestProtocolSchedules =
@@ -95,7 +251,7 @@ static T8nResult runTest(
95251
final Wei dataGasPrice = protocolSpec.getFeeMarket().dataPrice(DataGas.ZERO);
96252

97253
List<TransactionReceipt> receipts = new ArrayList<>();
98-
List<T8nSubCommand.RejectedTransaction> invalidTransactions = new ArrayList<>();
254+
List<RejectedTransaction> invalidTransactions = new ArrayList<>(rejections);
99255
List<Transaction> validTransactions = new ArrayList<>();
100256
ArrayNode receiptsArray = objectMapper.createArrayNode();
101257
long gasUsed = 0;
@@ -138,8 +294,7 @@ static T8nResult runTest(
138294
}
139295
if (result.isInvalid()) {
140296
invalidTransactions.add(
141-
new T8nSubCommand.RejectedTransaction(
142-
i, result.getValidationResult().getErrorMessage()));
297+
new RejectedTransaction(i, result.getValidationResult().getErrorMessage()));
143298
} else {
144299
validTransactions.add(transaction);
145300

0 commit comments

Comments
 (0)