/// <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); } }
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" }); }
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); }
/// <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); }