예제 #1
0
        public override void Decode(ref AbiDecodeBuffer buff, out bool val)
        {
            // Input data validity check: last byte should be either 0 or 1.
            switch (buff.HeadCursor[31])
            {
            case 0:
                val = false;
                break;

            case 1:
                val = true;
                break;

            default:
                throw Error(buff.HeadCursor);
            }

#if ZERO_BYTE_CHECKS
            // Input data validity check: all but the last byte should be zero.
            // Span<byte>.SequenceEquals should use the fast native memory slab comparer.
            if (!buff.HeadCursor.Slice(0, UInt256.SIZE - 1).SequenceEqual(ZEROx31))
            {
                throw Error(buff.HeadCursor.Slice(0, UInt256.SIZE - 1));
            }
#endif

            buff.IncrementHeadCursor(UInt256.SIZE);

            Exception Error(ReadOnlySpan <byte> payload)
            {
                return(new ArgumentException("Invalid boolean input data; should be 31 zeros followed by a 1 or 0; received: " + payload.Slice(0, UInt256.SIZE).ToHexString()));
            }
        }
예제 #2
0
        public override void Decode(ref AbiDecodeBuffer buff, out string val)
        {
            var uintEncoder = UInt256Encoder.UncheckedEncoders.Get();

            try
            {
                // Read the next header int which is the offset to the start of the data
                // in the data payload area.
                uintEncoder.Decode(buff.HeadCursor, out int startingPosition);

                // The first int in our offset of data area is the length of the rest of the payload.
                var encodedLength = buff.Buffer.Slice(startingPosition, UInt256.SIZE);
                uintEncoder.Decode(encodedLength, out int byteLen);

                // Read the actual payload from the data area
                var encodedString = buff.Buffer.Slice(startingPosition + UInt256.SIZE, byteLen);
                var bytes         = new byte[byteLen];
                encodedString.CopyTo(bytes);
                val = UTF8.GetString(bytes);
                int bodyLen = PadLength(bytes.Length, UInt256.SIZE);

                buff.IncrementHeadCursor(UInt256.SIZE);
            }
            finally
            {
                UInt256Encoder.UncheckedEncoders.Put(uintEncoder);
            }
        }
예제 #3
0
        public void Decode(ref AbiDecodeBuffer buff, out TItem[] val)
        {
            var uintEncoder = UInt256Encoder.UncheckedEncoders.Get();

            try
            {
                // Read the next header int which is the offset to the start of the data
                // in the data payload area.
                uintEncoder.Decode(buff.HeadCursor, out int startingPosition);

                // The first int in our offset of data area is the length of the rest of the payload.
                var encodedLength = buff.Buffer.Slice(startingPosition, UInt256.SIZE);
                uintEncoder.Decode(encodedLength, out int itemCount);

                var payloadOffset = startingPosition + UInt256.SIZE;
                var payload       = buff.Buffer.Slice(payloadOffset, buff.Buffer.Length - payloadOffset);
                var payloadBuffer = new AbiDecodeBuffer(payload, Enumerable.Repeat(_info.ArrayItemInfo, itemCount).ToArray());
                var items         = new TItem[itemCount];
                for (var i = 0; i < itemCount; i++)
                {
                    _itemEncoder.Decode(ref payloadBuffer, out var item);
                    items[i] = item;
                }

                val = items;

                buff.IncrementHeadCursor(UInt256.SIZE);
            }
            finally
            {
                UInt256Encoder.UncheckedEncoders.Put(uintEncoder);
            }
        }
예제 #4
0
        public void Int24_2()
        {
            var encodedNum = "0000000000000000000000000000000000000000000000000000000000fed260";
            var buff       = new AbiDecodeBuffer(encodedNum, "int24");

            DecoderFactory.Decode("int24", ref buff, out int result);
            Assert.Equal(0, buff.HeadCursor.Length);
            Assert.Equal(-77216, result);
        }
예제 #5
0
        public void StringUnicode()
        {
            var encodedStr = "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028757466383b20342062797465733a20f0a0beb43b20332062797465733a20e28fb020776f726b7321000000000000000000000000000000000000000000000000";
            var buff       = new AbiDecodeBuffer(encodedStr, "string");

            DecoderFactory.Decode("string", ref buff, out string result);
            Assert.Equal(0, buff.HeadCursor.Length);
            Assert.Equal("utf8; 4 bytes: 𠾴; 3 bytes: ⏰ works!", result);
        }
