This is an automated email from the ASF dual-hosted git repository.
toulmean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git
The following commit(s) were added to refs/heads/main by this push:
new eb3e9c9 Add address from transaction
new 532e941 Merge pull request #393 from atoulme/address_tx
eb3e9c9 is described below
commit eb3e9c925101158ac907f6af959a89d021ed2bf9
Author: Antoine Toulme <[email protected]>
AuthorDate: Fri Mar 25 22:32:02 2022 -0700
Add address from transaction
---
.../apache/tuweni/blockprocessor/BlockProcessor.kt | 9 +--
.../main/java/org/apache/tuweni/eth/Address.java | 15 +++++
.../java/org/apache/tuweni/eth/Transaction.java | 51 ++++++++------
.../java/org/apache/tuweni/eth/AddressTest.java | 77 ++++++++++++++++++++++
4 files changed, 125 insertions(+), 27 deletions(-)
diff --git
a/eth-blockprocessor/src/main/kotlin/org/apache/tuweni/blockprocessor/BlockProcessor.kt
b/eth-blockprocessor/src/main/kotlin/org/apache/tuweni/blockprocessor/BlockProcessor.kt
index d27ecfc..95e5718 100644
---
a/eth-blockprocessor/src/main/kotlin/org/apache/tuweni/blockprocessor/BlockProcessor.kt
+++
b/eth-blockprocessor/src/main/kotlin/org/apache/tuweni/blockprocessor/BlockProcessor.kt
@@ -78,14 +78,7 @@ class BlockProcessor {
var to: Address
var inputData: Bytes
if (null == tx.to) {
- val contractAddress = Address.fromBytes(
- Hash.hash(
- RLP.encodeList {
- it.writeValue(tx.sender!!)
- it.writeValue(tx.nonce)
- }
- ).slice(12)
- )
+ val contractAddress = Address.fromTransaction(tx)
to = contractAddress
code = tx.payload
inputData = Bytes.EMPTY
diff --git a/eth/src/main/java/org/apache/tuweni/eth/Address.java
b/eth/src/main/java/org/apache/tuweni/eth/Address.java
index 9dce379..c01872a 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/Address.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/Address.java
@@ -18,6 +18,7 @@ import static java.util.Objects.requireNonNull;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.DelegatingBytes;
import org.apache.tuweni.crypto.SECP256K1;
+import org.apache.tuweni.rlp.RLP;
/**
* An Ethereum account address.
@@ -30,6 +31,20 @@ public final class Address extends DelegatingBytes {
public static final Address ZERO = Address.fromBytes(Bytes.repeat((byte) 0,
20));
/**
+ * Derive a contract address from a transaction.
+ */
+ public static Address fromTransaction(Transaction transaction) {
+ if (transaction.getSender() == null) {
+ throw new IllegalArgumentException("Invalid transaction signature,
cannot recover sender");
+ }
+ Bytes encoded = RLP.encodeList((writer) -> {
+ writer.writeValue(transaction.getSender());
+ writer.writeValue(transaction.getNonce().toMinimalBytes());
+ });
+ return Address.fromBytes(Hash.hash(encoded).slice(12));
+ }
+
+ /**
* Transform a public key into an Ethereum address.
*
* @param publicKey the public key
diff --git a/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
b/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
index 5843a6b..9f07a71 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
@@ -103,26 +103,8 @@ public final class Transaction {
throw new RLPException("Additional bytes present at the end of the
encoding");
}
- byte v;
- Integer chainId = null;
-
- if (encodedV == V_BASE || encodedV == (V_BASE + 1)) {
- v = (byte) (encodedV - V_BASE);
- } else if (encodedV > 35) {
- chainId = (encodedV - 35) / 2;
- v = (byte) (encodedV - (2 * chainId + 35));
- } else {
- throw new RLPException("Invalid v encoded value " + encodedV);
- }
-
- SECP256K1.Signature signature;
try {
- signature = SECP256K1.Signature.create(v, r, s);
- } catch (IllegalArgumentException e) {
- throw new RLPException("Invalid signature: " + e.getMessage());
- }
- try {
- return new Transaction(nonce, gasPrice, gasLimit, address, value,
payload, chainId, signature);
+ return fromEncoded(nonce, gasPrice, gasLimit, address, value, payload,
r, s, encodedV);
} catch (IllegalArgumentException e) {
throw new RLPException(e.getMessage(), e);
}
@@ -232,6 +214,37 @@ public final class Transaction {
this.chainId = chainId;
}
+ public static Transaction fromEncoded(
+ UInt256 nonce,
+ Wei gasPrice,
+ Gas gasLimit,
+ @Nullable Address to,
+ Wei value,
+ Bytes payload,
+ BigInteger r,
+ BigInteger s,
+ int encodedV) {
+ byte v;
+ Integer chainId = null;
+
+ if (encodedV == V_BASE || encodedV == (V_BASE + 1)) {
+ v = (byte) (encodedV - V_BASE);
+ } else if (encodedV > 35) {
+ chainId = (encodedV - 35) / 2;
+ v = (byte) (encodedV - (2 * chainId + 35));
+ } else {
+ throw new RLPException("Invalid v encoded value " + encodedV);
+ }
+
+ SECP256K1.Signature signature;
+ try {
+ signature = SECP256K1.Signature.create(v, r, s);
+ } catch (IllegalArgumentException e) {
+ throw new RLPException("Invalid signature: " + e.getMessage());
+ }
+ return new Transaction(nonce, gasPrice, gasLimit, to, value, payload,
chainId, signature);
+ }
+
/**
* Provides the transaction nonce
*
diff --git a/eth/src/test/java/org/apache/tuweni/eth/AddressTest.java
b/eth/src/test/java/org/apache/tuweni/eth/AddressTest.java
new file mode 100644
index 0000000..085aac8
--- /dev/null
+++ b/eth/src/test/java/org/apache/tuweni/eth/AddressTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding
copyright ownership. The ASF licenses this file
+ * to You 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.
+ */
+package org.apache.tuweni.eth;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.junit.BouncyCastleExtension;
+import org.apache.tuweni.units.bigints.UInt256;
+import org.apache.tuweni.units.ethereum.Gas;
+import org.apache.tuweni.units.ethereum.Wei;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(BouncyCastleExtension.class)
+public class AddressTest {
+ /*
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "result": {
+ "blockHash":
"0xdf10741b3b0820015caba402f3a230237af86ac0302a923bba4d4f81610c13f0",
+ "blockNumber": "0x64b991",
+ "from": "0xc82a6220398714f74e2d929309f4c5b1d4f7b0f6",
+ "gas": "0x1abffe",
+ "gasPrice": "0x4a817c800",
+ "hash":
"0x24158c06c57f4a2814b8b31809378c4a457028d57dcf3c29dfbbc13f850ebfea",
+ "input":
"0x60806040523480156200001157600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040805190810160405280600381526020017f4332450000000000000000000000000000000000000000000000000000000000815250600290805190602001906200009f929190620001f8565b506040805190810160405280600981526020017f43324520546f6b656e000000000000000000000000000000000000000000000081525060039080519060200190620000ed929190620001f8565b5
[...]
+ "nonce": "0x2",
+ "r":
"0x10900d90580ce9c809937d8cedc0ae7e487ff94b672b0ecf6443f58dc417f57f",
+ "s":
"0x3f702acb8d9bf4f6887376f3c10b3c254d0b0f136dc570df2a114784d35612e2",
+ "to": null,
+ "transactionIndex": "0x5",
+ "type": "0x0",
+ "v": "0x26",
+ "value": "0x0"
+ }
+ }
+ */
+ @Test
+ void testTransactionToAddress() {
+ UInt256 r =
UInt256.fromHexString("0x10900d90580ce9c809937d8cedc0ae7e487ff94b672b0ecf6443f58dc417f57f");
+ UInt256 s =
UInt256.fromHexString("0x3f702acb8d9bf4f6887376f3c10b3c254d0b0f136dc570df2a114784d35612e2");
+ Bytes v = Bytes.fromHexString("0x26");
+ Transaction tx = Transaction
+ .fromEncoded(
+ UInt256.valueOf(2),
+ Wei.valueOf(UInt256.fromHexString("0x4a817c800")),
+ Gas.valueOf(UInt256.fromHexString("0x1abffe")),
+ null,
+ Wei.valueOf(0),
+ Bytes
+ .fromHexString(
+
"0x60806040523480156200001157600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040805190810160405280600381526020017f4332450000000000000000000000000000000000000000000000000000000000815250600290805190602001906200009f929190620001f8565b506040805190810160405280600981526020017f43324520546f6b656e000000000000000000000000000000000000000000000081525060039080519060200190620000ed92919062000
[...]
+ r.toUnsignedBigInteger(),
+ s.toUnsignedBigInteger(),
+ v.toInt());
+ assertEquals(
+
Hash.fromHexString("0x24158c06c57f4a2814b8b31809378c4a457028d57dcf3c29dfbbc13f850ebfea"),
+ tx.getHash());
+
+ assertEquals("0xc82a6220398714f74e2d929309f4c5b1d4f7b0f6",
tx.getSender().toHexString());
+ Address result = Address.fromTransaction(tx);
+ assertEquals("0xceb46d90598cd81c4e10557c0050a27569e2163e",
result.toHexString());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]