Пример #1
0
        /// <inheritdoc/>
        public bool TryDeserialize(FastStreamReader stream, out string error)
        {
            if (!CompactInt.TryRead(stream, out CompactInt count, out error))
            {
                return(false);
            }

            // A quick check to avoid data loss during cast below
            if (count > int.MaxValue)
            {
                error = "Item count is too big.";
                return(false);
            }
            Items = new PushDataOp[(int)count];
            for (int i = 0; i < Items.Length; i++)
            {
                PushDataOp temp = new PushDataOp();
                if (!temp.TryReadWitness(stream, out error))
                {
                    return(false);
                }
                Items[i] = temp;
            }

            error = null;
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Initializes a new instance of <see cref="SignatureScript"/> using the given block height
        /// (used for creating the signature script of the coinbase transactions).
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException"/>
        /// <param name="height">Block height</param>
        /// <param name="extraData">An extra data to push in this coinbase script</param>
        public SignatureScript(int height, byte[] extraData)
        {
            if (height < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(height), "Block height can not be negative.");
            }

            PushDataOp hPush = new PushDataOp(height);

            if (extraData == null)
            {
                SetData(new IOperation[] { hPush });
                if (Data.Length < Constants.MinCoinbaseScriptLength)
                {
                    SetData(new IOperation[] { hPush, new PushDataOp(Encoding.UTF8.GetBytes("Bitcoin.Net")) });
                }
            }
            else
            {
                // No need for a min length check since with any height >= 1 it will be at least 2 bytes
                if (extraData.Length > Constants.MaxCoinbaseScriptLength - 4) // 1 byte push + 3 byte height byte
                {
                    throw new ArgumentOutOfRangeException(nameof(extraData.Length),
                                                          $"Coinbase script can not be bigger than {Constants.MaxCoinbaseScriptLength}");
                }
                SetData(new IOperation[] { hPush, new PushDataOp(extraData) });
            }
        }
Пример #3
0
        public static IEnumerable <object[]> GetMultiSigOutOfRangeExCases()
        {
            var rdm = new MockSerializableRedeemScript(RedeemScriptType.MultiSig, new byte[1], 0);
            var tx  = new MockTxIdTx("")
            {
                TxInList = new TxIn[1]
            };
            var zero  = new PushDataOp(OP._0);
            var one   = new PushDataOp(OP._1);
            var two   = new PushDataOp(OP._2);
            var neg   = new PushDataOp(OP.Negative1);
            var chsig = new CheckMultiSigOp();

            yield return(new object[] { Helper.ShortSig1, rdm, tx, -1, "Invalid input index." });

            yield return(new object[] { Helper.ShortSig1, rdm, tx, 1, "Invalid input index." });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockSerializableRedeemScript(RedeemScriptType.MultiSig, new byte[Constants.MaxScriptItemLength + 1], 0),
                tx, 0, "Redeem script is bigger than allowed length."
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { neg }, 0),
                tx, 0, "M can not be negative."
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { zero }, 0),
                tx, 0, "M value zero is not allowed"
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { one, neg, chsig }, 0),
                tx, 0, "N can not be negative."
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { one, zero, chsig }, 0),
                tx, 0, "N value zero is not allowed"
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { two, one, chsig }, 0),
                tx, 0, "M can not be bigger than N."
            });
        }
Пример #4
0
        public void Constructor_FromBytesTest()
        {
            byte[]     data = { 1, 2, 3 };
            PushDataOp op   = new PushDataOp(data);

            // Make sure data is cloned
            data[0] = 255;

            Helper.ComparePrivateField(op, "data", new byte[] { 1, 2, 3 });
            Assert.Equal(3, (byte)op.OpValue);
        }
Пример #5
0
        public void Constructor_FromScriptTest()
        {
            byte[] data = { 1, 2, 3 };
            MockSerializableScript scr = new MockSerializableScript(data, 255);
            PushDataOp             op  = new PushDataOp(scr);

            // Make sure data is cloned
            scr.Data[0] = 255;

            Helper.ComparePrivateField(op, "data", new byte[] { 1, 2, 3 });
            Assert.Equal(3, (byte)op.OpValue);
        }