예제 #6
0
        public void String()
        {
            var encodedStr = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000";
            var buff       = new AbiDecodeBuffer(encodedStr, "bool");

            DecoderFactory.Decode("string", ref buff, out string result);
            Assert.Equal(0, buff.HeadCursor.Length);
            Assert.Equal("Hello, world!", result);
        }
예제 #7
0
        public void Address()
        {
            var encodedAddr = "00000000000000000000000011f4d0a3c12e86b4b5f39b213f7e19d048276dae";
            var buff        = new AbiDecodeBuffer(encodedAddr, "address");

            DecoderFactory.Decode("address", ref buff, out Address address);
            Assert.Equal(0, buff.HeadCursor.Length);
            Assert.Equal("0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe".ToLowerInvariant(), address.ToString());
        }
예제 #8
0
        public void Boolean_False()
        {
            var encodedFalse = "0000000000000000000000000000000000000000000000000000000000000000";
            var buff         = new AbiDecodeBuffer(encodedFalse, "bool");

            DecoderFactory.Decode("bool", ref buff, out bool decodedFalse);
            Assert.Equal(0, buff.HeadCursor.Length);
            Assert.False(decodedFalse);
        }
예제 #9
0
        public void Int64FixedArray()
        {
            var encodedArr = "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000011c20000000000000000000000000000000000000000000000007fffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fffffffffffffff";
            var buff       = new AbiDecodeBuffer(encodedArr, "int64[5]");

            DecoderFactory.Decode("int64[5]", ref buff, out long[] result, EncoderFactory.LoadEncoder("int64", default(long)));
            Assert.Equal(0, buff.HeadCursor.Length);
            long[] expected = new long[] { 1, 4546, long.MaxValue, 0, long.MaxValue };
            Assert.Equal(expected, result);
        }
예제 #10
0
        public void UInt8FixedArray()
        {
            var encodedArr = "00000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000e70000000000000000000000000000000000000000000000000000000000000046";
            var buff       = new AbiDecodeBuffer(encodedArr, "uint8[5]");

            DecoderFactory.Decode("uint8[5]", ref buff, out byte[] result, EncoderFactory.LoadEncoder("uint8", default(byte)));
            Assert.Equal(0, buff.HeadCursor.Length);
            byte[] expected = HexUtil.HexToBytes("072696e746");
            Assert.Equal(expected, result);
        }
예제 #11
0
        public void UInt32()
        {
            var encodedNum = "00000000000000000000000000000000000000000000000000000000ffff5544";
            var buff       = new AbiDecodeBuffer(encodedNum, "uint32");

            DecoderFactory.Decode("uint32", ref buff, out uint result);
            Assert.Equal(0, buff.HeadCursor.Length);
            uint expected = 4294923588;

            Assert.Equal(expected, result);
        }
예제 #12
0
        public void UInt24()
        {
            var encodedNum = "0000000000000000000000000000000000000000000000000000000000005ba0";
            var buff       = new AbiDecodeBuffer(encodedNum, "uint24");

            DecoderFactory.Decode("uint24", ref buff, out uint result);
            Assert.Equal(0, buff.HeadCursor.Length);
            uint expected = 23456;

            Assert.Equal(expected, result);
        }
예제 #13
0
        public void Int56()
        {
            var encodedNum = "00000000000000000000000000000000000000000000000000ffffffffffd492";
            var buff       = new AbiDecodeBuffer(encodedNum, "int56");

            DecoderFactory.Decode("int56", ref buff, out long result);
            Assert.Equal(0, buff.HeadCursor.Length);
            var expected = (long)-11118;

            Assert.Equal(expected, result);
        }
예제 #14
0
        public void Bytes_M()
        {
            var encodedBytes22 = "072696e74657220746f6f6b20612067616c6c657920600000000000000000000";
            var buff           = new AbiDecodeBuffer(encodedBytes22, "bytes22");

            DecoderFactory.Decode("bytes22", ref buff, out byte[] result);
            Assert.Equal(0, buff.HeadCursor.Length);

            byte[] expected = HexUtil.HexToBytes("072696e74657220746f6f6b20612067616c6c6579206");
            Assert.Equal(expected, result);
        }
예제 #15
0
        public void Bytes()
        {
            var encodedBytes = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003d207072696e74657220746f6f6b20612067616c6c6579206f66207479706520616e6420736372616d626c656420697420746f206d616b65206120747970000000";
            var buff         = new AbiDecodeBuffer(encodedBytes, "bytes");

            DecoderFactory.Decode("bytes", ref buff, out byte[] result);
            Assert.Equal(0, buff.HeadCursor.Length);

            byte[] expected = "207072696e74657220746f6f6b20612067616c6c6579206f66207479706520616e6420736372616d626c656420697420746f206d616b65206120747970".HexToBytes();
            Assert.Equal(expected, result);
        }
