CReceipt: //收据信息
receipt.from_uid = CUserID(CNickID(from));
receipt.to_uid = CUserID(CNickID(to));
receipt.coin_symbol = quantity.sym.code().to_string();
receipt.coin_amount = quantity.amount;
receipt.code = TRANSFER_ACTUAL_COINS; ///202,
tx.inline_transactions.push_back({contract_name.value, action.value, std::vector<permission>{{authorizer_name.value, wasmio_owner}}, action_data});
struct inline_transaction {
uint64_t contract;
uint64_t action;
std::vector <permission> authorization;
std::vector<char> data;
IMPLEMENT_SERIALIZE (
READWRITE(VARINT(contract ));
READWRITE(VARINT(action ));
READWRITE(authorization);
READWRITE(data);
)
WASM_REFLECT( inline_transaction, (contract)(action)(authorization)(data) )
}
/提交WASM的api
Value submitwasmcontractcalltx( const Array ¶ms, bool fHelp ) {
wasm::name contract_name = wasm::name(params[1].get_str());
if(!get_native_contract_abi(contract_name.value, abi)){
**//非系统合约,获取合约信息**
get_contract(database_account, database_contract, contract_name, contract, contract_store );
}
tx.nTxType = WASM_CONTRACT_TX;
tx.txUid = authorizer.regid;
tx.valid_height = chainActive.Height();
tx.fee_symbol = fee.symbol;
tx.llFees = fee.GetSawiAmount();
///一会执行这个交易
tx.inline_transactions.push_back({contract_name.value, action.value, std::vector<permission>{{authorizer_name.value, wasmio_owner}}, action_data});
/执行交易
std::tuple<bool, string> ret = wallet->CommitTx((CBaseTx * ) & tx);
...
}
到内存池里进行check
CWallet::CommitTx(CBaseTx *pTx) {
LOCK2(cs_main, cs_wallet);
LogPrint(BCLog::INFO, "CommitTx() : %s\n", pTx->ToString(*pCdMan->pAccountCache));
{
//到内存池
if (!::AcceptToMemoryPool(mempool, state, pTx, true)) {
//到未确认交易
bool flag = CWalletDB(strWalletFile).WriteUnconfirmedTx(txid, un
::RelayTransaction(pTx, txid);
return std::make_tuple(flag, message);
}
bool AcceptToMemoryPool(CTxMemPool &pool, CValidationState &state, CBaseTx *pBaseTx,
bool fLimitFree, bool fRejectInsaneFee) {
pool.AddUnchecked(hash, entry, state); ->CheckTxInMemPool()
}
bool CTxMemPool::CheckTxInMemPool(const uint256 &txid, const CTxMemPoolEntry &memPoolEntry, CValidationState &state,
bool bExecute) {
// is it within valid height
.....
emPoolEntry.GetTransaction()->ExecuteTx(context)
}
///WASM contract excecute
bool CWasmContractTx::ExecuteTx(CTxExecuteContext &context) {
......
///< 扣取发起者的手续费
sub_balance(payer, wasm::asset(llFees, wasm::symbol(SYMB::WICC, 8)), database.accountCache);
for (auto& trx: inline_transactions) {
trx_current_for_exception = &trx;
trx_trace.traces.emplace_back();
//执行交易
execute_inline_transaction(trx_trace.traces.back(), trx, trx.contract, database, receipts, 0);
trx_current_for_exception = nullptr;
}
....
//save trx receipts
trace_to_receipts(trx_trace, receipts);
CHAIN_ASSERT( database.txReceiptCache.SetTxReceipts(GetHash(), receipts),
wasm_chain::account_access_exception,
"set tx '%s' receipts failed",
GetHash().ToString())
//set runstep for block fuel sum
nRunStep = run_cost;
return true;
}
CWasmContractTx::execute_inline_transaction(wasm::inline_transaction_trace& trace,
wasm::inline_transaction& trx,
uint64_t receiver,
CCacheWrapper& database,
vector <CReceipt>& receipts,
uint32_t recurse_depth) {
wasm_context wasm_execute_context(*this, trx, database, receipts, mining, recurse_depth);
wasm_execute_context._receiver = receiver;
wasm_execute_context.execute(trace);
}
//执行trace
//这个通过执行后bank的系统合约来增加notiy,来触发用户合约的transfer的接口
void wasm_context::execute(inline_transaction_trace &trace) {
initialize();
///notified
notified.push_back(_receiver);
execute_one(trace); ///如果是合约, 会把合约加入notify
for (uint32_t i = 1; i < notified.size(); ++i) {
_receiver = notified[i];
trace.inline_traces.emplace_back();
execute_one(trace.inline_traces.back());
}
CHAIN_ASSERT( recurse_depth < wasm::max_inline_transaction_depth,
wasm_chain::transaction_exception,
"max inline transaction depth per transaction reached");
//执行合约内部交易的请求
for (auto &inline_trx : inline_transactions) {
trace.inline_traces.emplace_back();
control_trx.execute_inline_transaction(trace.inline_traces.back(), inline_trx,
inline_trx.contract, database, receipts,
recurse_depth + 1);
}
}
void wasm_context::execute_one(inline_transaction_trace &trace) {
//auto start = system_clock::now();
control_trx.recipients_size ++;
trace.trx = trx;
trace.receiver = _receiver;
auto native = find_native_handle(_receiver, trx.action);
if (native) {
//执行内部的transfer
(*native)(*this);
} else {
vector <uint8_t> code = get_code(_receiver);
if (code.size() > 0) {
wasmif.execute(code, this);
}
}
if (contracts_console()) {
print_debug(_receiver, trace);
}
}
//系统合约交易函数
void wasmio_bank_native_transfer(wasm_context &context) {
transfer_data_type transfer_data = wasm::unpack<std::tuple<uint64_t, uint64_t, wasm::asset, string>>(context.trx.data);
auto from = std::get<0>(transfer_data);
auto to = std::get<1>(transfer_data);
auto quantity = std::get<2>(transfer_data);
auto memo = std::get<3>(transfer_data);
....
sub_balance( from_account, quantity, database ); //修改WICC金额
....
add_balance( to_account, quantity, database );
context.require_recipient(from); ///添加notify继续执行 sender
context.require_recipient(to); ///< 当前这个合约
}
}
void wasm_interface::execute(const vector <uint8_t> &code, wasm_context_interface *pWasmContext) {
pWasmContext->pause_billing_timer();
auto pInstantiated_module = get_instantiated_backend(code);
pWasmContext->resume_billing_timer();
//system_clock::time_point start = system_clock::now();
pInstantiated_module->apply(pWasmContext); ///调用到用户的合约
}
///json RPC的执行请求
json_spirit::Value CRPCTable::execute(const string& strMethod,
const json_spirit::Array& params) const {
Value result;
{
if (pcmd->threadSafe)
result = pcmd->actor(params, false);
else if (!pWalletMain) {
LOCK(cs_main);
result = pcmd->actor(params, false);
} else {
LOCK2(cs_main, pWalletMain->cs_wallet);
result = pcmd->actor(params, false);
}
}
}
static void inline_trace_to_receipts(const wasm::inline_transaction_trace& trace,
vector<CReceipt>& receipts,
map<transfer_data_type, uint64_t>& receipts_duplicate_check) {
if (trace.trx.contract == wasmio_bank && trace.trx.action == wasm::N(transfer)) {
CReceipt receipt;
receipt.code = TRANSFER_ACTUAL_COINS;
transfer_data_type transfer_data = wasm::unpack < std::tuple < uint64_t, uint64_t, wasm::asset, string>> (trace.trx.data);
auto from = std::get<0>(transfer_data);
auto to = std::get<1>(transfer_data);
auto quantity = std::get<2>(transfer_data);
auto memo = std::get<3>(transfer_data);
auto itr = receipts_duplicate_check.find(std::tuple(from, to ,quantity, memo));
if (itr == receipts_duplicate_check.end()){
receipts_duplicate_check[std::tuple(from, to ,quantity, memo)] = wasmio_bank;
receipt.from_uid = CUserID(CNickID(from));
receipt.to_uid = CUserID(CNickID(to));
receipt.coin_symbol = quantity.sym.code().to_string();
receipt.coin_amount = quantity.amount;
receipts.push_back(receipt);
}
}
///这个inline_traces 哪里来的
for (auto t: trace.inline_traces) {
inline_trace_to_receipts(t, receipts, receipts_duplicate_check);
}
}
虚拟机是如何响应外部执行需求的,这个主要体现在对外接
层面虚拟机接口对外暴露虚拟机实例创建和合约执行入口,具体声明在如下路径文件中
//这个是合约执行的关键, 回调用用户合约请求
void apply(wasm::wasm_context_interface *pContext) override {
.......
//这个就是调用用户合约定义的apply接口
auto fn = [&]() {
const auto &res = _runtime->_bkend->call(
pContext, "env", "apply", pContext->receiver(),
pContext->contract(),
pContext->action());
}
//收据的生成,递归生成
static void inline_trace_to_receipts(const wasm::inline_transaction_trace& trace,
vector<CReceipt>& receipts,
map<transfer_data_type, uint64_t>& receipts_duplicate_check) {
if (trace.trx.contract == wasmio_bank && trace.trx.action == wasm::N(transfer)) {
CReceipt receipt;
receipt.code = TRANSFER_ACTUAL_COINS;
transfer_data_type transfer_data = wasm::unpack < std::tuple < uint64_t, uint64_t, wasm::asset, string>> (trace.trx.data);
auto from = std::get<0>(transfer_data);
auto to = std::get<1>(transfer_data);
auto quantity = std::get<2>(transfer_data);
auto memo = std::get<3>(transfer_data);
auto itr = receipts_duplicate_check.find(std::tuple(from, to ,quantity, memo));
if (itr == receipts_duplicate_check.end()){
receipts_duplicate_check[std::tuple(from, to ,quantity, memo)] = wasmio_bank;
receipt.from_uid = CUserID(CNickID(from));
receipt.to_uid = CUserID(CNickID(to));
receipt.coin_symbol = quantity.sym.code().to_string();
receipt.coin_amount = quantity.amount;
receipts.push_back(receipt);
}
}
for (auto t: trace.inline_traces) {
inline_trace_to_receipts(t, receipts, receipts_duplicate_check);
}
}
合约的接口是如何让主要程序调用
提供了api 底层调用
extern "C" {
void apply(uint64_t receiver, uint64_t code, uint64_t action) {
wasm::execute_action( wasm::name(receiver), wasm::name(code), &eidos::close );
bool execute_action( name self, name code, void (T::*func)(Args...) ) {
size_t size = action_data_size();
//using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions
constexpr size_t max_stack_buffer_size = 512;
void* buffer = nullptr;
if( size > 0 ) {
buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size);
read_action_data( buffer, size );
}
std::tuple<std::decay_t<Args>...> args;
datastream<const char*> ds((char*)buffer, size);
ds >> args;
T inst(self, code, ds);
auto f2 = [&]( auto... a ){
((&inst)->*func)( a... );
};
boost::mp11::tuple_apply( f2, args );
if ( max_stack_buffer_size < size ) {
free(buffer);
}
return true;
}