Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas) { if (_t.isCreation()) return Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); else return Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); }
Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret) { Transaction ret; if (_secret) { if (_t.isCreation()) ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); else ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); } else { if (_t.isCreation()) ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); else ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); ret.forceSender(_t.safeSender()); } return ret; }
void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { for (auto& i: _v.get_obj()) { cerr << i.first << endl; mObject& o = i.second.get_obj(); if (_fillin) { TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); //Construct Rlp of the given transaction RLPStream rlpStream = createRLPStreamFromTransactionFields(tObj); o["rlp"] = toHex(rlpStream.out(), 2, HexPrefix::Add); try { Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); if (!txFromFields.signature().isValid()) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); o["sender"] = toString(txFromFields.sender()); o["transaction"] = ImportTest::makeAllFieldsHex(tObj); } catch(Exception const& _e) { //Transaction is InValid cnote << "Transaction Exception: " << diagnostic_information(_e); o.erase(o.find("transaction")); if (o.count("expect") > 0) { bool expectInValid = (o["expect"].get_str() == "invalid"); if (Options::get().checkState) {TBOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} else {TBOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} o.erase(o.find("expect")); } } //Transaction is Valid if (o.count("expect") > 0) { bool expectValid = (o["expect"].get_str() == "valid"); if (Options::get().checkState) {TBOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} else {TBOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} o.erase(o.find("expect")); } } else { TBOOST_REQUIRE((o.count("rlp") > 0)); Transaction txFromRlp; try { bytes stream = importByteArray(o["rlp"].get_str()); RLP rlp(stream); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); if (!txFromRlp.signature().isValid()) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } catch(Exception const& _e) { cnote << i.first; cnote << "Transaction Exception: " << diagnostic_information(_e); TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } catch(...) { TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything); //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!"); TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!"); TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!"); TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!"); TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!"); TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!"); TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!"); TBOOST_REQUIRE ((o.count("sender") > 0)); Address addressReaded = Address(o["sender"].get_str()); TBOOST_CHECK_MESSAGE((txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded), "Signature address of sender does not match given sender address!"); } }//for }//doTransactionTests
// TODO: prototype changed - will need rejigging. ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, EnvInfo const& _envInfo, bool _call) { State execState = _state; execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation eth::ExecutionResult er; Executive execution(execState, _envInfo); execution.setResultRecipient(er); execution.initialize(_t); execution.execute(); std::vector<MachineState> machineStates; std::vector<unsigned> levels; std::vector<MachineCode> codes; std::map<bytes const*, unsigned> codeIndexes; std::vector<bytes> data; std::map<bytesConstRef const*, unsigned> dataIndexes; bytes const* lastCode = nullptr; bytesConstRef const* lastData = nullptr; unsigned codeIndex = 0; unsigned dataIndex = 0; auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, void* voidVM, void const* voidExt) { VM& vm = *static_cast<VM*>(voidVM); ExtVM const& ext = *static_cast<ExtVM const*>(voidExt); if (lastCode == nullptr || lastCode != &ext.code) { auto const& iter = codeIndexes.find(&ext.code); if (iter != codeIndexes.end()) codeIndex = iter->second; else { codeIndex = codes.size(); codes.push_back(MachineCode({ext.myAddress, ext.code})); codeIndexes[&ext.code] = codeIndex; } lastCode = &ext.code; } if (lastData == nullptr || lastData != &ext.data) { auto const& iter = dataIndexes.find(&ext.data); if (iter != dataIndexes.end()) dataIndex = iter->second; else { dataIndex = data.size(); data.push_back(ext.data.toBytes()); dataIndexes[&ext.data] = dataIndex; } lastData = &ext.data; } if (levels.size() < ext.depth) levels.push_back(machineStates.size() - 1); else levels.resize(ext.depth); machineStates.push_back(MachineState{ steps, vm.curPC(), inst, newMemSize, static_cast<u256>(gas), vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), std::move(levels), codeIndex, dataIndex }); }; execution.go(onOp); execution.finalize(); switch (er.excepted) { case TransactionException::None: break; case TransactionException::NotEnoughCash: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); case TransactionException::OutOfGasIntrinsic: case TransactionException::OutOfGasBase: case TransactionException::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); case TransactionException::BlockGasLimitReached: BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); case TransactionException::BadJumpDestination: BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Solidity exception (bad jump)")); case TransactionException::OutOfStack: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); case TransactionException::StackUnderflow: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); //these should not happen in mix case TransactionException::Unknown: case TransactionException::BadInstruction: case TransactionException::InvalidSignature: case TransactionException::InvalidNonce: case TransactionException::InvalidFormat: case TransactionException::BadRLP: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); } ExecutionResult d; d.inputParameters = _t.data(); d.result = er; d.machineStates = machineStates; d.executionCode = std::move(codes); d.transactionData = std::move(data); d.address = _t.receiveAddress(); d.sender = _t.sender(); d.value = _t.value(); d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; if (_t.isCreation()) d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); if (!_call) d.transactionIndex = m_postMine.pending().size(); d.executonIndex = m_executions.size(); return d; }