예제 #16
0
        public override void Decode(ref AbiDecodeBuffer buff, out Address val)
        {
#if ZERO_BYTE_CHECKS
            // data validity check: 20 address bytes should be left-padded with 12 zero-bytes
            if (!buff.HeadCursor.Slice(0, 12).SequenceEqual(ZEROx12))
            {
                throw new ArgumentException("Invalid address input data; should be 20 address bytes, left-padded with 12 zero-bytes; received: " + buff.HeadCursor.Slice(0, UInt256.SIZE).ToHexString());
            }
#endif
            val = MemoryMarshal.Read <Address>(buff.HeadCursor.Slice(12));
            buff.IncrementHeadCursor(UInt256.SIZE);
        }
예제 #17
0
        public void DecodeObject(ref AbiDecodeBuffer buff, out object val)
        {
            var items = new object[TypeInfo.ArrayLength];

            for (var i = 0; i < items.Length; i++)
            {
                _itemEncoder.DecodeObject(ref buff, out var item);
                items[i] = item;
            }

            val = items;
        }
예제 #18
0
        public override void Decode(ref AbiDecodeBuffer buff, out IEnumerable <TItem> val)
        {
            var items = new TItem[_info.ArrayLength];

            for (var i = 0; i < items.Length; i++)
            {
                _itemEncoder.Decode(ref buff, out var item);
                items[i] = item;
            }

            val = items;
        }
예제 #19
0
        public void Boolean_BadInput_2()
        {
            var encodedTrue = "0000000000000000000000000000000000000000000000000000000000000002";
            var buff        = new AbiDecodeBuffer(encodedTrue, "bool");

            try
            {
                DecoderFactory.Decode("bool", ref buff, out bool val);
                throw null;
            }
            catch (ArgumentException) { }
        }
예제 #20
0
        public void Bytes_BadInput_BadLengthPrefix()
        {
            var encodedBytes = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000010000000000000000000003d207072696e74657220746f6f6b20612067616c6c6579206f66207479706520616e6420736372616d626c656420697420746f206d616b65206120747970000000";
            var buff         = new AbiDecodeBuffer(encodedBytes, "bytes");

            try
            {
                DecoderFactory.Decode("bytes", ref buff, out byte[] result);
                throw null;
            }
            catch (ArgumentException) { }
            catch (OverflowException) { }
        }
예제 #21
0
        public void String_BadInput_BadLengthPrefix()
        {
            var encodedBytes = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000060000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000";
            var buff         = new AbiDecodeBuffer(encodedBytes, "bytes");

            try
            {
                DecoderFactory.Decode("bytes", ref buff, out byte[] result);
                throw null;
            }
            catch (ArgumentException) { }
            catch (OverflowException) { }
        }
예제 #22
0
        public void Decode(ref AbiDecodeBuffer buff, out TItem[] val)
        {
            if (_info.ArrayDimensionSizes.Length != 1)
            {
                throw new NotImplementedException();
            }

            var items = new TItem[_info.ArrayDimensionSizes[0]];

            for (var i = 0; i < items.Length; i++)
            {
                _itemEncoder.Decode(ref buff, out var item);
                items[i] = item;
            }

            val = items;
        }
