Skip to content

Commit

Permalink
Parse t8n command txs properly (hyperledger#5193)
Browse files Browse the repository at this point in the history
When receiving transactions from a file parse them as an RLP list.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Co-authored-by: Antoine Toulme <antoine@toulme.name>
  • Loading branch information
shemnon and atoulme authored Mar 11, 2023
1 parent 3e35dba commit ccabc72
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState;
Expand All @@ -65,6 +66,7 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -230,7 +232,15 @@ public void run() {
initialWorldState =
objectMapper.convertValue(config.get("alloc"), ReferenceTestWorldState.class);
initialWorldState.persist(null);
Iterator<JsonNode> it = config.get("txs").elements();
var node = config.get("txs");
Iterator<JsonNode> it;
if (node.isArray()) {
it = config.get("txs").elements();
} else if (node == null || node.isNull()) {
it = Collections.emptyIterator();
} else {
it = List.of(node).iterator();
}

transactions = extractTransactions(it);
if (!outDir.toString().isBlank()) {
Expand Down Expand Up @@ -478,14 +488,14 @@ public void run() {

BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
rlpOut.writeList(transactions, Transaction::writeTo);
Bytes bodyBytes = rlpOut.encoded();
TextNode bodyBytes = TextNode.valueOf(rlpOut.encoded().toHexString());

if (outBody.equals((stdoutPath))) {
outputObject.set("body", TextNode.valueOf(bodyBytes.toHexString()));
outputObject.set("body", bodyBytes);
} else {
try (PrintStream fileOut =
new PrintStream(new FileOutputStream(outDir.resolve(outBody).toFile()))) {
fileOut.print(bodyBytes.toHexString());
fileOut.println(bodyBytes);
}
}

Expand All @@ -506,57 +516,70 @@ public void run() {
}
}

private static List<Transaction> extractTransactions(final Iterator<JsonNode> it) {
private List<Transaction> extractTransactions(final Iterator<JsonNode> it) {
List<Transaction> transactions = new ArrayList<>();
while (it.hasNext()) {
JsonNode txNode = it.next();
if (txNode.has("txBytes")) {
Transaction tx = Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText()));
transactions.add(tx);
} else {
Transaction.Builder builder = Transaction.builder();
int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt();
TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type);
builder.type(transactionType);
builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong());
builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue()));
builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong());
builder.value(Wei.fromHexString(txNode.get("value").textValue()));
builder.payload(Bytes.fromHexString(txNode.get("input").textValue()));
if (txNode.has("to")) {
builder.to(Address.fromHexString(txNode.get("to").textValue()));
}

if (transactionType.requiresChainId()
|| !txNode.has("protected")
|| txNode.get("protected").booleanValue()) {
// chainid if protected
builder.chainId(
new BigInteger(
1,
Bytes.fromHexStringLenient(txNode.get("chainId").textValue()).toArrayUnsafe()));
if (txNode.isTextual()) {
BytesValueRLPInput rlpInput =
new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false);
rlpInput.enterList();
while (!rlpInput.isEndOfCurrentList()) {
Transaction tx = Transaction.readFrom(rlpInput);
transactions.add(tx);
}
} else if (txNode.isObject()) {
if (txNode.has("txBytes")) {
Transaction tx =
Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText()));
transactions.add(tx);
} else {
Transaction.Builder builder = Transaction.builder();
int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt();
TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type);
builder.type(transactionType);
builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong());
builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue()));
builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong());
builder.value(Wei.fromHexString(txNode.get("value").textValue()));
builder.payload(Bytes.fromHexString(txNode.get("input").textValue()));
if (txNode.has("to")) {
builder.to(Address.fromHexString(txNode.get("to").textValue()));
}