Пример #6
0
        public void Constructor_FromBytesTest()
        {
            byte[][]     data     = new byte[][] { new byte[] { 1, 2, 3 }, new byte[] { 10, 20 }, new byte[] { 255, 255 } };
            PushDataOp[] expected = new PushDataOp[]
            {
                new PushDataOp(new byte[] { 1, 2, 3 }),
                new PushDataOp(new byte[] { 10, 20 }),
                new PushDataOp(new byte[] { 255, 255 })
            };
            Witness wit = new Witness(data);

            Assert.Equal(expected, wit.Items);
        }
Пример #7
0
        /// <summary>
        /// Initializes a new instance of <see cref="Witness"/> using the given data array.
        /// </summary>
        /// <exception cref="ArgumentNullException"/>
        /// <param name="dataItems">An array of byte arrays to use as witness items</param>
        public Witness(byte[][] dataItems)
        {
            if (dataItems == null)
            {
                throw new ArgumentNullException(nameof(dataItems), "Data items can not be null.");
            }

            Items = new PushDataOp[dataItems.Length];
            for (int i = 0; i < Items.Length; i++)
            {
                Items[i] = new PushDataOp(dataItems[i]);
            }
        }
Пример #8
0
        public void Constructor_DefaultTest()
        {
            PushDataOp op     = new PushDataOp();
            FastStream stream = new FastStream();

            op.WriteToStream(stream);

            byte[] actual   = stream.ToByteArray();
            byte[] expected = new byte[1] {
                0
            };

            Assert.Equal(expected, actual);
        }
Пример #9
0
        /// <inheritdoc/>
        public bool VerifyCoinbase(int height, IConsensus consensus)
        {
            if (Data.Length < Constants.MinCoinbaseScriptLength || Data.Length > Constants.MaxCoinbaseScriptLength)
            {
                return(false);
            }

            if (consensus.IsBip34Enabled(height))
            {
                PushDataOp op = new PushDataOp();
                return(op.TryRead(new FastStreamReader(Data), out _) && op.TryGetNumber(out long h, out _, true, 5) && h == height);
            }
            else
            {
                return(true);
            }
        }