예제 #23
0
            public HelloEvent(Meadow.JsonRpc.Types.FilterLogObject log) : base(log)
            {
                // Decode the log topic args.
                Span <byte> topicBytes = MemoryMarshal.AsBytes(new Span <Meadow.Core.EthTypes.Data>(log.Topics).Slice(1));

                AbiTypeInfo[] topicTypes = Array.Empty <AbiTypeInfo>();
                var           topicBuff  = new AbiDecodeBuffer(topicBytes, topicTypes);
                // Decode the log data args.
                Span <byte> dataBytes = log.Data;

                AbiTypeInfo[] dataTypes = new AbiTypeInfo[] { "string", "address" };
                var           dataBuff  = new AbiDecodeBuffer(dataBytes, dataTypes);

                DecoderFactory.Decode(dataTypes[0], ref dataBuff, out _message);
                DecoderFactory.Decode(dataTypes[1], ref dataBuff, out _sender);
                // Add all the log args and their metadata to a collection that can be checked at runtime.
                LogArgs = new(string Name, string Type, bool Indexed, object Value)[] { ("_message", "string", false, _message), ("_sender", "address", false, _sender) };
예제 #24
0
            public Transfer(Meadow.JsonRpc.Types.FilterLogObject log) : base(log)
            {
                // Decode the log topic args.
                Span <byte> topicBytes = MemoryMarshal.AsBytes(new Span <Meadow.Core.EthTypes.Data>(log.Topics).Slice(1));

                AbiTypeInfo[] topicTypes = new AbiTypeInfo[] { "address", "address" };
                var           topicBuff  = new AbiDecodeBuffer(topicBytes, topicTypes);

                DecoderFactory.Decode(topicTypes[0], ref topicBuff, out from);
                DecoderFactory.Decode(topicTypes[1], ref topicBuff, out to);
                // Decode the log data args.
                Span <byte> dataBytes = log.Data;

                AbiTypeInfo[] dataTypes = new AbiTypeInfo[] { "uint256" };
                var           dataBuff  = new AbiDecodeBuffer(dataBytes, dataTypes);

                DecoderFactory.Decode(dataTypes[0], ref dataBuff, out tokens);
                // Add all the log args and their metadata to a collection that can be checked at runtime.
                LogArgs = new(string Name, string Type, bool Indexed, object Value)[] { ("from", "address", true, from), ("to", "address", true, to), ("tokens", "uint256", false, tokens) };
예제 #25
0
        public void FunctionData_MultipleStringParams()
        {
            var strP1 = "first string";
            var strP2 = "asdf";
            var strP3 = "utf8; 4 bytes: 𠾴; 3 bytes: ⏰ works!";

            var encoded = "000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c666972737420737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000461736466000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028757466383b20342062797465733a20f0a0beb43b20332062797465733a20e28fb020776f726b7321000000000000000000000000000000000000000000000000";

            AbiDecodeBuffer buff = new AbiDecodeBuffer(encoded, "string", "string", "string");

            DecoderFactory.Decode("string", ref buff, out string ru1);
            Assert.Equal(strP1, ru1);

            DecoderFactory.Decode("string", ref buff, out string ru2);
            Assert.Equal(strP2, ru2);

            DecoderFactory.Decode("string", ref buff, out string ru3);
            Assert.Equal(strP3, ru3);
        }
            public LogAccess(Meadow.JsonRpc.Types.FilterLogObject log) : base(log)
            {
                // Decode the log topic args.
                Span <byte> topicBytes = MemoryMarshal.AsBytes(new Span <Meadow.Core.EthTypes.Data>(log.Topics).Slice(1));

                AbiTypeInfo[] topicTypes = new AbiTypeInfo[] { "address", "uint256" };
                var           topicBuff  = new AbiDecodeBuffer(topicBytes, topicTypes);

                DecoderFactory.Decode(topicTypes[0], ref topicBuff, out by);
                DecoderFactory.Decode(topicTypes[1], ref topicBuff, out accessTime);
                // Decode the log data args.
                Span <byte> dataBytes = log.Data;

                AbiTypeInfo[] dataTypes = new AbiTypeInfo[] { "string", "string" };
                var           dataBuff  = new AbiDecodeBuffer(dataBytes, dataTypes);

                DecoderFactory.Decode(dataTypes[0], ref dataBuff, out method);
                DecoderFactory.Decode(dataTypes[1], ref dataBuff, out desc);
                // Add all the log args and their metadata to a collection that can be checked at runtime.
                LogArgs = new(string Name, string Type, bool Indexed, object Value)[] { ("by", "address", true, by), ("accessTime", "uint256", true, accessTime), ("method", "string", false, method), ("desc", "string", false, desc) };
예제 #27
0
        public override void Decode(ref AbiDecodeBuffer buff, out IEnumerable <byte> val)
        {
            var uintEncoder = UInt256Encoder.UncheckedEncoders.Get();

            try
            {
                // Read the next header int which is the offset to the start of the data
                // in the data payload area.
                uintEncoder.Decode(buff.HeadCursor, out int startingPosition);

                // The first int in our offset of data area is the length of the rest of the payload.
                var encodedLength = buff.Buffer.Slice(startingPosition, UInt256.SIZE);
                uintEncoder.Decode(encodedLength, out int byteLen);

                // Read the actual payload from the data area
                var payloadOffset = startingPosition + UInt256.SIZE;
                var payload       = buff.Buffer.Slice(payloadOffset, byteLen);
                var bytes         = payload.ToArray();
                int bodyLen       = PadLength(bytes.Length, UInt256.SIZE);
                val = bytes;

#if ZERO_BYTE_CHECKS
                // data validity check: should be right-padded with zero bytes
                for (var i = payloadOffset + byteLen; i < payloadOffset + bodyLen; i++)
                {
                    if (buff.Buffer[i] != 0)
                    {
                        throw new ArgumentException($"Invalid bytes input data; should be {bytes.Length} bytes of data followed by {bodyLen - bytes.Length} zero-bytes");
                    }
                }
#endif

                buff.IncrementHeadCursor(UInt256.SIZE);
            }
            finally
            {
                UInt256Encoder.UncheckedEncoders.Put(uintEncoder);
            }
        }
예제 #28
0
        public override void Decode(ref AbiDecodeBuffer buff, out IEnumerable <byte> val)
        {
            var bytes = new byte[_info.ArrayLength];

            for (var i = 0; i < bytes.Length; i++)
            {
                bytes[i] = buff.HeadCursor[i];
            }

#if ZERO_BYTE_CHECKS
            // data validity check: all bytes after the fixed M amount should be zero
            for (var i = bytes.Length; i < UInt256.SIZE; i++)
            {
                if (buff.HeadCursor[i] != 0)
                {
                    throw new ArgumentException($"Invalid {_info.SolidityName} input data; should be {_info.ArrayLength} bytes padded {UInt256.SIZE - _info.ArrayLength} zero-bytes; received: " + buff.HeadCursor.Slice(0, 32).ToHexString());
                }
            }
#endif

            val = bytes;
            buff.IncrementHeadCursor(UInt256.SIZE);
        }
예제 #29
0
        public void Int56Random()
        {
            var rand         = new Random();
            var int56Encoder = EncoderFactory.LoadEncoder("int56", default(long));

            for (var i = 0; i < 50_000; i++)
            {
                byte[]      num   = new byte[32];
                Span <byte> bytes = num;
                Span <long> view  = MemoryMarshal.Cast <byte, long>(bytes);

                byte[] tmp = new byte[7];
                rand.NextBytes(tmp);
                tmp.CopyTo(num, 25);

                var buff = new AbiDecodeBuffer(bytes, "int56");
                int56Encoder.Decode(ref buff, out var result);
                Span <byte> resultBuff    = new byte[32];
                var         abiEncodeBuff = new AbiEncodeBuffer(resultBuff, "int56");
                int56Encoder.SetValue(result);
                int56Encoder.Encode(ref abiEncodeBuff);
                Assert.Equal(bytes.Slice(25).ToHexString(), resultBuff.Slice(25).ToHexString());
            }
        }
        public void DecodeObject(ref AbiDecodeBuffer buffer, out object result)
        {
            // If we have no elements, no work needs to be done.
            if (TypeInfo.ArrayDimensionSizes.Length == 0)
            {
                result = Array.CreateInstance(TypeInfo.ArrayItemInfo.ClrType, 0);
                return;
            }

            // Create our initial array.
            var items = (Array)ArrayExtensions.CreateJaggedArray(TypeInfo.ArrayItemInfo.ClrType, TypeInfo.ArrayDimensionSizes);

            // Create a variable to track our position.
            int[] decodingPosition = new int[TypeInfo.ArrayDimensionSizes.Length];

            // Loop for each element to index.
            bool reachedEnd = false;

            while (!reachedEnd)
            {
                // Define the parent array to resolve for this element.
                Array innerMostArray = items;

                // Increment our decoding position.
                bool incrementing = true;
                for (int x = 0; x < decodingPosition.Length; x++)
                {
                    // If this isn't the final index (inner most array index), then it's an index to another array.
                    if (x < decodingPosition.Length - 1)
                    {
                        innerMostArray = (Array)innerMostArray.GetValue(decodingPosition[x]);
                    }
                    else
                    {
                        // We've resolved the element to index.
                        _itemEncoder.DecodeObject(ref buffer, out var item);
                        innerMostArray.SetValue(item, decodingPosition[x]);
                    }

                    // Increment the index for this dimension
                    if (incrementing)
                    {
                        // Increment our position.
                        decodingPosition[x]++;

                        // Determine if we need to carry a digit.
                        if (decodingPosition[x] >= TypeInfo.ArrayDimensionSizes[x])
                        {
                            // Reset the digit, we will carry over to the next.
                            decodingPosition[x] = 0;
                        }
                        else
                        {
                            incrementing = false;
                        }
                    }
                }

                // If we incremented all digits and still have increment flag set, we overflowed our last element, so we reached the end
                reachedEnd = incrementing;
            }

            // Set our result
            result = items;
        }