public static KzOp Push(ReadOnlySpan <byte> data) { var code = KzOpcode.OP_INVALIDOPCODE; var val = KzValType.None; if (data.Length == 1 && data[0] <= 16) { code = data[0] == 0 ? KzOpcode.OP_0 : (KzOpcode)(data[0] - 1 + (int)KzOpcode.OP_1); } else { if (data.Length < (int)KzOpcode.OP_PUSHDATA1) { code = (KzOpcode)data.Length; } else if (data.Length <= 0xff) { code = KzOpcode.OP_PUSHDATA1; } else if (data.Length <= 0xffff) { code = KzOpcode.OP_PUSHDATA2; } else { code = KzOpcode.OP_PUSHDATA4; } val = new KzValType(data.ToArray()); } var op = new KzOp(code, val); return(op); }
/* * // script.h lines 527-562 * bool GetOp2(const_iterator &pc, opcodetype &opcodeRet, * std::vector<uint8_t> *pvchRet) const { * opcodeRet = OP_INVALIDOPCODE; * if (pvchRet) pvchRet->clear(); * if (pc >= end()) return false; * * // Read instruction * if (end() - pc < 1) return false; * unsigned int opcode = *pc++; * * // Immediate operand * if (opcode <= OP_PUSHDATA4) { * unsigned int nSize = 0; * if (opcode < OP_PUSHDATA1) { * nSize = opcode; * } else if (opcode == OP_PUSHDATA1) { * if (end() - pc < 1) return false; * nSize = *pc++; * } else if (opcode == OP_PUSHDATA2) { * if (end() - pc < 2) return false; * nSize = ReadLE16(&pc[0]); * pc += 2; * } else if (opcode == OP_PUSHDATA4) { * if (end() - pc < 4) return false; * nSize = ReadLE32(&pc[0]); * pc += 4; * } * if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize) * return false; * if (pvchRet) pvchRet->assign(pc, pc + nSize); * pc += nSize; * } * * opcodeRet = (opcodetype)opcode; * return true; * } */ public static (bool ok, KzOp op) TryRead(ref ReadOnlySequence <byte> ros, out long consumed) { var op = new KzOp(); var ok = op.TryReadOp(ref ros, out consumed); return(ok, op); }
public int FindAndDelete(KzValType vchSig) { int nFound = 0; var s = _script; var r = s; if (vchSig.Length == 0) { return(nFound); } var op = new KzOp(); var consumed = 0L; var offset = 0L; var o = vchSig.Sequence; var oLen = o.Length; do { offset += consumed; while (s.StartsWith(o)) { r = r.RemoveSlice(offset, oLen); s = s.Slice(oLen); ++nFound; } } while (op.TryReadOp(ref s, out consumed)); _script = r; return(nFound); #if false CScript result; iterator pc = begin(), pc2 = begin(); opcodetype opcode; do { result.insert(result.end(), pc2, pc); while (static_cast <size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; } pc2 = pc; } while (GetOp(pc, opcode)); if (nFound > 0) { result.insert(result.end(), pc2, end()); *this = result; } #endif }
/// <summary> /// Decode script opcodes and push data. /// </summary> /// <returns></returns> public IEnumerable <KzOp> Decode() { var ros = _script; while (ros.Length > 0) { var op = new KzOp(); if (!op.TryReadOp(ref ros)) { goto fail; } yield return(op); } fail: ; }
/// <summary> /// Return the Template String representation of script bytes. /// If the returned string does not include all the script opcodes, either because the scriptLen or limitLen /// arguments are greater than zero, or if the script sequence ends with an incomplete multibyte opcode, /// then "..." is appended following the last complete opcode. /// /// scriptLen argument should be used when the actual script is longer than the script sequence provided, /// which must then be a subsequence from the start of the script. /// If greater than zero it may be longer than the sequence provided in which case "..." will be appended /// after the last opcode. /// /// limitLen argument stops converting opcodes to their template string format after processing this many bytes. /// </summary> /// <param name="script"></param> /// <param name="scriptLen">How long the entire script is, or zero.</param> /// <param name="limitLen">How many bytes to process, or zero.</param> /// <returns></returns> public static string ToTemplateString(ReadOnlySequence <byte> script, long scriptLen = 0, long limitLen = 0) { var ros = script; if (limitLen == 0) { limitLen = long.MaxValue; } var ok = true; var count = 0L; var sb = new StringBuilder(); while (ros.Length > 0 && ok && limitLen > count) { var op = new KzOp(); ok = op.TryReadOp(ref ros, out var consumed); count += consumed; if (ok && limitLen >= count) { var len = op.Data.Length; if (len == 0) { sb.Append($"{op.CodeName} "); } else { sb.Append($"[{op.Data.Length}] "); } } } if (sb.Length > 0) { sb.Length--; } if (scriptLen == 0) { scriptLen = count; } if (!ok || limitLen < count || count < scriptLen) { sb.Append("..."); } return(sb.ToString()); }
public static KzOp Push(long v) { var code = KzOpcode.OP_INVALIDOPCODE; var val = KzValType.None; if (v == -1) { code = KzOpcode.OP_1NEGATE; } else if (v >= 0 && v <= 16) { code = v == 0 ? KzOpcode.OP_0 : (KzOpcode)(v - 1 + (int)KzOpcode.OP_1); } else { var bytes = BitConverter.GetBytes(v).AsSpan(); if (v <= 0xff) { code = KzOpcode.OP_PUSH1; val = new KzValType(bytes.Slice(0, 1).ToArray()); } else if (v <= 0xffff) { code = KzOpcode.OP_PUSH2; val = new KzValType(bytes.Slice(0, 2).ToArray()); } else if (v <= 0xffffff) { code = KzOpcode.OP_PUSH3; val = new KzValType(bytes.Slice(0, 3).ToArray()); } else { code = KzOpcode.OP_PUSH4; val = new KzValType(bytes.Slice(0, 4).ToArray()); } } var op = new KzOp(code, val); return(op); }
public bool IsPushOnly() { var ros = _script; var op = new KzOp(); while (ros.Length > 0) { if (!op.TryReadOp(ref ros)) { return(false); } // Note that IsPushOnly() *does* consider OP_RESERVED to be a push-type // opcode, however execution of OP_RESERVED fails, so it's not relevant // to P2SH/BIP62 as the scriptSig would fail prior to the P2SH special // validation code being executed. if (op.Code > KzOpcode.OP_16) { return(false); } } return(true); }
public KzBOp(KzValType data) : this() { IsFinal = true; IsRaw = true; Op = new KzOp(KzOpcode.OP_NOP, data); }
public KzBOp(KzOp op) : this() { IsFinal = true; Op = op; }