Пример #10
0
        /// <inheritdoc/>
        public void SetToP2WSH_MultiSig(Signature[] sigs, RedeemScript redeem)
        {
            Items = new PushDataOp[sigs.Length + 2]; // OP_0 | Sig1 | sig2 | .... | sig(n) | redeemScript

            Items[0] = new PushDataOp(OP._0);

            for (int i = 1; i <= sigs.Length; i++)
            {
                Items[i] = new PushDataOp(sigs[i].ToByteArray());
            }

            FastStream stream = new FastStream();
            PushDataOp temp   = new PushDataOp(redeem.Data);

            temp.WriteToStream(stream);

            Items[^ 1] = new PushDataOp(stream.ToByteArray());
Пример #11
0
        private bool VerifyP2pkh(ITransaction tx, int index, PushDataOp sigPush, PushDataOp pubPush,
                                 ReadOnlySpan <byte> pubScrData, out string error)
        {
            var actualHash = hash160.ComputeHash(pubPush.data);

            if (!pubScrData.Slice(3, 20).SequenceEqual(actualHash))
            {
                error = "Invalid hash.";
                return(false);
            }

            Signature sig;

            if (consensus.IsStrictDerSig(BlockHeight))
            {
                if (!Signature.TryReadStrict(sigPush.data, out sig, out error))
                {
                    return(false);
                }
            }
            else
            {
                if (!Signature.TryReadLoose(sigPush.data, out sig, out error))
                {
                    return(false);
                }
            }

            if (!PublicKey.TryRead(pubPush.data, out PublicKey pubK))
            {
                error = "Invalid public key";
                return(false);
            }

            byte[] toSign = tx.SerializeForSigning(pubScrData.ToArray(), index, sig.SigHash);
            if (calc.Verify(toSign, sig, pubK, ForceLowS))
            {
                error = null;
                return(true);
            }
            else
            {
                error = "Invalid signature";
                return(false);
            }
        }
Пример #12
0
        public void EqualsTest()
        {
            IOperation r1_1 = new ReturnOp();
            IOperation r1_2 = new ReturnOp();
            IOperation r2_1 = new ReturnOp(new byte[] { 1, 2 }, false);
            IOperation r2_2 = new ReturnOp(new byte[] { 1, 2 }, false);
            IOperation r2_3 = new ReturnOp(new byte[] { 1, 2 }, true);
            IOperation r2_4 = new PushDataOp(new byte[] { 1, 2 });
            string     diff = "ReturnOp";

            Assert.True(r1_1.Equals(r1_1));
            Assert.True(r1_1.Equals(r1_2));
            Assert.False(r1_1.Equals(r2_1));

            Assert.True(r2_1.Equals(r2_1));
            Assert.True(r2_1.Equals(r2_2));
            Assert.False(r2_1.Equals(r2_3));
            Assert.False(r2_1.Equals(r2_4));
            Assert.False(r2_1.Equals(diff));
        }
Пример #13
0
        private bool VerifyP2wpkh(ITransaction tx, int index, PushDataOp sigPush, PushDataOp pubPush,
                                  ReadOnlySpan <byte> pubScrData, ulong amount, out string error)
        {
            if (sigPush.data == null || pubPush.data == null)
            {
                error = "Invalid data pushes in P2WPKH witness.";
                return(false);
            }

            var actualHash = hash160.ComputeHash(pubPush.data);

            if (!pubScrData.Slice(2, 20).SequenceEqual(actualHash))
            {
                error = "Invalid hash.";
                return(false);
            }

            if (!Signature.TryReadStrict(sigPush.data, out Signature sig, out error))
            {
                error = $"Invalid signature ({error})";
                return(false);
            }

            if (!PublicKey.TryRead(pubPush.data, out PublicKey pubK))
            {
                error = "Invalid public key";
                return(false);
            }

            byte[] toSign = tx.SerializeForSigningSegWit(scrSer.ConvertP2wpkh(actualHash), index, amount, sig.SigHash);
            if (calc.Verify(toSign, sig, pubK, ForceLowS))
            {
                error = null;
                return(true);
            }
            else
            {
                error = "Invalid signature";
                return(false);
            }
        }
Пример #14
0
        public static IEnumerable <object[]> GetMultiSigArgExCases()
        {
            var tx = new MockTxIdTx("")
            {
                TxInList = new TxIn[1]
            };
            PushDataOp badNum = new PushDataOp();

            badNum.TryRead(new FastStreamReader(new byte[] { 1, 0 }), out _);
            var two   = new PushDataOp(OP._2);
            var chsig = new CheckMultiSigOp();

            yield return(new object[]
            {
                Helper.ShortSig1, new MockSerializableRedeemScript(RedeemScriptType.Empty, new byte[0], 0),
                tx, 0, "Invalid redeem script type."
            });

            yield return(new object[]
            {
                Helper.ShortSig1, new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, null, 0),
                tx, 0, "Can not evaluate redeem script: Foo"
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { badNum }, 0),
                tx, 0, "Invalid m"
            });

            yield return(new object[]
            {
                Helper.ShortSig1,
                new MockEvaluatableRedeemScript(RedeemScriptType.MultiSig, new IOperation[] { two, badNum, chsig }, 0),
                tx, 0, "Invalid n"
            });
        }
