From 8081f027c9276518b8b80f44430b9cd443a7bdd5 Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Fri, 6 Apr 2018 08:21:29 +0200 Subject: [PATCH 1/6] initial work on transaction decoder --- .../org/web3j/crypto/TransactionDecoder.java | 26 ++++++++++++++ .../web3j/crypto/TransactionDecoderTest.java | 34 +++++++++++++++++++ rlp/build.gradle | 2 +- .../main/java/org/web3j/rlp/RlpString.java | 13 +++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java create mode 100644 crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java diff --git a/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java new file mode 100644 index 000000000..06e319a1a --- /dev/null +++ b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java @@ -0,0 +1,26 @@ +package org.web3j.crypto; + +import java.math.BigInteger; + +import org.web3j.rlp.RlpDecoder; +import org.web3j.rlp.RlpList; +import org.web3j.rlp.RlpString; +import org.web3j.utils.Numeric; + +public class TransactionDecoder { + + public static RawTransaction decode(String hexTransaction) { + byte[] transaction = Numeric.hexStringToByteArray(hexTransaction); + RlpList rlpList = RlpDecoder.decode(transaction); + RlpList values = (RlpList) rlpList.getValues().get(0); + BigInteger nonce = ((RlpString) values.getValues().get(0)).asBigInteger(); + BigInteger gasPrice = ((RlpString) values.getValues().get(1)).asBigInteger(); + BigInteger gasLimit = ((RlpString) values.getValues().get(2)).asBigInteger(); + String to = ((RlpString) values.getValues().get(3)).asString(); + BigInteger value = null; + String data = null; + RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, + gasPrice, gasLimit, to, value, data); + return rawTransaction; + } +} diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java new file mode 100644 index 000000000..9456081cd --- /dev/null +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -0,0 +1,34 @@ +package org.web3j.crypto; + +import java.math.BigInteger; + +import org.junit.Test; + +import org.web3j.utils.Numeric; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TransactionDecoderTest { + + @Test + public void testDecoding() throws Exception { + BigInteger nonce = BigInteger.ZERO; + BigInteger gasPrice = BigInteger.ONE; + BigInteger gasLimit = BigInteger.TEN; + String to = "0xadd5355"; + RawTransaction rawTransaction = RawTransaction.createEtherTransaction( + nonce, gasPrice, gasLimit, to, + BigInteger.valueOf(Long.MAX_VALUE)); + byte[] signedMessage = TransactionEncoder.signMessage( + rawTransaction, SampleKeys.CREDENTIALS); + String hexMessage = Numeric.toHexString(signedMessage); + + RawTransaction result = TransactionDecoder.decode(hexMessage); + assertNotNull(result); + assertEquals(nonce, result.getNonce()); + assertEquals(gasPrice, result.getGasPrice()); + assertEquals(gasLimit, result.getGasLimit()); + assertEquals(to, result.getTo()); + } +} diff --git a/rlp/build.gradle b/rlp/build.gradle index 1f98d8c09..3f5ae0c8c 100644 --- a/rlp/build.gradle +++ b/rlp/build.gradle @@ -2,5 +2,5 @@ description 'Ethereum Recursive Length Prefix (RLP) encoding for serializing objects' dependencies { - testCompile project(':utils') + compile project(':utils') } diff --git a/rlp/src/main/java/org/web3j/rlp/RlpString.java b/rlp/src/main/java/org/web3j/rlp/RlpString.java index 3519413c4..636d9af1b 100644 --- a/rlp/src/main/java/org/web3j/rlp/RlpString.java +++ b/rlp/src/main/java/org/web3j/rlp/RlpString.java @@ -3,6 +3,8 @@ import java.math.BigInteger; import java.util.Arrays; +import org.web3j.utils.Numeric; + /** * RLP string type. */ @@ -19,6 +21,17 @@ public byte[] getBytes() { return value; } + public BigInteger asBigInteger() { + if (value.length == 0) { + return BigInteger.ZERO; + } + return new BigInteger(value); + } + + public String asString() { + return Numeric.toHexString(value); + } + public static RlpString create(byte[] value) { return new RlpString(value); } From 09e644ce40e462e264cf8331e3fb8b6b6d3595b9 Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Tue, 10 Apr 2018 17:40:42 +0200 Subject: [PATCH 2/6] parse signed raw transaction --- .../java/org/web3j/crypto/RawTransaction.java | 2 +- .../web3j/crypto/SignedRawTransaction.java | 19 +++++++++ .../org/web3j/crypto/TransactionDecoder.java | 16 ++++++-- .../web3j/crypto/TransactionDecoderTest.java | 39 +++++++++++++++++-- 4 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java diff --git a/crypto/src/main/java/org/web3j/crypto/RawTransaction.java b/crypto/src/main/java/org/web3j/crypto/RawTransaction.java index e400022c9..aecbf2e99 100644 --- a/crypto/src/main/java/org/web3j/crypto/RawTransaction.java +++ b/crypto/src/main/java/org/web3j/crypto/RawTransaction.java @@ -18,7 +18,7 @@ public class RawTransaction { private BigInteger value; private String data; - private RawTransaction(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, + protected RawTransaction(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, BigInteger value, String data) { this.nonce = nonce; this.gasPrice = gasPrice; diff --git a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java new file mode 100644 index 000000000..2fcdc0e24 --- /dev/null +++ b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java @@ -0,0 +1,19 @@ +package org.web3j.crypto; + +import java.math.BigInteger; + +public class SignedRawTransaction extends RawTransaction { + + private Sign.SignatureData signatureData; + + public SignedRawTransaction(BigInteger nonce, BigInteger gasPrice, + BigInteger gasLimit, String to, BigInteger value, String data, + Sign.SignatureData signatureData) { + super(nonce, gasPrice, gasLimit, to, value, data); + this.signatureData = signatureData; + } + + public Sign.SignatureData getSignatureData() { + return signatureData; + } +} diff --git a/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java index 06e319a1a..48f2c83b9 100644 --- a/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java +++ b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java @@ -17,10 +17,18 @@ public static RawTransaction decode(String hexTransaction) { BigInteger gasPrice = ((RlpString) values.getValues().get(1)).asBigInteger(); BigInteger gasLimit = ((RlpString) values.getValues().get(2)).asBigInteger(); String to = ((RlpString) values.getValues().get(3)).asString(); - BigInteger value = null; - String data = null; - RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, + BigInteger value = ((RlpString) values.getValues().get(4)).asBigInteger(); + String data = ((RlpString) values.getValues().get(5)).asString(); + if (values.getValues().size() > 6) { + byte v = ((RlpString) values.getValues().get(6)).getBytes()[0]; + byte[] r = ((RlpString) values.getValues().get(7)).getBytes(); + byte[] s = ((RlpString) values.getValues().get(8)).getBytes(); + Sign.SignatureData signatureData = new Sign.SignatureData(v, r, s); + return new SignedRawTransaction(nonce, gasPrice, gasLimit, + to, value, data, signatureData); + } else { + return RawTransaction.createTransaction(nonce, gasPrice, gasLimit, to, value, data); - return rawTransaction; + } } } diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java index 9456081cd..3a4fdbffa 100644 --- a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -8,6 +8,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.web3j.crypto.TransactionEncoder.encode; public class TransactionDecoderTest { @@ -16,10 +18,32 @@ public void testDecoding() throws Exception { BigInteger nonce = BigInteger.ZERO; BigInteger gasPrice = BigInteger.ONE; BigInteger gasLimit = BigInteger.TEN; - String to = "0xadd5355"; + String to = "0x0add5355"; + BigInteger value = BigInteger.valueOf(Long.MAX_VALUE); RawTransaction rawTransaction = RawTransaction.createEtherTransaction( - nonce, gasPrice, gasLimit, to, - BigInteger.valueOf(Long.MAX_VALUE)); + nonce, gasPrice, gasLimit, to, value); + byte[] encodedMessage = TransactionEncoder.encode(rawTransaction); + String hexMessage = Numeric.toHexString(encodedMessage); + + RawTransaction result = TransactionDecoder.decode(hexMessage); + assertNotNull(result); + assertEquals(nonce, result.getNonce()); + assertEquals(gasPrice, result.getGasPrice()); + assertEquals(gasLimit, result.getGasLimit()); + assertEquals(to, result.getTo()); + assertEquals(value, result.getValue()); + assertEquals("", result.getData()); + } + + @Test + public void testDecodingSigned() throws Exception { + BigInteger nonce = BigInteger.ZERO; + BigInteger gasPrice = BigInteger.ONE; + BigInteger gasLimit = BigInteger.TEN; + String to = "0x0add5355"; + BigInteger value = BigInteger.valueOf(Long.MAX_VALUE); + RawTransaction rawTransaction = RawTransaction.createEtherTransaction( + nonce, gasPrice, gasLimit, to, value); byte[] signedMessage = TransactionEncoder.signMessage( rawTransaction, SampleKeys.CREDENTIALS); String hexMessage = Numeric.toHexString(signedMessage); @@ -30,5 +54,14 @@ public void testDecoding() throws Exception { assertEquals(gasPrice, result.getGasPrice()); assertEquals(gasLimit, result.getGasLimit()); assertEquals(to, result.getTo()); + assertEquals(value, result.getValue()); + assertEquals("", result.getData()); + assertTrue(result instanceof SignedRawTransaction); + SignedRawTransaction signedResult = (SignedRawTransaction) result; + assertNotNull(signedResult.getSignatureData()); + Sign.SignatureData signatureData = signedResult.getSignatureData(); + byte[] encodedTransaction = encode(rawTransaction); + BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); + assertEquals(key, SampleKeys.PUBLIC_KEY); } } From 45ea55ad22bf4c5c34531f536b6d792a33fcf8f5 Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Tue, 10 Apr 2018 17:52:03 +0200 Subject: [PATCH 3/6] getFrom --- .../main/java/org/web3j/crypto/SignedRawTransaction.java | 7 +++++++ .../test/java/org/web3j/crypto/TransactionDecoderTest.java | 1 + 2 files changed, 8 insertions(+) diff --git a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java index 2fcdc0e24..964345ee0 100644 --- a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java +++ b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java @@ -1,6 +1,7 @@ package org.web3j.crypto; import java.math.BigInteger; +import java.security.SignatureException; public class SignedRawTransaction extends RawTransaction { @@ -16,4 +17,10 @@ public SignedRawTransaction(BigInteger nonce, BigInteger gasPrice, public Sign.SignatureData getSignatureData() { return signatureData; } + + public String getFrom() throws SignatureException { + byte[] encodedTransaction = TransactionEncoder.encode(this); + BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); + return "0x" + Keys.getAddress(key); + } } diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java index 3a4fdbffa..4500771ba 100644 --- a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -63,5 +63,6 @@ public void testDecodingSigned() throws Exception { byte[] encodedTransaction = encode(rawTransaction); BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); assertEquals(key, SampleKeys.PUBLIC_KEY); + assertEquals(SampleKeys.ADDRESS, signedResult.getFrom()); } } From 0de15d77e0c942b1f85b5c4d1bb92410b0fc08bc Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Tue, 10 Apr 2018 18:00:46 +0200 Subject: [PATCH 4/6] verify --- .../main/java/org/web3j/crypto/SignedRawTransaction.java | 7 +++++++ .../test/java/org/web3j/crypto/TransactionDecoderTest.java | 1 + 2 files changed, 8 insertions(+) diff --git a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java index 964345ee0..4cc92e8d6 100644 --- a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java +++ b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java @@ -23,4 +23,11 @@ public String getFrom() throws SignatureException { BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); return "0x" + Keys.getAddress(key); } + + public void verify(String from) throws SignatureException { + String actualFrom = getFrom(); + if (!actualFrom.equals(from)) { + throw new SignatureException("from mismatch"); + } + } } diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java index 4500771ba..af5c56140 100644 --- a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -64,5 +64,6 @@ public void testDecodingSigned() throws Exception { BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); assertEquals(key, SampleKeys.PUBLIC_KEY); assertEquals(SampleKeys.ADDRESS, signedResult.getFrom()); + signedResult.verify(SampleKeys.ADDRESS); } } From ec22e99f3b83057a5abf9ef91a055abb65b94724 Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Tue, 10 Apr 2018 20:04:42 +0200 Subject: [PATCH 5/6] chain id --- .../web3j/crypto/SignedRawTransaction.java | 38 ++++++++++++++++++- .../web3j/crypto/TransactionDecoderTest.java | 34 ++++++++++++++++- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java index 4cc92e8d6..472b71fd9 100644 --- a/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java +++ b/crypto/src/main/java/org/web3j/crypto/SignedRawTransaction.java @@ -5,6 +5,9 @@ public class SignedRawTransaction extends RawTransaction { + private static final int CHAIN_ID_INC = 35; + private static final int LOWER_REAL_V = 27; + private Sign.SignatureData signatureData; public SignedRawTransaction(BigInteger nonce, BigInteger gasPrice, @@ -19,8 +22,18 @@ public Sign.SignatureData getSignatureData() { } public String getFrom() throws SignatureException { - byte[] encodedTransaction = TransactionEncoder.encode(this); - BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); + Integer chainId = getChainId(); + byte[] encodedTransaction; + if (null == chainId) { + encodedTransaction = TransactionEncoder.encode(this); + } else { + encodedTransaction = TransactionEncoder.encode(this, chainId.byteValue()); + } + byte v = signatureData.getV(); + byte[] r = signatureData.getR(); + byte[] s = signatureData.getS(); + Sign.SignatureData signatureDataV = new Sign.SignatureData(getRealV(v), r, s); + BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureDataV); return "0x" + Keys.getAddress(key); } @@ -30,4 +43,25 @@ public void verify(String from) throws SignatureException { throw new SignatureException("from mismatch"); } } + + private byte getRealV(byte v) { + if (v == LOWER_REAL_V || v == (LOWER_REAL_V + 1)) { + return v; + } + byte realV = LOWER_REAL_V; + int inc = 0; + if ((int) v % 2 == 0) { + inc = 1; + } + return (byte) (realV + inc); + } + + public Integer getChainId() { + byte v = signatureData.getV(); + if (v == LOWER_REAL_V || v == (LOWER_REAL_V + 1)) { + return null; + } + Integer chainId = (v - CHAIN_ID_INC) / 2; + return chainId; + } } diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java index af5c56140..c8ac29571 100644 --- a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -8,8 +8,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.web3j.crypto.TransactionEncoder.encode; public class TransactionDecoderTest { @@ -60,10 +60,40 @@ public void testDecodingSigned() throws Exception { SignedRawTransaction signedResult = (SignedRawTransaction) result; assertNotNull(signedResult.getSignatureData()); Sign.SignatureData signatureData = signedResult.getSignatureData(); - byte[] encodedTransaction = encode(rawTransaction); + byte[] encodedTransaction = TransactionEncoder.encode(rawTransaction); BigInteger key = Sign.signedMessageToKey(encodedTransaction, signatureData); assertEquals(key, SampleKeys.PUBLIC_KEY); assertEquals(SampleKeys.ADDRESS, signedResult.getFrom()); signedResult.verify(SampleKeys.ADDRESS); + assertNull(signedResult.getChainId()); + } + + @Test + public void testDecodingSignedChainId() throws Exception { + BigInteger nonce = BigInteger.ZERO; + BigInteger gasPrice = BigInteger.ONE; + BigInteger gasLimit = BigInteger.TEN; + String to = "0x0add5355"; + BigInteger value = BigInteger.valueOf(Long.MAX_VALUE); + Integer chainId = 1; + RawTransaction rawTransaction = RawTransaction.createEtherTransaction( + nonce, gasPrice, gasLimit, to, value); + byte[] signedMessage = TransactionEncoder.signMessage( + rawTransaction, chainId.byteValue(), SampleKeys.CREDENTIALS); + String hexMessage = Numeric.toHexString(signedMessage); + + RawTransaction result = TransactionDecoder.decode(hexMessage); + assertNotNull(result); + assertEquals(nonce, result.getNonce()); + assertEquals(gasPrice, result.getGasPrice()); + assertEquals(gasLimit, result.getGasLimit()); + assertEquals(to, result.getTo()); + assertEquals(value, result.getValue()); + assertEquals("", result.getData()); + assertTrue(result instanceof SignedRawTransaction); + SignedRawTransaction signedResult = (SignedRawTransaction) result; + assertEquals(SampleKeys.ADDRESS, signedResult.getFrom()); + signedResult.verify(SampleKeys.ADDRESS); + assertEquals(chainId, signedResult.getChainId()); } } From 48e0decb330c80b9cf0f94805bc31e2fcdfdb368 Mon Sep 17 00:00:00 2001 From: Frank Cornelis Date: Tue, 17 Apr 2018 16:34:43 +0200 Subject: [PATCH 6/6] padding fix for r and s --- .../java/org/web3j/crypto/TransactionDecoder.java | 14 ++++++++++++-- .../org/web3j/crypto/TransactionDecoderTest.java | 10 ++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java index 48f2c83b9..231f4b5be 100644 --- a/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java +++ b/crypto/src/main/java/org/web3j/crypto/TransactionDecoder.java @@ -21,8 +21,8 @@ public static RawTransaction decode(String hexTransaction) { String data = ((RlpString) values.getValues().get(5)).asString(); if (values.getValues().size() > 6) { byte v = ((RlpString) values.getValues().get(6)).getBytes()[0]; - byte[] r = ((RlpString) values.getValues().get(7)).getBytes(); - byte[] s = ((RlpString) values.getValues().get(8)).getBytes(); + byte[] r = zeroPadded(((RlpString) values.getValues().get(7)).getBytes(), 32); + byte[] s = zeroPadded(((RlpString) values.getValues().get(8)).getBytes(), 32); Sign.SignatureData signatureData = new Sign.SignatureData(v, r, s); return new SignedRawTransaction(nonce, gasPrice, gasLimit, to, value, data, signatureData); @@ -31,4 +31,14 @@ public static RawTransaction decode(String hexTransaction) { gasPrice, gasLimit, to, value, data); } } + + private static byte[] zeroPadded(byte[] value, int size) { + if (value.length == size) { + return value; + } + int diff = size - value.length; + byte[] paddedValue = new byte[size]; + System.arraycopy(value, 0, paddedValue, diff, value.length); + return paddedValue; + } } diff --git a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java index c8ac29571..7e0414cc4 100644 --- a/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java +++ b/crypto/src/test/java/org/web3j/crypto/TransactionDecoderTest.java @@ -96,4 +96,14 @@ public void testDecodingSignedChainId() throws Exception { signedResult.verify(SampleKeys.ADDRESS); assertEquals(chainId, signedResult.getChainId()); } + + @Test + public void testRSize31() throws Exception { + //CHECKSTYLE:OFF + String hexTransaction = "0xf883370183419ce09433c98f20dd73d7bb1d533c4aa3371f2b30c6ebde80a45093dc7d00000000000000000000000000000000000000000000000000000000000000351c9fb90996c836fb34b782ee3d6efa9e2c79a75b277c014e353b51b23b00524d2da07435ebebca627a51a863bf590aff911c4746ab8386a0477c8221bb89671a5d58"; + //CHECKSTYLE:ON + RawTransaction result = TransactionDecoder.decode(hexTransaction); + SignedRawTransaction signedResult = (SignedRawTransaction) result; + assertEquals("0x1b609b03e2e9b0275a61fa5c69a8f32550285536", signedResult.getFrom()); + } }