Пример #1
0
        // 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);
        }
Пример #2
0
        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));
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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));
        }
Пример #5
0
        /// <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)));
        }
Пример #6
0
        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));
        }
Пример #7
0
        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))));
        }
Пример #8
0
        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));
        }
Пример #9
0
        /// <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)));
        }
Пример #10
0
        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));
        }
Пример #11
0
        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));
        }
Пример #12
0
        public byte[] Serialize()
        {
            var tx = new byte[][]
            {
                ByteManipulator.GetBytes(Nonce),
                Ammount.GetBytes(),
                Fee.GetBytes(),
                Source,
                Destination,
                Signature,
                Network
            };

            return(RLP.Encode(tx));
        }
Пример #13
0
        // 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));
        }
Пример #14
0
        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);
        }
Пример #15
0
        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 }));
        }
Пример #16
0
        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);
            }
        }
Пример #17
0
        /// <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);
        }
Пример #18
0
        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();
        }
Пример #19
0
        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();
        }
Пример #20
0
        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]);
                }
            }
        }
Пример #21
0
        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));
        }
Пример #22
0
 public byte[] GetMiningHash()
 {
     return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize(ExtraData, null, null))));
 }
Пример #23
0
 public byte[] GetSigningHash()
 {
     return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize(null, MixHash, Nonce))));
 }
Пример #24
0
 public byte[] GetHash()
 {
     return(KeccakHash.ComputeHashBytes(RLP.Encode(Serialize())));
 }
Пример #25
0
 public void ImplicitEncoding_NegativeInt()
 {
     Assert.ThrowsAny <Exception>(() => RLP.Encode(-1234));
 }