Пример #15
0
        private bool TryRead(byte[] data, List <IOperation> opList, ref int offset, out string error)
        {
            if (IsPushOp(data[offset]))
            {
                PushDataOp op = new PushDataOp();
                if (!op.TryRead(data, ref offset, out error, IsWitness))
                {
                    return(false);
                }
                opList.Add(op);
            }
            else if (data[offset] == (byte)OP.RETURN)
            {
                ReturnOp op = new ReturnOp();
                if (!op.TryRead(data, ref offset, out error, len))
                {
                    return(false);
                }
                opList.Add(op);
            }
            else
            {
                switch ((OP)data[offset])
                {
                // Invalid OPs:
                case OP.VerIf:
                case OP.VerNotIf:
                    error = $"Invalid OP was found: {GetOpName((OP)data[offset])}";
                    return(false);

                // Disabled OPs:
                case OP.CAT:
                case OP.SubStr:
                case OP.LEFT:
                case OP.RIGHT:
                case OP.INVERT:
                case OP.AND:
                case OP.OR:
                case OP.XOR:
                case OP.MUL2:
                case OP.DIV2:
                case OP.MUL:
                case OP.DIV:
                case OP.MOD:
                case OP.LSHIFT:
                case OP.RSHIFT:
                    error = $"Disabled OP was found: {GetOpName((OP)data[offset])}";
                    return(false);

                // Special case of IFs:
                case OP.IF:
                    IFOp ifop = new IFOp();
                    List <IOperation> ifOps = new List <IOperation>();
                    offset++;
                    while (data[offset] != (byte)OP.EndIf && data[offset] != (byte)OP.ELSE && offset < endIndex)
                    {
                        if (!TryRead(data, ifOps, ref offset, out error))
                        {
                            return(false);
                        }
                        if (offset > endIndex)
                        {
                            error = "Bad format.";
                            return(false);
                        }
                        if (ifOps.Count == 0)
                        {
                            error = "Empty OP_IF";
                            return(false);
                        }
                    }
                    if (data[offset] == (byte)OP.ELSE)
                    {
                        List <IOperation> elseOps = new List <IOperation>();
                        offset++;
                        while (data[offset] != (byte)OP.EndIf && offset < endIndex)
                        {
                            if (!TryRead(data, elseOps, ref offset, out error))
                            {
                                return(false);
                            }
                        }
                        if (offset > endIndex)
                        {
                            error = "Bad format.";
                            return(false);
                        }
                        if (elseOps.Count == 0)
                        {
                            error = "Empty OP_ELSE";
                            return(false);
                        }
                        ifop.elseOps = elseOps.ToArray();
                    }

                    if (data[offset] != (byte)OP.EndIf)
                    {
                        error = "No OP_ENDIF was found.";    //this may never happen!
                        return(false);
                    }

                    ifop.mainOps = ifOps.ToArray();

                    opList.Add(ifop);
                    break;

                case OP.NotIf:
                    NotIfOp           notifOp = new NotIfOp();
                    List <IOperation> ifOps2  = new List <IOperation>();
                    offset++;
                    while (data[offset] != (byte)OP.EndIf && data[offset] != (byte)OP.ELSE && offset < endIndex)
                    {
                        if (!TryRead(data, ifOps2, ref offset, out error))
                        {
                            return(false);
                        }
                        if (offset > endIndex)
                        {
                            error = "Bad format.";
                            return(false);
                        }
                        if (ifOps2.Count == 0)
                        {
                            error = "Empty OP_IF";
                            return(false);
                        }
                    }
                    if (data[offset] == (byte)OP.ELSE)
                    {
                        List <IOperation> elseOps2 = new List <IOperation>();
                        offset++;
                        while (data[offset] != (byte)OP.EndIf && offset < endIndex)
                        {
                            if (!TryRead(data, elseOps2, ref offset, out error))
                            {
                                return(false);
                            }
                        }
                        if (offset > endIndex)
                        {
                            error = "Bad format.";
                            return(false);
                        }
                        if (elseOps2.Count == 0)
                        {
                            error = "Empty OP_ELSE";
                            return(false);
                        }
                        notifOp.elseOps = elseOps2.ToArray();
                    }

                    if (data[offset] != (byte)OP.EndIf)
                    {
                        error = "No OP_ENDIF was found.";    //this may never happen!
                        return(false);
                    }

                    notifOp.mainOps = ifOps2.ToArray();

                    opList.Add(notifOp);
                    break;

                case OP.ELSE:
                    error = "OP_ELSE found without prior OP_IF or OP_NOTIF.";
                    return(false);

                case OP.EndIf:
                    error = "OP_EndIf found without prior OP_IF or OP_NOTIF.";
                    return(false);

                // From OP_0 to OP_16 except OP_Reserved is already handled.

                case OP.Reserved:
                    opList.Add(new ReservedOp());
                    break;

                case OP.NOP:
                    opList.Add(new NOPOp());
                    break;

                case OP.VER:
                    opList.Add(new VEROp());
                    break;

                // OP.IF and OP.NotIf moved to top
                // OP.VerIf and OP.VerNotIf moved to top (Invalid tx)
                // OP.ELSE and OP.EndIf moved to top

                case OP.VERIFY:
                    opList.Add(new VerifyOp());
                    break;

                // OP.RETURN is already handled

                case OP.ToAltStack:
                    opList.Add(new ToAltStackOp());
                    break;

                case OP.FromAltStack:
                    opList.Add(new FromAltStackOp());
                    break;

                case OP.DROP2:
                    opList.Add(new DROP2Op());
                    break;

                case OP.DUP2:
                    opList.Add(new DUP2Op());
                    break;

                case OP.DUP3:
                    opList.Add(new DUP3Op());
                    break;

                case OP.OVER2:
                    opList.Add(new OVER2Op());
                    break;

                case OP.ROT2:
                    opList.Add(new ROT2Op());
                    break;

                case OP.SWAP2:
                    opList.Add(new SWAP2Op());
                    break;

                case OP.IfDup:
                    opList.Add(new IfDupOp());
                    break;

                case OP.DEPTH:
                    opList.Add(new DEPTHOp());
                    break;

                case OP.DROP:
                    opList.Add(new DROPOp());
                    break;

                case OP.DUP:
                    opList.Add(new DUPOp());
                    break;

                case OP.NIP:
                    opList.Add(new NIPOp());
                    break;

                case OP.OVER:
                    opList.Add(new OVEROp());
                    break;

                case OP.PICK:
                    opList.Add(new PICKOp());
                    break;

                case OP.ROLL:
                    opList.Add(new ROLLOp());
                    break;

                case OP.ROT:
                    opList.Add(new ROTOp());
                    break;

                case OP.SWAP:
                    opList.Add(new SWAPOp());
                    break;

                case OP.TUCK:
                    opList.Add(new TUCKOp());
                    break;

                // OP_ (CAT SubStr LEFT RIGHT INVERT AND OR XOR) are moved to top

                case OP.SIZE:
                    opList.Add(new SizeOp());
                    break;

                case OP.EQUAL:
                    opList.Add(new EqualOp());
                    break;

                case OP.EqualVerify:
                    opList.Add(new EqualVerifyOp());
                    break;

                case OP.Reserved1:
                    opList.Add(new Reserved1Op());
                    break;

                case OP.Reserved2:
                    opList.Add(new Reserved2Op());
                    break;

                case OP.ADD1:
                    opList.Add(new ADD1Op());
                    break;

                case OP.SUB1:
                    opList.Add(new SUB1Op());
                    break;

                // OP.MUL2 and OP.DIV2 are moved to top (disabled op).

                case OP.NEGATE:
                    opList.Add(new NEGATEOp());
                    break;

                case OP.ABS:
                    opList.Add(new ABSOp());
                    break;

                case OP.NOT:
                    opList.Add(new NOTOp());
                    break;

                case OP.NotEqual0:
                    opList.Add(new NotEqual0Op());
                    break;

                case OP.ADD:
                    opList.Add(new AddOp());
                    break;

                case OP.SUB:
                    opList.Add(new SUBOp());
                    break;

                // OP_ (MUL DIV MOD LSHIFT RSHIFT) are moved to top (disabled op).

                case OP.BoolAnd:
                    opList.Add(new BoolAndOp());
                    break;

                case OP.BoolOr:
                    opList.Add(new BoolOrOp());
                    break;

                case OP.NumEqual:
                    opList.Add(new NumEqualOp());
                    break;

                case OP.NumEqualVerify:
                    opList.Add(new NumEqualVerifyOp());
                    break;

                case OP.NumNotEqual:
                    opList.Add(new NumNotEqualOp());
                    break;

                case OP.LessThan:
                    opList.Add(new LessThanOp());
                    break;

                case OP.GreaterThan:
                    opList.Add(new GreaterThanOp());
                    break;

                case OP.LessThanOrEqual:
                    opList.Add(new LessThanOrEqualOp());
                    break;

                case OP.GreaterThanOrEqual:
                    opList.Add(new GreaterThanOrEqualOp());
                    break;

                case OP.MIN:
                    opList.Add(new MINOp());
                    break;

                case OP.MAX:
                    opList.Add(new MAXOp());
                    break;

                case OP.WITHIN:
                    opList.Add(new WITHINOp());
                    break;

                case OP.RIPEMD160:
                    opList.Add(new RipeMd160Op());
                    break;

                case OP.SHA1:
                    opList.Add(new Sha1Op());
                    break;

                case OP.SHA256:
                    opList.Add(new Sha256Op());
                    break;

                case OP.HASH160:
                    opList.Add(new Hash160Op());
                    break;

                case OP.HASH256:
                    opList.Add(new Hash256Op());
                    break;

                //case OP.CodeSeparator:
                //    break;
                case OP.CheckSig:
                    opList.Add(new CheckSigOp());
                    break;

                case OP.CheckSigVerify:
                    opList.Add(new CheckSigVerifyOp());
                    break;

                case OP.CheckMultiSig:
                    opList.Add(new CheckMultiSigOp());
                    break;

                case OP.CheckMultiSigVerify:
                    opList.Add(new CheckMultiSigVerifyOp());
                    break;

                case OP.NOP1:
                    opList.Add(new NOP1Op());
                    break;

                case OP.CheckLocktimeVerify:
                    opList.Add(new CheckLocktimeVerifyOp());
                    break;

                //case OP.CheckSequenceVerify:
                //    break;
                case OP.NOP4:
                    opList.Add(new NOP4Op());
                    break;

                case OP.NOP5:
                    opList.Add(new NOP5Op());
                    break;

                case OP.NOP6:
                    opList.Add(new NOP6Op());
                    break;

                case OP.NOP7:
                    opList.Add(new NOP7Op());
                    break;

                case OP.NOP8:
                    opList.Add(new NOP8Op());
                    break;

                case OP.NOP9:
                    opList.Add(new NOP9Op());
                    break;

                case OP.NOP10:
                    opList.Add(new NOP10Op());
                    break;

                default:
                    error = "Undefined OP code";
                    return(false);
                }

                offset++;
            }

            error = null;
            return(true);
        }