if (txNode.has("secretKey")) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
KeyPair keys =
signatureAlgorithm.createKeyPair(
signatureAlgorithm.createPrivateKey(
Bytes32.fromHexString(txNode.get("secretKey").textValue())));
if (transactionType.requiresChainId()
|| !txNode.has("protected")
|| txNode.get("protected").booleanValue()) {
// chainid if protected
builder.chainId(
new BigInteger(
1,
Bytes.fromHexStringLenient(txNode.get("chainId").textValue()).toArrayUnsafe()));
}

transactions.add(builder.signAndBuild(keys));
} else {
builder.signature(
SignatureAlgorithmFactory.getInstance()
.createSignature(
Bytes.fromHexString(txNode.get("r").textValue()).toUnsignedBigInteger(),
Bytes.fromHexString(txNode.get("s").textValue()).toUnsignedBigInteger(),
Bytes.fromHexString(txNode.get("v").textValue())
.toUnsignedBigInteger()
.subtract(Transaction.REPLAY_UNPROTECTED_V_BASE)
.byteValueExact()));
transactions.add(builder.build());
if (txNode.has("secretKey")) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
KeyPair keys =
signatureAlgorithm.createKeyPair(
signatureAlgorithm.createPrivateKey(
Bytes32.fromHexString(txNode.get("secretKey").textValue())));

transactions.add(builder.signAndBuild(keys));
} else {
builder.signature(
SignatureAlgorithmFactory.getInstance()
.createSignature(
Bytes.fromHexString(txNode.get("r").textValue()).toUnsignedBigInteger(),
Bytes.fromHexString(txNode.get("s").textValue()).toUnsignedBigInteger(),
Bytes.fromHexString(txNode.get("v").textValue())
.toUnsignedBigInteger()
.subtract(Transaction.REPLAY_UNPROTECTED_V_BASE)
.byteValueExact()));
transactions.add(builder.build());
}
}
} else {
parentCommand.out.printf("TX json node unparseable: %s%n", txNode);
}
}
return transactions;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"cli": [
"t8n",
"--input.alloc=stdin",
"--input.txs=stdin",
"--input.env=stdin",
"--output.result=stdout",
"--output.alloc=stdout",
"--output.body=stdout",
"--state.fork=Shanghai",
"--state.chainid=1",
"--state.reward=2000000000000000000"
],
"stdin": {
"alloc": {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
"balance": "0",
"code": "0x",
"nonce": "1",
"storage": {
}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000000000000000000",
"code": "0x600160010160005500",
"nonce": "0",
"storage": {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "1000000000000000000",
"code": "0x",
"nonce": "0",
"storage": {
}
}
},
"txs": "0xf864f862800a8203e894095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0bb6249049eb38732aa28ef23385945e51c9582c7fab78bd33f6086bd4181615da035118c5432cd6a3bdd6f989d4eee3d43d11736e640bc249d9a2c37e01db3d4b5",
"env": {
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentGasLimit": "0xFF112233445566",
"currentNumber": "1",
"currentTimestamp": "1000",
"currentDifficulty": "0x20000",
"currentBaseFee": "0xa",
"blockHashes": {
"0": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"ommers": [],
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}
},
"stdout": {
"alloc": {
"0x095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"code": "0x600160010160005500",
"balance": "0x1000000000000000000"
},
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
"balance": "0x0",
"nonce": "0x1"
},
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0x1000000000000000000"
}
},
"body": "0xf864f862800a8203e894095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0bb6249049eb38732aa28ef23385945e51c9582c7fab78bd33f6086bd4181615da035118c5432cd6a3bdd6f989d4eee3d43d11736e640bc249d9a2c37e01db3d4b5",
"result": {
"stateRoot": "0xec92f4c572101075d17eb5aaf15c33df92b6d5519cbed635fc53353b99e8e6da",
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"receipts": [],
"rejected": [
{
"index": 0,
"error": "intrinsic gas cost 21000 exceeds gas limit 1000"
}
],
"currentDifficulty": "0x20000",
"gasUsed": "0x0",
"currentBaseFee": "0xa",
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
}
}

0 comments on commit ccabc72

Please sign in to comment.