// RLP encoding/decoding trie nodes /// <summary> /// Given a trie node, encodes it into an RLP item such that if it is 32 bytes or less encoded, it is directly included, otherwise it will be a 32 byte reference to the data. /// </summary> /// <param name="node">The node to encode into an RLP item for storage in the trie.</param> /// <returns>Returns the RLP encoded trie node as it should be represented in our trie efficienctly.</returns> private RLPItem EncodeNode(RLPList node) { // If it's a blank node, we return blank. if (node == null || node.Items.Count == 0) { return(BLANK_NODE); } // Obtain our node type TrieNodeType type = GetNodeType(node); byte[] encoded = RLP.Encode(node); // If our RLP encoded node is less than 32 bytes, we'll include the node directly as an RLP list. if (encoded.Length < 32) { return(node); } // Otherwise if the data is 32 bytes or longer, we encode it as an RLP byte array with the hash to the node in the database. // Get our hash key byte[] hashKey = KeccakHash.ComputeHashBytes(encoded); // Set in our database. Database.Set(hashKey, encoded); // Return as an RLP byte array featuring the lookup hash/key for the encoded node. return(hashKey); }
public void RLPLongerStringList() { // Source of test data: http://hidskes.com/blog/2014/04/02/ethereum-building-blocks-part-1-rlp/ byte[] expected = new byte[] { 248, 144, 152, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 118, 101, 114, 121, 32, 108, 111, 110, 103, 32, 108, 105, 115, 116, 158, 121, 111, 117, 32, 110, 101, 118, 101, 114, 32, 103, 117, 101, 115, 115, 32, 104, 111, 119, 32, 108, 111, 110, 103, 32, 105, 116, 32, 105, 115, 169, 105, 110, 100, 101, 101, 100, 44, 32, 104, 111, 119, 32, 100, 105, 100, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 105, 116, 32, 119, 97, 115, 32, 116, 104, 105, 115, 32, 108, 111, 110, 103, 173, 103, 111, 111, 100, 32, 106, 111, 98, 44, 32, 116, 104, 97, 116, 32, 73, 32, 99, 97, 110, 32, 116, 101, 108, 108, 32, 121, 111, 117, 32, 105, 110, 32, 104, 111, 110, 101, 115, 116, 108, 121, 121, 121, 121, 121 }; byte[] result = RLP.Encode(new RLPList( "this is a very long list", "you never guess how long it is", "indeed, how did you know it was this long", "good job, that I can tell you in honestlyyyyy")); Assert.True(expected.ValuesEqual(result)); }
/// <summary> /// Signs transaction data and returns the raw byte array. Typically used for eth_sendRawTransaction. /// </summary> public static byte[] SignRawTransaction(EthereumEcdsa privateKey, BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, Address?to, BigInteger value, byte[] data, uint?chainID) { var sig = Sign(privateKey, nonce, gasPrice, gasLimit, to, value, data, chainID); var serialized = Serialize(sig.V, sig.R, sig.S, nonce, gasPrice, gasLimit, to, value, data); byte[] bytes = RLP.Encode(serialized); return(bytes); }
public static Address MakeContractAddress(Address sender, BigInteger nonce) { // Create an RLP list with the address and nonce RLPList list = new RLPList(RLP.FromInteger(sender, ADDRESS_SIZE), RLP.FromInteger(nonce)); var hash = KeccakHash.ComputeHash(RLP.Encode(list)).Slice(EVMDefinitions.WORD_SIZE - ADDRESS_SIZE); return(new Address(hash)); }
/// <summary> /// Given a node, duplicates it such that it is structurally the same, yet is a different object instance. /// </summary> /// <param name="node">The node to duplicate.</param> /// <returns>Returns a duplicate of the provided node.</returns> private RLPList NodeDuplicate(RLPList node) { // If the node is null, we return null. if (node == null) { return(null); } // Otherwise we serialize and deserialize it to clone it. return((RLPList)RLP.Decode(RLP.Encode(node))); }
public void TransactionRLPAndVerify() { // Verifies our RLP decoding works, and we can recover the public key/sender from the transaction. byte[] rlpEncodedTransaction = "f86a15850430e23400830186a094a593094cebb06bf34df7311845c2a34996b5232485e8d4a510008026a0a003ddf704feb0c62aba5459ad0af698eab974b0fe9c3685426bde2f31669252a05625a814b54f7f994faf5747eae956dbf5c85e4649022b22b9512a74c41e92f4".HexToBytes(); Transaction transaction = new Transaction(RLP.Decode(rlpEncodedTransaction)); Assert.Equal("0x82bd8ead9cfbf50d35f9c3ab75f994a59e6c3317", transaction.GetSenderAddress().ToString()); // Verifies our rlp reencoded exactly as intended. byte[] rlpReencodedTransaction = RLP.Encode(transaction.Serialize()); Assert.True(rlpEncodedTransaction.ValuesEqual(rlpReencodedTransaction)); }
public static byte[] GetUnsignedHash(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, Address?to, BigInteger value, byte[] data, uint?chainID) { // Spurious Dragon introduced an update to deter replay attacks where v = CHAIN_ID * 2 + 35 or v = CHAIN_ID * 2 + 36. if (chainID != null) { // Ethereum uses this to deter replay attacks by embedding the network/chain ID in the hashed data. return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize((byte)chainID, 0, 0, nonce, gasPrice, gasLimit, to, value, data)))); // we serialize with our network ID. } // Pre-Spurious Dragon, we simply hash all main properties except v, r, s. return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize(null, null, null, nonce, gasPrice, gasLimit, to, value, data)))); }
public void UpdateUnclesHash(BlockHeader[] uncles) { // We create an RLP list with all of our uncle block headers RLPList rlpUncles = new RLPList(); foreach (BlockHeader uncleHeader in uncles) { rlpUncles.Items.Add(uncleHeader.Serialize()); } // RLP encode our uncles and hash them UnclesHash = KeccakHash.ComputeHashBytes(RLP.Encode(rlpUncles)); }
/// <summary> /// Calculates the hash for the RLP encoded uncle array. /// </summary> /// <returns>Returns the hash of the RLP encoded uncle array.</returns> public byte[] CalculateUnclesHash() { // We create an RLP list with all of our uncle block headers RLPList rlpUncles = new RLPList(); foreach (BlockHeader uncleHeader in Uncles) { rlpUncles.Items.Add(uncleHeader.Serialize()); } // RLP encode our uncles and hash them return(KeccakHash.ComputeHashBytes(RLP.Encode(rlpUncles))); }
public void RLPBasicStringList() { // Source of test data: http://hidskes.com/blog/2014/04/02/ethereum-building-blocks-part-1-rlp/ byte[] expected = new byte[] { 200, 131, 99, 97, 116, 131, 100, 111, 103 }; byte[] result = RLP.Encode(new RLPList(new List <RLPItem>() { new RLPByteArray(System.Text.ASCIIEncoding.ASCII.GetBytes("cat")), new RLPByteArray(System.Text.ASCIIEncoding.ASCII.GetBytes("dog")) })); Assert.True(expected.ValuesEqual(result)); }
public override byte[] Serialize() { // Verify our underlying properties VerifyProperties(); // Create an RLP item to contain all of our data RLPList rlpList = new RLPList(); rlpList.Items.Add(EphemeralPublicKey); rlpList.Items.Add(Nonce); rlpList.Items.Add(RLP.FromInteger(Version, 32, true)); // Serialize our RLP data return(RLP.Encode(rlpList)); }
public byte[] Serialize() { var tx = new byte[][] { ByteManipulator.GetBytes(Nonce), Ammount.GetBytes(), Fee.GetBytes(), Source, Destination, Signature, Network }; return(RLP.Encode(tx)); }
// Underlying trie implementation / helpers /// <summary> /// Checks if two given nodes are equal in structure. /// </summary> /// <param name="first">The first node to check structural equality of.</param> /// <param name="second">The second node to check structural equality of.</param> /// <returns>Returns a boolean indicating if the provided nodes are equal in structure and underlying values.</returns> private bool NodeEquals(RLPList first, RLPList second) { // If both are null, they're equal. If only one is, they aren't. if (first == null && second == null) { return(true); } else if (first == null || second == null) { return(false); } // Otherwise we treat it as a real node, encode, and compare. byte[] encodedFirst = RLP.Encode(first); byte[] encodedSecond = RLP.Encode(second); return(encodedFirst.ValuesEqual(encodedSecond)); }
public void ImplicitEncoding() { #pragma warning disable SA1114 // Parameter list should follow declaration #pragma warning disable SA1115 // Parameter should follow comma #pragma warning disable CA1825 // Avoid zero-length array allocations. #pragma warning disable SA1118 // Parameter should not span multiple lines #pragma warning disable SA1111 // Closing parenthesis should be on line of last parameter #pragma warning disable SA1009 // Closing parenthesis should be spaced correctly var item = RLP.Encode( // string "First item", // byte array "0x7cafb9c3de0fd02142754ce648ba7db04e4c161e".HexToBytes(), // single byte (byte)0xf5, // integer 2147483648, // empty array new RLPItem[] { }, // array of mixed types new RLPItem[] { "hello world", 123456 } ); #pragma warning restore SA1114 // Parameter list should follow declaration #pragma warning restore SA1115 // Parameter should follow comma #pragma warning restore CA1825 // Avoid zero-length array allocations. #pragma warning restore SA1118 // Parameter should not span multiple lines #pragma warning restore SA1111 // Closing parenthesis should be on line of last parameter #pragma warning restore SA1009 // Closing parenthesis should be spaced correctly var result = item.ToHexString(hexPrefix: true); var expected = "0xf8398a4669727374206974656d947cafb9c3de0fd02142754ce648ba7db04e4c161e81f58480000000c0d08b68656c6c6f20776f726c648301e240"; Assert.Equal(expected, result); }
public void RLPLogTest() { Meadow.EVM.Data_Types.Transactions.Log log = new Meadow.EVM.Data_Types.Transactions.Log((BigInteger)0x11223344, new List <BigInteger>() { 3, 2, 1 }, new byte[] { 00, 77, 00, 77 }); RLPItem item = log.Serialize(); byte[] data = RLP.Encode(item); item = RLP.Decode(data); log.Deserialize(item); item = log.Serialize(); byte[] data2 = RLP.Encode(item); Assert.True(data.ValuesEqual(data2)); Assert.Equal(0x11223344, (BigInteger)log.Address); Assert.True(log.Topics.Count == 3 && log.Topics[0] == 3 && log.Topics[1] == 2 && log.Topics[2] == 1); Assert.True(log.Data.ValuesEqual(new byte[] { 00, 77, 00, 77 })); }
private void RLPStringEncodeDecodeTest(string s) { RLPItem s1 = s; byte[] encoded = RLP.Encode(s); RLPItem s2 = RLP.Decode(encoded); string ss1 = s1; string ss2 = s2; if (s.Length == 0) { Assert.Null((string)s2); } else { Assert.Equal((string)s1, (string)s2); } }
/// <summary> /// Recalculates the root node hash and sets it in the database accordingly. /// </summary> private void RehashRootNode() { // If our root node is null, we set the hash as the blank node hash, and exit. if (RootNode == null) { RootNodeHash = BLANK_NODE_HASH; return; } // Otherwise we get our value, and calculate our key (the hash of the value) byte[] value = RLP.Encode(RootNode); byte[] key = KeccakHash.ComputeHashBytes(value); // Update our root hash. RootNodeHash = key; // Set our value in our database. Database.Set(key, value); }
private void EncodeMessage() { var code = RLP.Encode(((int)this.MessageCode).ToBytes()); var version = RLP.Encode(this.p2pVersion.ToBytes()); var client = RLP.Encode(this.clientId.ToBytes()); //var capabilities = new List<dynamic>(this.supportedCapabilities.Count); //capabilities.AddRange(this.supportedCapabilities.Select(capability => new List<string> // { // capability.Name, // capability.Version.ToString(CultureInfo.InvariantCulture) // })); //var capabilities = new byte[this.supportedCapabilities.Count][]; //for (var i = 0; i < this.supportedCapabilities.Count(); i++) //{ // var capability = this.supportedCapabilities[i]; // capabilities[i] = RLP.Encode(new List<dynamic> // { // capability.Name, // capability.Version.ToString(CultureInfo.InvariantCulture) // }); //} //var caps = RLP.Encode(capabilities); var port = RLP.Encode(this.defaultPort.ToBytes()); var peer = RLP.Encode(this.peerId.ToBytes()); this.encodedMessage = new List <byte[]> { code, version, client, //caps, port, peer }.SelectMany(x => x).ToArray(); }
public void CommitStorageChanges() { // For each storage cache item, we want to flush those changes to the main trie/database. foreach (var key in StorageCache.Keys) { // If the value is null, it means the value is non existent anymore, so we remove the key value pair if (StorageCache[key] == null) { StorageTrie.Remove(key); } else { // Otherwise we set the new value. StorageTrie.Set(key, RLP.Encode(StorageCache[key])); } } // Now we clear our cache. StorageCache.Clear(); // And update our account's storage root hash. StorageRoot = StorageTrie.GetRootNodeHash(); }
private void RLPListEncodeDecodeTest(int items) { RLPList list = new RLPList(); for (int i = 0; i < items; i++) { if (i % 2 == 0) { list.Items.Add(new byte[] { (byte)(i % 256) }); } else { list.Items.Add(new RLPList()); } } byte[] encoded = RLP.Encode(list); RLPList list2 = (RLPList)RLP.Decode(encoded); Assert.Equal(list.Items.Count, list2.Items.Count); for (int i = 0; i < list.Items.Count; i++) { if (i % 2 == 0) { Assert.IsType <RLPByteArray>(list2.Items[i]); RLPByteArray b1 = ((RLPByteArray)list.Items[i]); RLPByteArray b2 = ((RLPByteArray)list2.Items[i]); Assert.True(MemoryExtensions.SequenceEqual(b1.Data.Span, b2.Data.Span)); } else { Assert.IsType <RLPList>(list2.Items[i]); } } }
public byte[] Serialize() { var transactionByteList = new List <byte[]>(); foreach (var transaction in Transactions) { transactionByteList.Add(transaction.Serialize()); } var serializedTransactions = RLP.Encode(transactionByteList); var block = new byte[][] { ByteManipulator.GetBytes((uint)Height), ByteManipulator.GetBytes(Timestamp), Difficulty.GetBytes(), Nonce, MinerAddress, PreviousBlockHash, serializedTransactions }; return(RLP.Encode(block)); }
public byte[] GetMiningHash() { return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize(ExtraData, null, null)))); }
public byte[] GetSigningHash() { return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize(null, MixHash, Nonce)))); }
public byte[] GetHash() { return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize()))); }
public void ImplicitEncoding_NegativeInt() { Assert.ThrowsAny <Exception>(() => RLP.Encode(-1234)); }