Пример #16
0
        /// <summary>
        /// Deserializes the given byte array starting from the specified offset. The return value indicates success.
        /// </summary>
        /// <param name="data">Byte array containing a <see cref="Script"/>.</param>
        /// <param name="offset">The offset inside the <paramref name="data"/> to start from.</param>
        /// <param name="error">Error message (null if sucessful, otherwise will contain information about the failure).</param>
        /// <returns>True if deserialization was successful, false if otherwise.</returns>
        public virtual bool TryDeserialize(byte[] data, ref int offset, out string error)
        {
            if (offset < 0)
            {
                error = "Offset can not be negative.";
                return(false);
            }
            if (data == null || data.Length - offset < 0)
            {
                error = "Data length is not valid.";
                return(false);
            }


            if (!CompactInt.TryReadFromBytes(data, ref offset, out CompactInt lengthOrCount, out error))
            {
                return(false);
            }
            if (lengthOrCount.Value > int.MaxValue)
            {
                error = (IsWitness ? "Item count" : "Script length") + "is too big.";
                return(false);
            }

            if (IsWitness)
            {
                // cast is ok since the check happend in previous line.
                int count = (int)lengthOrCount;
                if (count > maxLenOrCount)
                {
                    error = "Invalid witness item count.";
                    return(false);
                }


                OperationList = new IOperation[count];
                for (int i = 0; i < count; i++)
                {
                    // TODO: the assumption here is that witness doesn't have anything but PushDataOp, this may be wrong.
                    PushDataOp op = new PushDataOp();
                    if (!op.TryRead(data, ref offset, out error, true))
                    {
                        return(false);
                    }
                    OperationList[i] = op;
                }
            }
            else
            {
                // cast is ok same as above
                len = (int)lengthOrCount;

                // Empty script (offset doesn't change, it already changed when reading CompactInt)
                if (len == 0)
                {
                    OperationList = new IOperation[0];
                    error         = null;
                    return(true);
                }

                List <IOperation> opList = new List <IOperation>();
                endIndex = offset + len;
                while (offset < endIndex)
                {
                    if (!TryRead(data, opList, ref offset, out error))
                    {
                        return(false);
                    }
                }

                if (offset != endIndex)
                {
                    error = "Invalid stack format.";
                    return(false);
                }
                OperationList = opList.ToArray();
            }

            error = null;
            return(true);
        }
Пример #17
0
        public void Constructor_FromOpNumTest(OP val)
        {
            PushDataOp op = new PushDataOp(val);

            Assert.Equal(val, op.OpValue);
        }
Пример #18
0
        public void Constructor_FromInt_HasOpNum_Test(int i, OP expected)
        {
            PushDataOp op = new PushDataOp(i);

            Assert.Equal(expected, op.OpValue);
        }