// main entry into parser void encode_rpn() { statement *stmt, *tempstmt = gprog->firststmt; struct labelset *label; unsigned int x = 0, y = 0; int channum = 0, lastfnc = 0, lastvar = 0, ifcount = 0; byte display = 0, watchchannel = 0, special = 0; char *cont; symbol *sym; begin: stmt = SafeMalloc(sizeof(statement)); stmtinit(stmt); for (x=0; x<MAX_STMT_METAS; x++) { stmt->metalist[x].operation = 0; stmt->metalist[x].floatarg.mantisa.i = 0; stmt->metalist[x].floatarg.exp = 0; stmt->metalist[x].shortarg = 0; for (y=0; y<MAX_STRING_LENGTH; y++) stmt->metalist[x].stringarg[y] = 0; } special = 0; foundequals = 0; firstvar = 1; numlabels = 0; envinfo.stmttype = 0; tokenpos = 0; token_type = 1; lastopcode = 0; for (x=0; x<32; x++) { numargs[x] = 0; parenstack[x] = 0; } do { get_token(); tokenpos += strlen(token); if(!checkoption(get_cmdindex(get_opname(stmt->opcode)), token, token_type)) lineerror(stmt, __FILE__, __LINE__); // hack to avoid using runtime system // using runtime system would change the last executed line info. // if ((!strcmp(token, "PBSTEP")) && (token_type == TOK_COMMAND)) // dbg_step(); switch (token_type) { case TOK_ERROR: lineerror(stmt, __FILE__, __LINE__); break; case TOK_COMMAND: lastopcode = get_opcode(token); if (cmdtable[get_cmdindex(token)].options & IO_CHANNEL) watchchannel = 1; else watchchannel = 0; stmt->opcode = get_opcode(token); if (stmt->opcode == CMD_LET) goto loop2; else goto loop; case TOK_NUMBER: stmt->opcode = 0; stmt->linenum = atoi(token); break; default: buffermeta(stmt, token_type, token); goto loop2; } buffermeta(stmt, token_type, token); loop: get_token(); if (checkerr == 2) checkerr = 1; else if (checkerr == 1) { if (token[0] == '=') { if (stmt->metalist[stmt->metapos-2].operation == 0xEC) stmt->metapos-=2; else stmt->metapos--; push("ERR", TOK_OPERATOR); } else if (token[0] == '(') { prog--; stmt->metapos--; strcpy(token, "ERR"); token_type = TOK_FUNCTION; } checkerr = 0; } if (lastopcode == CMD_SETERR) { if (!strcmp(token, "ON")) lastopcode = CMD_SETERRON; if (!strcmp(token, "OFF")) lastopcode = CMD_SETERROFF; } if (!strcmp(token, "RECORD")) { if (stmt->opcode == CMD_READ) lastopcode = CMD_READRECORD; if (stmt->opcode == CMD_WRITE) lastopcode = CMD_WRITERECORD; if (stmt->opcode == CMD_EXTRACT) lastopcode = CMD_EXTRACTRECORD; if (stmt->opcode == CMD_FIND) lastopcode = CMD_FINDRECORD; if (stmt->opcode == CMD_PRINT) lastopcode = CMD_PRINTRECORD; token_type = lasttype; goto loop; } if (lastopcode == CMD_REM) { stmt->metalist[1].operation = 0xF5; tokenpos -= 2; if (input[tokenpos] == '\"') x = tokenpos; else x = tokenpos+2; stmt->metalist[1].shortarg = strlen(input) - x; y = 0; for (x=x; x<strlen(input); x++) { stmt->metalist[1].stringarg[y] = input[x]; y++; } stmt->metalist[1].stringarg[y] = '\0'; stmt->metapos++; if (stmt->linenum) insertstmt(gprog, stmt); return; } tokenpos += strlen(token); if(!checkoption(get_cmdindex(get_opname(lastopcode)), token, token_type)) lineerror(stmt, __FILE__, __LINE__); loop2: switch (token_type) { case TOK_SEMICOLON: popstack(stmt, -1); if (!stmt->linenum) { execline(gprog, stmt); stmtinit(stmt); } break; case TOK_COLON: if ((stmt->metalist[stmt->metapos-1].operation == SETVAL_NUMERIC) || (stmt->metalist[stmt->metapos-1].operation == GETVAL_NUMERIC) || (stmt->metalist[stmt->metapos-1].operation == LABELREF)) { label = SafeMalloc(sizeof(struct labelset)); sym = idx2sym(gprog, stmt->metalist[stmt->metapos-1].shortarg); label->labelnum = addlabel(gprog, sym->name, stmt->linenum); for (x=0; x<MAX_STRING_LENGTH; x++) sym->name[x] = '\0'; x = 0; stmt->metapos--; stmt->metalist[stmt->metapos].shortarg = 0; stmt->opcode = 0; stmt->labelset[stmt->numlabels] = label; stmt->numlabels++; firstvar = 1; } else { do { if (stmt->linenum == tempstmt->linenum) { for (x=0; x<strlen(input); x++) if (input[x] == ':') break; y = x; for (x=0; x<=y; x++) input[x] = ' '; cont = SafeMalloc(1024*64); *cont = 0; listline(cont, tempstmt, 1); strcat(cont, input); *prog = 0; prog = cont; display = 1; goto begin; } tempstmt = tempstmt->nextstmt; } while (tempstmt != NULL); numlabels++; } goto loop; case TOK_COMMA: if (parencount > 0) { // comma being delimiter for system functions popstack(stmt, -2); push("(", TOK_OPERATOR); if (chaninfo == 1) { if (!channum) { channum = 1; stmt->metalist[stmt->metapos].operation = 0xE1; stmt->metapos++; } } else { if (special == 1) numargs[parencount-1]+=10; else numargs[parencount-1]++; envinfo.stmttype = 0; } } else { // comma being delimiter for verbs popstack(stmt, -1); buffermeta(stmt, TOK_COMMA, token); for (x=0; x<32; x++) numargs[x] = 0; envinfo.stmttype = 0; foundequals = 0; firstvar = 1; } goto loop; case TOK_ERROR: lineerror(stmt, __FILE__, __LINE__); return; case TOK_COMMAND: lastopcode = get_opcode(token); if (cmdtable[get_cmdindex(token)].options & IO_CHANNEL) watchchannel = 1; else watchchannel = 0; if (!strcmp(token, "IF")) ifcount++; if (!stmt->opcode) { stmt->opcode = get_opcode(token); envinfo.stmttype = 0; goto loop; } else { popstack(stmt, -1); envinfo.stmttype = 0; if (ifcount > 0) { stmt->metalist[stmt->metapos].operation = 0xE7; stmt->metalist[stmt->metapos].shortarg = 0; stmt->metalist[stmt->metapos].intarg = 0; stmt->metapos++; stmt->length++; // watchchannel = 0; chaninfo = 0; channum = 0; ifcount--; } if (lastopcode == CMD_ON) { special = 1; if (!strcmp(token, "GOTO")) stmt->metalist[stmt->metapos].operation = 0x00F4; else stmt->metalist[stmt->metapos].operation = 0x01F4; stmt->length += 2; stmt->metapos++; } else buffermeta(stmt, TOK_COMMAND, token); goto loop; } break; case TOK_RESERVED: popstack(stmt, -1); envinfo.stmttype = 0; lineref = 0; if (!strcmp(token, "ELSE")) { stmt->metalist[stmt->metapos].operation = 0xE7; stmt->metalist[stmt->metapos].intarg = 0; stmt->metalist[stmt->metapos].shortarg = 0; stmt->metapos++; stmt->metalist[stmt->metapos].operation = 0xE2; stmt->metalist[stmt->metapos].intarg = 0; stmt->metalist[stmt->metapos].shortarg = 0; stmt->metapos++; stmt->length+=2; envinfo.stmttype = 0; chaninfo = 0; channum = 0; } goto loop; case TOK_DONE: if ((stmt->linenum) && (!stmt->opcode)) deletestmt(gprog,stmt->linenum); else { popstack(stmt, -1); if (stmt->opcode == CMD_LET && foundequals == 0) lineerror(stmt, __FILE__, __LINE__); if (parencount > 0 || numlabels < 0) lineerror(stmt, __FILE__, __LINE__); if (stmt->linenum) { if (!stmt->errorflag) insertstmt(gprog, stmt); } else if (stmt->opcode) { if (!stmt->errorflag) { execline(gprog, stmt); } } } if (display) { GC_realloc(cont, strlen(cont)); listprog(gprog, stmt->linenum, stmt->linenum); } return; case TOK_USERFUNCTION: if (lastopcode == CMD_DEFFN) addfunction(gprog, token, stmt->linenum, 1); else addfunction(gprog, token, stmt->linenum, 0); if (token[strlen(token)-1] == '$') parenstack[parencount] = 8; else parenstack[parencount] = 7; buffermeta(stmt, TOK_USERFUNCTION, token); break; case TOK_FUNCTION: lastfnc = get_fnc(token); numlabels++; case TOK_OPERATOR: if (token[0] == '[') { special = 1; cont = get_symname(lastvar); if (cont[strlen(cont)-1] == '$') parenstack[parencount] = 2; else parenstack[parencount] = 1; numlabels++; goto openparen; } else if (token[0] == ']') { numargs[parencount-1] += 9; popstack(stmt, -2); envinfo.stmttype = parenstack[parencount]; token_type = TOK_ARRAY; special = 0; goto loop; } else if (token[0] == '-') { // placeholder if ((lasttype == TOK_OPERATOR) || (lasttype == TOK_RESERVED)) token[0] = '_'; evalstack(stmt); goto loop; } else if (token[0] == '(') { openparen: if (lasttype == TOK_COMMAND) { if (watchchannel == 1) chaninfo = 1; } else if (lasttype == TOK_ARRAY) { envinfo.stmttype = 0; numargs[parencount]++; push(token, token_type); goto loop; } else if (lasttype == TOK_SETVAL) { push(get_symname(lastvar), TOK_SETVAL); stmt->metapos--; stmt->metalist[stmt->metapos].shortarg = 0; numlabels++; cont = get_symname(lastvar); if (cont[strlen(cont)-1] == '$') parenstack[parencount] = 2; else parenstack[parencount] = 1; } else if (lasttype == TOK_VARIABLE) { push(get_symname(lastvar), TOK_VARIABLE); numlabels++; stmt->metapos--; stmt->metalist[stmt->metapos].shortarg = 0; cont = get_symname(lastvar); if (cont[strlen(cont)-1] == '$') parenstack[parencount] = 2; else parenstack[parencount] = 1; } else if (lasttype == TOK_USERFUNCTION) { stmt->metapos--; stmt->metalist[stmt->metapos].operation = 0xF5; stmt->metapos++; stmt->length++; } else if (lasttype == TOK_FUNCTION) { if ((envinfo.stmttype != fnctable[lastfnc].returntype) && (envinfo.stmttype != 0)) lineerror(stmt, __FILE__, __LINE__); else parenstack[parencount] = fnctable[lastfnc].returntype; } else parenstack[parencount] = 1; envinfo.stmttype = 0; numargs[parencount] = 1; push(token, token_type); goto loop; } else if (token[0] == ')') { if (parencount == 0) lineerror(stmt, __FILE__, __LINE__); popstack(stmt, -2); if (parenstack[parencount] == 7) { stmt->metalist[stmt->metapos].operation = 0xF8; stmt->metapos++; stmt->length++; envinfo.stmttype = 1; } else if (parenstack[parencount] == 8) { stmt->metalist[stmt->metapos].operation = 0xF8; stmt->metapos++; stmt->length++; envinfo.stmttype = 2; } else envinfo.stmttype = parenstack[parencount]; if (lastopcode == CMD_DEFFN && foundequals == 0) { stmt->metapos--; stmt->metalist[stmt->metapos].operation = 0xF8; stmt->metapos++; } if (chaninfo == 1) { chaninfo = 0; if (!channum) { stmt->metalist[stmt->metapos].operation = 0xE1; stmt->metapos++; } stmt->metalist[stmt->metapos].operation = 0xF4F1; stmt->metapos++; numargs[parencount] = 0; } goto loop; } else { evalstack(stmt); goto loop; } break; case TOK_VARIABLE: if (get_sysvar(token)) { buffermeta(stmt, TOK_SYSVAR, token); numlabels++; goto loop; } else { addsymbol(gprog, token); lastvar = get_symref(token); } case TOK_NUMBER: default: if(!stmt->opcode) { envinfo.stmttype = 0; lastopcode = stmt->opcode = CMD_LET; } if ((firstvar == 1) && (token_type == TOK_VARIABLE) && (lastopcode == CMD_LET || lastopcode == CMD_FOR || lastopcode == CMD_FOR || lastopcode == CMD_NEXT || lastopcode == CMD_DIM || lastopcode == CMD_INPUT)) { buffermeta(stmt, TOK_SETVAL, token); firstvar = 0; token_type = TOK_SETVAL; } else { numlabels++; buffermeta(stmt, token_type, token); } goto loop; } } while (1); }
bool bp_script_verify(const GString *scriptSig, const GString *scriptPubKey, const struct bp_tx *txTo, unsigned int nIn, unsigned int flags, int nHashType) { bool rc = false; GPtrArray *stack = g_ptr_array_new_with_free_func( (GDestroyNotify) buffer_free); GString *pubkey2 = NULL; GPtrArray *stackCopy = NULL; if (!bp_script_eval(stack, scriptSig, txTo, nIn, flags, nHashType)) goto out; if (flags & SCRIPT_VERIFY_P2SH) { stackCopy = g_ptr_array_new_full(stack->len, (GDestroyNotify) buffer_free); stack_copy(stackCopy, stack); } if (!bp_script_eval(stack, scriptPubKey, txTo, nIn, flags, nHashType)) goto out; if (stack->len == 0) goto out; if (CastToBool(stacktop(stack, -1)) == false) goto out; if ((flags & SCRIPT_VERIFY_P2SH) && is_bsp_p2sh_str(scriptPubKey)) { struct const_buffer sigbuf = { scriptSig->str, scriptSig->len }; if (!is_bsp_pushonly(&sigbuf)) goto out; if (stackCopy->len < 1) goto out; struct buffer *pubkey2_buf = stack_take(stackCopy, -1); popstack(stackCopy); GString *pubkey2 = g_string_sized_new(pubkey2_buf->len); g_string_append_len(pubkey2, pubkey2_buf->p, pubkey2_buf->len); buffer_free(pubkey2_buf); bool rc2 = bp_script_eval(stackCopy, pubkey2, txTo, nIn, flags, nHashType); g_string_free(pubkey2, TRUE); if (!rc2) goto out; if (stackCopy->len == 0) goto out; if (CastToBool(stacktop(stackCopy, -1)) == false) goto out; } rc = true; out: g_ptr_array_free(stack, TRUE); if (pubkey2) g_string_free(pubkey2, TRUE); if (stackCopy) g_ptr_array_free(stackCopy, TRUE); return rc; }
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; vector<bool> vfExec; vector<valtype> altstack; if (script.size() > 10000) return false; int nOpCount = 0; try { while (pc < pend) { bool fExec = !count(vfExec.begin(), vfExec.end(), false); // // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) return false; if (vchPushValue.size() > 520) return false; if (opcode > OP_16 && ++nOpCount > 201) return false; if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT || opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_AND || opcode == OP_OR || opcode == OP_XOR || opcode == OP_2MUL || opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) return false; if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) switch (opcode) { // // Push value // case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: { // ( -- value) CBigNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; // // Control // case OP_NOP: case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; case OP_IF: case OP_NOTIF: { // <expression> if [statements] [else [statements]] endif bool fValue = false; if (fExec) { if (stack.size() < 1) return false; valtype& vch = stacktop(-1); fValue = CastToBool(vch); if (opcode == OP_NOTIF) fValue = !fValue; popstack(stack); } vfExec.push_back(fValue); } break; case OP_ELSE: { if (vfExec.empty()) return false; vfExec.back() = !vfExec.back(); } break; case OP_ENDIF: { if (vfExec.empty()) return false; vfExec.pop_back(); } break; case OP_VERIFY: { // (true -- ) or // (false -- false) and return if (stack.size() < 1) return false; bool fValue = CastToBool(stacktop(-1)); if (fValue) popstack(stack); else return false; } break; case OP_RETURN: { return false; } break; // // Stack ops // case OP_TOALTSTACK: { if (stack.size() < 1) return false; altstack.push_back(stacktop(-1)); popstack(stack); } break; case OP_FROMALTSTACK: { if (altstack.size() < 1) return false; stack.push_back(altstacktop(-1)); popstack(altstack); } break; case OP_2DROP: { // (x1 x2 -- ) if (stack.size() < 2) return false; popstack(stack); popstack(stack); } break; case OP_2DUP: { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) return false; valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_3DUP: { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) return false; valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); stack.push_back(vch3); } break; case OP_2OVER: { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) return false; valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2ROT: { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) return false; valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end()-6, stack.end()-4); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2SWAP: { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) return false; swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } break; case OP_IFDUP: { // (x - 0 | x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); if (CastToBool(vch)) stack.push_back(vch); } break; case OP_DEPTH: { // -- stacksize CBigNum bn(stack.size()); stack.push_back(bn.getvch()); } break; case OP_DROP: { // (x -- ) if (stack.size() < 1) return false; popstack(stack); } break; case OP_DUP: { // (x -- x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); stack.push_back(vch); } break; case OP_NIP: { // (x1 x2 -- x2) if (stack.size() < 2) return false; stack.erase(stack.end() - 2); } break; case OP_OVER: { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) return false; valtype vch = stacktop(-2); stack.push_back(vch); } break; case OP_PICK: case OP_ROLL: { // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; int n = CastToBigNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= stack.size()) return false; valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) stack.erase(stack.end()-n-1); stack.push_back(vch); } break; case OP_ROT: { // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) return false; swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } break; case OP_SWAP: { // (x1 x2 -- x2 x1) if (stack.size() < 2) return false; swap(stacktop(-2), stacktop(-1)); } break; case OP_TUCK: { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) return false; valtype vch = stacktop(-1); stack.insert(stack.end()-2, vch); } break; // // Splice ops // case OP_CAT: { // (x1 x2 -- out) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); vch1.insert(vch1.end(), vch2.begin(), vch2.end()); popstack(stack); if (stacktop(-1).size() > 520) return false; } break; case OP_SUBSTR: { // (in begin size -- out) if (stack.size() < 3) return false; valtype& vch = stacktop(-3); int nBegin = CastToBigNum(stacktop(-2)).getint(); int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); if (nBegin < 0 || nEnd < nBegin) return false; if (nBegin > vch.size()) nBegin = vch.size(); if (nEnd > vch.size()) nEnd = vch.size(); vch.erase(vch.begin() + nEnd, vch.end()); vch.erase(vch.begin(), vch.begin() + nBegin); popstack(stack); popstack(stack); } break; case OP_LEFT: case OP_RIGHT: { // (in size -- out) if (stack.size() < 2) return false; valtype& vch = stacktop(-2); int nSize = CastToBigNum(stacktop(-1)).getint(); if (nSize < 0) return false; if (nSize > vch.size()) nSize = vch.size(); if (opcode == OP_LEFT) vch.erase(vch.begin() + nSize, vch.end()); else vch.erase(vch.begin(), vch.end() - nSize); popstack(stack); } break; case OP_SIZE: { // (in -- in size) if (stack.size() < 1) return false; CBigNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; // // Bitwise logic // case OP_INVERT: { // (in - out) if (stack.size() < 1) return false; valtype& vch = stacktop(-1); for (int i = 0; i < vch.size(); i++) vch[i] = ~vch[i]; } break; case OP_AND: case OP_OR: case OP_XOR: { // (x1 x2 - out) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); MakeSameSize(vch1, vch2); if (opcode == OP_AND) { for (int i = 0; i < vch1.size(); i++) vch1[i] &= vch2[i]; } else if (opcode == OP_OR) { for (int i = 0; i < vch1.size(); i++) vch1[i] |= vch2[i]; } else if (opcode == OP_XOR) { for (int i = 0; i < vch1.size(); i++) vch1[i] ^= vch2[i]; } popstack(stack); } break; case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL { // (x1 x2 - bool) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); // OP_NOTEQUAL is disabled because it would be too easy to say // something like n != 1 and have some wiseguy pass in 1 with extra // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) //if (opcode == OP_NOTEQUAL) // fEqual = !fEqual; popstack(stack); popstack(stack); stack.push_back(fEqual ? vchTrue : vchFalse); if (opcode == OP_EQUALVERIFY) { if (fEqual) popstack(stack); else return false; } } break; // // Numeric // case OP_1ADD: case OP_1SUB: case OP_2MUL: case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: { // (in -- out) if (stack.size() < 1) return false; CBigNum bn = CastToBigNum(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; case OP_2MUL: bn <<= 1; break; case OP_2DIV: bn >>= 1; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; } popstack(stack); stack.push_back(bn.getvch()); } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_LSHIFT: case OP_RSHIFT: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: { // (x1 x2 -- out) if (stack.size() < 2) return false; CBigNum bn1 = CastToBigNum(stacktop(-2)); CBigNum bn2 = CastToBigNum(stacktop(-1)); CBigNum bn; switch (opcode) { case OP_ADD: bn = bn1 + bn2; break; case OP_SUB: bn = bn1 - bn2; break; case OP_MUL: if (!BN_mul(&bn, &bn1, &bn2, pctx)) return false; break; case OP_DIV: if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) return false; break; case OP_MOD: if (!BN_mod(&bn, &bn1, &bn2, pctx)) return false; break; case OP_LSHIFT: if (bn2 < bnZero || bn2 > CBigNum(2048)) return false; bn = bn1 << bn2.getulong(); break; case OP_RSHIFT: if (bn2 < bnZero || bn2 > CBigNum(2048)) return false; bn = bn1 >> bn2.getulong(); break; case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; case OP_LESSTHAN: bn = (bn1 < bn2); break; case OP_GREATERTHAN: bn = (bn1 > bn2); break; case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; } popstack(stack); popstack(stack); stack.push_back(bn.getvch()); if (opcode == OP_NUMEQUALVERIFY) { if (CastToBool(stacktop(-1))) popstack(stack); else return false; } } break; case OP_WITHIN: { // (x min max -- out) if (stack.size() < 3) return false; CBigNum bn1 = CastToBigNum(stacktop(-3)); CBigNum bn2 = CastToBigNum(stacktop(-2)); CBigNum bn3 = CastToBigNum(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); popstack(stack); stack.push_back(fValue ? vchTrue : vchFalse); } break; // // Crypto // case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: { // (in -- hash) if (stack.size() < 1) return false; valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) RIPEMD160(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA1) SHA1(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA256) SHA256(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_HASH160) { uint160 hash160 = Hash160(vch); memcpy(&vchHash[0], &hash160, sizeof(hash160)); } else if (opcode == OP_HASH256) { uint256 hash = Hash(vch.begin(), vch.end()); memcpy(&vchHash[0], &hash, sizeof(hash)); } popstack(stack); stack.push_back(vchHash); } break; case OP_CODESEPARATOR: { // Hash starts after the code separator pbegincodehash = pc; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: { // (sig pubkey -- bool) if (stack.size() < 2) return false; valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); ////// debug print //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKSIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; if (stack.size() < i) return false; int nKeysCount = CastToBigNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; if (nOpCount > 201) return false; int ikey = ++i; i += nKeysCount; if (stack.size() < i) return false; int nSigsCount = CastToBigNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; i += nSigsCount; if (stack.size() < i) return false; // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signatures, since there's no way for a signature to sign itself for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); scriptCode.FindAndDelete(CScript(vchSig)); } bool fSuccess = true; while (fSuccess && nSigsCount > 0) { valtype& vchSig = stacktop(-isig); valtype& vchPubKey = stacktop(-ikey); // Check signature if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)) { isig++; nSigsCount--; } ikey++; nKeysCount--; // If there are more signatures left than keys left, // then too many signatures have failed if (nSigsCount > nKeysCount) fSuccess = false; } while (i-- > 0) popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; default: return false; } // Size limits if (stack.size() + altstack.size() > 1000) return false; } } catch (...) { return false; } if (!vfExec.empty()) return false; return true; }