//TODO add input and output values names std::vector<double> Snakes::calculateOutput(std::vector<double> input, QString scriptFileName) { namespace py = boost::python; std::vector<double> output; //QString to const char* QByteArray byteArray = scriptFileName.toLatin1(); const char *filename = byteArray.data(); Py_Initialize(); py::object main_module = py::import("__main__"); py::object main_namespace = main_module.attr("__dict__"); try { for (int i = 0; i < input.size(); i++) { main_namespace["inputValue"] = input[i]; py::object noneType = py::exec_file(filename, main_namespace); const double res = py::extract<double>(main_namespace["outputValue"]); output.push_back(res); } } catch (...) { throw ScriptException("Failed to load script"); } return output; }
//----------------------------------------------------------------------------// bool LuaScriptModule::executeScriptedEventHandler_impl( const String& handler_name, const EventArgs& e, const int err_idx, const int top) { LuaFunctor::pushNamedFunction(d_state, handler_name); // push EventArgs as the first parameter tolua_pushusertype(d_state, (void*)&e, "const CEGUI::EventArgs"); // call it int error = lua_pcall(d_state, 1, 1, err_idx); // handle errors if (error) { String errStr(lua_tostring(d_state,-1)); lua_settop(d_state,top); CEGUI_THROW(ScriptException("Unable to evaluate the Lua event " "handler: '" + handler_name + "'\n\n" + errStr + "\n")); } // retrieve result bool ret = lua_isboolean(d_state, -1) ? lua_toboolean(d_state, -1 ) : true; lua_settop(d_state,top); return ret; }
/************************************************************************* Call operator *************************************************************************/ bool LuaFunctor::operator()(const EventArgs& args) const { // named error handler needs binding? if ((d_errFuncIndex == LUA_NOREF) && !d_errFuncName.empty()) { pushNamedFunction(L, d_errFuncName); d_errFuncIndex = luaL_ref(L, LUA_REGISTRYINDEX); d_ourErrFuncIndex = true; } // is this a late binding? if (needs_lookup) { pushNamedFunction(L, function_name); // reference function index = luaL_ref(L, LUA_REGISTRYINDEX); needs_lookup = false; CEGUI_LOGINSANE("Late binding of callback '"+function_name+"' performed"); function_name.clear(); } // put error handler on stack if we're using such a thing int err_idx = 0; if (d_errFuncIndex != LUA_NOREF) { lua_rawgeti(L, LUA_REGISTRYINDEX, d_errFuncIndex); err_idx = lua_gettop(L); } // retrieve function lua_rawgeti(L, LUA_REGISTRYINDEX, index); // possibly self as well? int nargs = 1; if (self != LUA_NOREF) { lua_rawgeti(L, LUA_REGISTRYINDEX, self); ++nargs; } // push EventArgs parameter tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs"); // call it int error = lua_pcall(L, nargs, 1, err_idx); // handle errors if (error) { String errStr(lua_tostring(L, -1)); lua_pop(L, 1); CEGUI_THROW(ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n")); } // retrieve result bool ret = lua_isboolean(L, -1) ? lua_toboolean(L, -1 ) : true; lua_pop(L, 1); return ret; }
void StackInterpreter::process_p2wsh(const BinaryData& scriptHash) { //get witness data auto witnessData = txStubPtr_->getWitnessData(inputIndex_); BinaryData witBD(witnessData); //prepare stack BinaryRefReader brr(witnessData); auto itemCount = brr.get_uint8_t(); for (unsigned i = 0; i < itemCount; i++) { auto len = brr.get_var_int(); stack_.push_back(brr.get_BinaryData(len)); } if (brr.getSizeRemaining() != 0) throw ScriptException("witness size mismatch"); flags_ |= SCRIPT_VERIFY_P2SH_SHA256; //construct output script auto&& swScript = BtcUtils::getP2WSHScript(scriptHash); processScript(swScript, true); }
bool TransactionVerifier::checkSig(unsigned inputId) const { //grab the uxto auto&& input = theTx_.getTxInRef(inputId); if (input.getSize() < 41) throw ScriptException("unexpected txin size"); //grab input script BinaryRefReader inputBrr(input); auto&& txHashRef = inputBrr.get_BinaryDataRef(32); auto outputId = inputBrr.get_uint32_t(); auto scriptSize = inputBrr.get_var_int(); auto&& inputScript = inputBrr.get_BinaryDataRef(scriptSize); auto utxoIter = utxos_.find(txHashRef); if (utxoIter == utxos_.end()) return false; auto& idMap = utxoIter->second; auto idIter = idMap.find(outputId); if (idIter == idMap.end()) return false; //grab output script auto& utxo = idIter->second; auto& outputScript = utxo.getScript(); //init stack StackInterpreter sstack(this, inputId); auto flags = sstack.getFlags(); flags |= flags_; sstack.setFlags(flags); if (theTx_.usesWitness_) { //reuse the sighash data object with segwit tx to leverage the pre state if (sigHashDataObject_ == nullptr) sigHashDataObject_ = make_shared<SigHashDataSegWit>(); sstack.setSegWitSigHashDataObject(sigHashDataObject_); } if ((flags_ & SCRIPT_VERIFY_SEGWIT) && inputScript.getSize() == 0) { sstack.processSW(outputScript); } else { sstack.processScript(inputScript, false); BinaryData inputScriptBD(inputScript); //process script sstack.processScript(outputScript, true); } sstack.checkState(); return true; }
void StackResolver::resolveStack() { auto resolveReferenceValue = []( shared_ptr<ReversedStackEntry> inPtr)->BinaryData { auto currentPtr = inPtr; while (1) { if (currentPtr->parent_ != nullptr) { currentPtr = currentPtr->parent_; } else if (currentPtr->static_) { return currentPtr->staticData_; } else { switch (currentPtr->resolvedValue_->type()) { case StackValueType_Static: { auto staticVal = dynamic_pointer_cast<StackValue_Static>( currentPtr->resolvedValue_); return staticVal->value_; } case StackValueType_FromFeed: { auto feedVal = dynamic_pointer_cast<StackValue_FromFeed>( currentPtr->resolvedValue_); return feedVal->value_; } case StackValueType_Reference: { auto refVal = dynamic_pointer_cast<StackValue_Reference>( currentPtr->resolvedValue_); currentPtr = refVal->valueReference_; break; } default: throw ScriptException("unexpected StackValue type \ during reference resolution"); } } if (currentPtr == inPtr) throw ScriptException("infinite loop in reference resolution"); } };
//----------------------------------------------------------------------------// int LuaScriptModule::executeScriptGlobal_impl(const String& function_name, const int err_idx, const int top) { // get the function from lua lua_getglobal(d_state, function_name.c_str()); // is it a function if (!lua_isfunction(d_state,-1)) { lua_settop(d_state,top); CEGUI_THROW(ScriptException("Unable to get Lua global: '" + function_name + "' as name not represent a global Lua function" )); } // call it int error = lua_pcall(d_state, 0, 1, err_idx); // handle errors if (error) { String errMsg = lua_tostring(d_state,-1); lua_settop(d_state,top); CEGUI_THROW(ScriptException("Unable to evaluate Lua global: '" + function_name + "\n\n" + errMsg + "\n")); } // get return value if (!lua_isnumber(d_state,-1)) { // log that return value is invalid. return -1 and move on. lua_settop(d_state,top); ScriptException("Unable to get Lua global : '" + function_name + "' return value as it's not a number"); return -1; } int ret = static_cast<int>(lua_tonumber(d_state,-1)); lua_settop(d_state,top); // return it return ret; }
float Table::getNumber( int index ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_rawgeti( m_lua, -1, index ); if ( lua_type(m_lua,-1) != LUA_TNUMBER ) throw ScriptException( Format("Tried to get number from table but type was invalid ({1})", lua_type(m_lua,-1)) ); return lua_tonumber( m_lua, -1 ); }
void* Table::getUserData( int index ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_rawgeti( m_lua, -1, index ); if ( !lua_isuserdata(m_lua,-1) ) throw ScriptException( Format("Tried to use script object type({0}) as user data", lua_type(m_lua,-1)) ); return lua_touserdata( m_lua, -1 ); }
unsigned TransactionVerifier::getTxInSequence(unsigned inputID) const { if (inputID > theTx_.txins_.size()) throw ScriptException("invalid txin index"); auto& inputOnS = theTx_.txins_[inputID]; auto sequenceOffset = inputOnS.first + inputOnS.second - 4; auto sequence = (unsigned*)(theTx_.data_ + sequenceOffset); return *sequence; }
float Table::getNumber( const String& name ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_pushUTF8( m_lua, name ); lua_rawget( m_lua, -2 ); if ( lua_type(m_lua,-1) != LUA_TNUMBER ) throw ScriptException( Format("Tried to get number {0} from table but type was invalid ({1})", name, lua_type(m_lua,-1)) ); return lua_tonumber( m_lua, -1 ); }
bool Table::getBoolean( const String& name ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_pushUTF8( m_lua, name ); lua_rawget( m_lua, -2 ); if ( lua_type(m_lua,-1) != LUA_TNUMBER && !lua_isnil(m_lua,-1) ) throw ScriptException( Format("Tried to get boolean {0} from table but type was invalid ({1})", name, lua_type(m_lua,-1)) ); return !lua_isnil( m_lua, -1 ); }
void* Table::getUserData( const String& name ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_pushUTF8( m_lua, name ); lua_rawget( m_lua, -2 ); if ( !lua_isuserdata(m_lua,-1) ) throw ScriptException( Format("Tried to use script object {0} type({1}) as user data", name, lua_type(m_lua,-1)) ); return lua_touserdata( m_lua, -1 ); }
void StackInterpreter::op_checksig() { //pop sig and pubkey from the stack if (stack_.size() < 2) throw ScriptException("insufficient stack size for checksig operation"); auto&& pubkey = pop_back(); auto&& sigScript = pop_back(); if (sigScript.getSize() < 65) { stack_.push_back(move(intToRawBinary(false))); return; } txInEvalState_.n_ = 1; txInEvalState_.m_ = 1; //extract sig and sighash type BinaryRefReader brrSig(sigScript); auto sigsize = sigScript.getSize() - 1; auto sig = brrSig.get_BinaryDataRef(sigsize); auto hashType = getSigHashSingleByte(brrSig.get_uint8_t()); //get data for sighash if (sigHashDataObject_ == nullptr) sigHashDataObject_ = make_shared<SigHashDataLegacy>(); auto&& sighashdata = sigHashDataObject_->getDataForSigHash(hashType, *txStubPtr_, outputScriptRef_, inputIndex_); //prepare pubkey BTC_ECPOINT ptPub; CryptoPP::ECP ecp = CryptoECDSA::Get_secp256k1_ECP(); ecp.DecodePoint(ptPub, (byte*)pubkey.getPtr(), pubkey.getSize()); BTC_PUBKEY cppPubKey; cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), ptPub); //check point validity /*BTC_PRNG prng; if (!cppPubKey.Validate(prng, 3)) throw ScriptException("invalid pubkey");*/ //check signature auto&& rs = BtcUtils::extractRSFromDERSig(sig); bool result = CryptoECDSA().VerifyData(sighashdata, rs, cppPubKey); stack_.push_back(move(intToRawBinary(result))); if (result) txInEvalState_.pubKeyState_.insert(make_pair(pubkey, true)); }
void handleException(TryCatch& tc) { Logging::log(Logging::ERROR, "V8 exception:\r\n"); HandleScope handleScope; Handle<Object> exception = tc.Exception()->ToObject(); String::AsciiValue exception_str(exception); Logging::log(Logging::ERROR, " : %s\r\n", *exception_str); /* Handle<Array> names = exception->GetPropertyNames(); for (unsigned int i = 0; i < names->Length(); i++) { std::string strI = Utility::toString((int)i); Logging::log(Logging::ERROR, " %d : %s : %s\r\n", i, *(v8::String::Utf8Value(names->Get(String::New(strI.c_str()))->ToString())), *(v8::String::Utf8Value(exception->Get(names->Get(String::New(strI.c_str()))->ToString())->ToString())) ); } */ Local<Message> message = tc.Message(); Logging::log(Logging::ERROR, "Message: Get: %s\r\n", *(v8::String::Utf8Value( message->Get() ))); Logging::log(Logging::ERROR, "Message: GetSourceLine: %s\r\n", *(v8::String::Utf8Value( message->GetSourceLine() ))); Logging::log(Logging::ERROR, "Message: GetScriptResourceName: %s\r\n", *(v8::String::Utf8Value( message->GetScriptResourceName()->ToString() ))); Logging::log(Logging::ERROR, "Message: GetLineNumber: %d\r\n", message->GetLineNumber() ); Local<Value> stackTrace = tc.StackTrace(); if (!stackTrace.IsEmpty()) { Logging::log(Logging::ERROR, "Stack trace: %s\r\n", *(v8::String::Utf8Value( stackTrace->ToString() ))); printf("\r\n\r\n^Stack trace^: %s\r\n", *(v8::String::Utf8Value( stackTrace->ToString() ))); } else Logging::log(Logging::ERROR, "No stack trace available in C++ handler (see above for possible in-script stack trace)\r\n"); #ifdef SERVER std::string clientMessage = *(v8::String::Utf8Value( message->Get() )); clientMessage += " - "; clientMessage += *(v8::String::Utf8Value( message->GetSourceLine() )); ServerSystem::fatalMessageToClients(clientMessage); #endif // assert(0); throw ScriptException("Bad!"); }
Table Table::getTable( int index ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_rawgeti( m_lua, -1, index ); if ( !lua_istable(m_lua,-1) ) throw ScriptException( Format("Tried to get table from table but type was invalid ({1})", lua_type(m_lua,-1)) ); Table tab; tab.m_lua = m_lua; tab.m_ref = lua_ref( m_lua, true ); return tab; }
Table Table::getTable( const String& name ) { assert( m_ref >= 0 ); RestoreStack rs( m_lua ); lua_getref( m_lua, m_ref ); lua_pushUTF8( m_lua, name ); lua_rawget( m_lua, -2 ); if ( !lua_istable(m_lua,-1) ) throw ScriptException( Format("Tried to get table {0} from table but type was invalid ({1})", name, lua_type(m_lua,-1)) ); Table tab; tab.m_lua = m_lua; tab.m_ref = lua_ref( m_lua, true ); return tab; }
//----------------------------------------------------------------------------// void LuaScriptModule::executeString_impl(const String& str, const int err_idx, const int top) { // load code into lua and call it int error = luaL_loadbuffer(d_state, str.c_str(), str.length(), str.c_str()) || lua_pcall(d_state, 0, 0, err_idx); // handle errors if (error) { String errMsg = lua_tostring(d_state,-1); lua_settop(d_state,top); CEGUI_THROW(ScriptException("Unable to execute Lua script string: '" + str + "'\n\n" + errMsg + "\n")); } lua_settop(d_state,top); }
void StackInterpreter::processOpCode(const OpCode& oc) { ++opcount_; //handle push data by itself, doesn't play well with switch if (oc.opcode_ == 0) { op_0(); return; } if (oc.opcode_ <= 75) { stack_.push_back(oc.dataRef_); return; } if (oc.opcode_ < 79) { //op push data stack_.push_back(oc.dataRef_); return; } if (oc.opcode_ == OP_1NEGATE) { op_1negate(); return; } if (oc.opcode_ <= 96 && oc.opcode_ >= 81) { //op_1 - op_16 uint8_t val = oc.opcode_ - 80; stack_.push_back(move(intToRawBinary(val))); return; } //If we got this far this op code is not push data. If this is the input //script, set the flag as per P2SH parsing rules (only push data in inputs) if (outputScriptRef_.getSize() == 0) onlyPushDataInInput_ = false; switch (oc.opcode_) { case OP_NOP: break; case OP_IF: { BinaryRefReader brr(oc.dataRef_); op_if(brr, false); break; } case OP_NOTIF: { op_not(); BinaryRefReader brr(oc.dataRef_); op_if(brr, false); break; } case OP_ELSE: //processed by opening if statement throw ScriptException("a wild else appears"); case OP_ENDIF: //processed by opening if statement throw ScriptException("a wild endif appears"); case OP_VERIFY: op_verify(); break; case OP_TOALTSTACK: op_toaltstack(); break; case OP_FROMALTSTACK: op_fromaltstack(); break; case OP_IFDUP: op_ifdup(); break; case OP_2DROP: { stack_.pop_back(); stack_.pop_back(); break; } case OP_2DUP: op_2dup(); break; case OP_3DUP: op_3dup(); break; case OP_2OVER: op_2over(); break; case OP_DEPTH: op_depth(); break; case OP_DROP: stack_.pop_back(); break; case OP_DUP: op_dup(); break; case OP_NIP: op_nip(); break; case OP_OVER: op_over(); break; case OP_PICK: op_pick(); break; case OP_ROLL: op_roll(); break; case OP_ROT: op_rot(); break; case OP_SWAP: op_swap(); break; case OP_TUCK: op_tuck(); break; case OP_SIZE: op_size(); break; case OP_EQUAL: { op_equal(); if (onlyPushDataInInput_ && p2shScript_.getSize() != 0) { //check the op_equal result op_verify(); if (!isValid_) break; if (flags_ & SCRIPT_VERIFY_SEGWIT) if (p2shScript_.getSize() == 22 || p2shScript_.getSize() == 34) { auto versionByte = p2shScript_.getPtr(); if (*versionByte <= 16) { processSW(p2shScript_); return; } } processScript(p2shScript_, true); } break; } case OP_EQUALVERIFY: { op_equal(); op_verify(); break; } case OP_1ADD: op_1add(); break; case OP_1SUB: op_1sub(); break; case OP_NEGATE: op_negate(); break; case OP_ABS: op_abs(); break; case OP_NOT: op_not(); break; case OP_0NOTEQUAL: op_0notequal(); break; case OP_ADD: op_add(); break; case OP_SUB: op_sub(); break; case OP_BOOLAND: op_booland(); break; case OP_BOOLOR: op_boolor(); break; case OP_NUMEQUAL: op_numequal(); break; case OP_NUMEQUALVERIFY: { op_numequal(); op_verify(); break; } case OP_NUMNOTEQUAL: op_numnotequal(); break; case OP_LESSTHAN: op_lessthan(); break; case OP_GREATERTHAN: op_greaterthan(); break; case OP_LESSTHANOREQUAL: op_lessthanorequal(); break; case OP_GREATERTHANOREQUAL: op_greaterthanorequal(); break; case OP_MIN: op_min(); break; case OP_MAX: op_max(); break; case OP_WITHIN: op_within(); break; case OP_RIPEMD160: op_ripemd160(); break; case OP_SHA256: { //save the script if this output is a possible p2sh if (flags_ & SCRIPT_VERIFY_P2SH_SHA256) if (opcount_ == 1 && onlyPushDataInInput_) p2shScript_ = stack_back(); op_sha256(); break; } case OP_HASH160: { //save the script if this output is a possible p2sh if (flags_ & SCRIPT_VERIFY_P2SH) if (opcount_ == 1 && onlyPushDataInInput_) p2shScript_ = stack_back(); op_hash160(); break; } case OP_HASH256: op_hash256(); break; case OP_CODESEPARATOR: { opcount_ = 0; if (outputScriptRef_.getSize() != 0) txStubPtr_->setLastOpCodeSeparator(inputIndex_, oc.offset_); break; } case OP_CHECKSIG: op_checksig(); break; case OP_CHECKSIGVERIFY: { op_checksig(); op_verify(); break; } case OP_CHECKMULTISIG: op_checkmultisig(); break; case OP_CHECKMULTISIGVERIFY: { op_checkmultisig(); op_verify(); } case OP_NOP1: break; case OP_NOP2: { if (!(flags_ & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) break; // not enabled; treat as a NOP //CLTV mechanics throw ScriptException("OP_CLTV not supported"); } case OP_NOP3: { if (!(flags_ & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) break; // not enabled; treat as a NOP //CSV mechanics throw ScriptException("OP_CSV not supported"); } case OP_NOP4: break; case OP_NOP5: break; case OP_NOP6: break; case OP_NOP7: break; case OP_NOP8: break; case OP_NOP9: break; case OP_NOP10: break; default: { stringstream ss; ss << "unknown opcode: " << (unsigned)oc.opcode_; throw runtime_error(ss.str()); } } }
/************************************************************************* Pushes a named function on the stack *************************************************************************/ void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name) { int top = lua_gettop(L); // do we have any dots in the handler name? if so we grab the function as a table field String::size_type i = handler_name.find_first_of((utf32)'.'); if (i!=String::npos) { // split the rest of the string up in parts seperated by '.' // TODO: count the dots and size the vector accordingly from the beginning. std::vector<String> parts; String::size_type start = 0; do { parts.push_back(handler_name.substr(start,i-start)); start = i+1; i = handler_name.find_first_of((utf32)'.',start); } while(i!=String::npos); // add last part parts.push_back(handler_name.substr(start)); // first part is the global lua_getglobal(L, parts[0].c_str()); if (!lua_istable(L,-1)) { lua_settop(L,top); CEGUI_THROW(ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table")); } // if there is more than two parts, we have more tables to go through std::vector<String>::size_type visz = parts.size(); if (visz-- > 2) // avoid subtracting one later on { // go through all the remaining parts to (hopefully) have a valid Lua function in the end std::vector<String>::size_type vi = 1; while (vi<visz) { // push key, and get the next table lua_pushstring(L,parts[vi].c_str()); lua_gettable(L,-2); if (!lua_istable(L,-1)) { lua_settop(L,top); CEGUI_THROW(ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table")); } // get rid of the last table and move on lua_remove(L,-2); vi++; } } // now we are ready to get the function to call ... phew :) lua_pushstring(L,parts[visz].c_str()); lua_gettable(L,-2); lua_remove(L,-2); // get rid of the table } // just a regular global function else { lua_getglobal(L, handler_name.c_str()); } // is it a function if (!lua_isfunction(L,-1)) { lua_settop(L,top); CEGUI_THROW(ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function")); } }
void StackResolver::processOpCode(const OpCode& oc) { if (oc.opcode_ >= 1 && oc.opcode_ <= 75) { pushdata(oc.dataRef_); return; } if (oc.opcode_ >= 81 && oc.opcode_ <= 96) { unsigned val = oc.opcode_ - 80; push_int(val); return; } opCodeCount_++; switch (oc.opcode_) { case OP_0: pushdata(BinaryData()); break; case OP_PUSHDATA1: case OP_PUSHDATA2: case OP_PUSHDATA4: pushdata(oc.dataRef_); break; case OP_DUP: op_dup(); break; case OP_HASH160: case OP_SHA256: { opHash_ = true; op_1item_verify(oc); break; } case OP_RIPEMD160: case OP_HASH256: op_1item_verify(oc); break; case OP_EQUAL: { if (opCodeCount_ == 2 && opHash_) isP2SH_ = true; op_2items(oc); break; } case OP_CHECKSIG: op_2items(oc); break; case OP_EQUALVERIFY: case OP_CHECKSIGVERIFY: op_2items_verify(oc); break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: push_op_code(oc); break; default: throw ScriptException("opcode not implemented with reverse stack"); } }
SIGHASH_TYPE StackInterpreter_BCH::getSigHashSingleByte(uint8_t sighashbyte) const { if (!(sighashbyte & 0x40)) throw ScriptException("invalid sighash for bch sig"); return SIGHASH_TYPE(sighashbyte & 0xBF); }
void StackInterpreter::op_checkmultisig() { //stack needs to have at least m, n, output script if (stack_.size() < 3) throw ScriptException("insufficient stack size for checkmultisig operation"); //pop n auto&& n = pop_back(); auto nI = rawBinaryToInt(n); if (nI < 0 || nI > 20) throw ScriptException("invalid n"); //pop pubkeys map<unsigned, pair<BTC_PUBKEY, BinaryData>> pubkeys; for (unsigned i = 0; i < nI; i++) { auto&& pubkey = pop_back(); CryptoPP::ECP ecp = CryptoECDSA::Get_secp256k1_ECP(); BTC_ECPOINT ptPub; ecp.DecodePoint(ptPub, (byte*)pubkey.getPtr(), pubkey.getSize()); BTC_PUBKEY cppPubKey; cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), ptPub); BTC_PRNG prng; if (cppPubKey.Validate(prng, 3)) { txInEvalState_.pubKeyState_.insert(make_pair(pubkey, false)); auto&& pubkeypair = make_pair(move(cppPubKey), pubkey); pubkeys.insert(move(make_pair(i, move(pubkeypair)))); } } //pop m auto&& m = pop_back(); auto mI = rawBinaryToInt(m); if (mI < 0 || mI > nI) throw ScriptException("invalid m"); txInEvalState_.n_ = nI; txInEvalState_.m_ = mI; //pop sigs struct sigData { BinaryData sig_; SIGHASH_TYPE hashType_; }; vector<sigData> sigVec; while (stack_.size() > 0) { auto&& sig = pop_back(); if (sig.getSize() == 0) break; sigData sdata; sdata.sig_ = sig.getSliceCopy(0, sig.getSize() - 1); //grab hash type sdata.hashType_ = getSigHashSingleByte(*(sig.getPtr() + sig.getSize() - 1)); //push to vector sigVec.push_back(move(sdata)); } //should have at least as many sigs as m /*if (sigVec.size() < mI) throw ScriptException("invalid sig count");*/ //check sigs map<SIGHASH_TYPE, BinaryData> dataToHash; //check sighashdata object if (sigHashDataObject_ == nullptr) sigHashDataObject_ = make_shared<SigHashDataLegacy>(); unsigned validSigCount = 0; int index = nI - 1; auto sigIter = sigVec.rbegin(); while(sigIter != sigVec.rend()) { auto& sigD = *sigIter++; //get data to hash auto& hashdata = dataToHash[sigD.hashType_]; if (hashdata.getSize() == 0) { hashdata = sigHashDataObject_->getDataForSigHash( sigD.hashType_, *txStubPtr_, outputScriptRef_, inputIndex_); } //prepare sig auto&& rs = BtcUtils::extractRSFromDERSig(sigD.sig_); BinaryWriter sigW; //pop pubkeys from deque to verify against sig while (pubkeys.size() > 0) { auto pubkey = pubkeys[index]; pubkeys.erase(index--); #ifdef SIGNER_DEBUG LOGWARN << "Verifying sig for: "; LOGWARN << " pubkey: " << pubkey.second.toHexStr(); auto&& msg_hash = BtcUtils::getHash256(hashdata); LOGWARN << " message: " << hashdata.toHexStr(); #endif if (CryptoECDSA().VerifyData(hashdata, rs, pubkey.first)) { txInEvalState_.pubKeyState_[pubkey.second] = true; validSigCount++; break; } } } if (validSigCount >= mI) op_true(); else op_0(); }