bitshares-ui transfer流程
components/Transfer/Transfer.jsx
onSubmit(e) {
...
AccountActions.transfer(
this.state.from_account.get("id"),
this.state.to_account.get("id"),
sendAmount.getAmount(),
asset.get("id"),
this.state.memo
? new Buffer(this.state.memo, "utf-8")
: this.state.memo,
this.state.propose ? this.state.propose_account : null,
this.state.feeAsset ? this.state.feeAsset.get("id") : "1.3.0"
)
.then(() => {
this.resetForm.call(this);
TransactionConfirmStore.unlisten(this.onTrxIncluded);
TransactionConfirmStore.listen(this.onTrxIncluded);
})
.catch(e => {
let msg = e.message
? e.message.split("\n")[1] || e.message
: null;
console.log("error: ", e, msg);
this.setState({error: msg});
});
}
onSubmit会调用actions中的AccountActions.transfer
app/actions/AccountActions.js
transfer(
from_account,
to_account,
amount,
asset,
memo,
propose_account = null,
fee_asset_id = "1.3.0"
) {
// Set the fee asset to use
fee_asset_id = accountUtils.getFinalFeeAsset(
propose_account || from_account,
"transfer",
fee_asset_id
);
try {
return dispatch => {
return ApplicationApi.transfer({
from_account,
to_account,
amount,
asset,
memo,
propose_account,
fee_asset_id
}).then(result => {
// console.log( "transfer result: ", result )
dispatch(result);
});
};
} catch (error) {
console.log(
"[AccountActions.js:90] ----- transfer error ----->",
error
);
return new Promise((resolve, reject) => {
reject(error);
});
}
}
actions只是封装一下简单调用ApplicationApi.transfer
app/api/ApplicationApi.js
转帐的主要实现在这个函数中,函数前面会对取帐号资产数据,并对memo加密等,真正的交易执行在以下代码:
let tr = new TransactionBuilder();
let transfer_op = tr.get_type_operation("transfer", {
fee: {
amount: 0,
asset_id: fee_asset_id
},
from: chain_from.get("id"),
to: chain_to.get("id"),
amount: {amount, asset_id: chain_asset.get("id")},
memo: memo_object
});
return tr.update_head_block().then(() => {
if (propose_account) {
tr.add_type_operation("proposal_create", {
proposed_ops: [{op: transfer_op}],
fee_paying_account: propose_acount_id
});
} else {
tr.add_operation(transfer_op);
}
return WalletDb.process_transaction(
tr,
null, //signer_private_keys,
broadcast
);
});
})
生成TransactionBuilder对象,通过get_type_operation取得传输数据,并add_operation加到operation列表中,最后调用WalletDb.process_transaction
app/stores/WalletDB.js
process_transaction(tr, signer_pubkeys, broadcast, extra_keys = []) {
... 签名处理
.then(() => {
if (broadcast) {
if (this.confirm_transactions) {
let p = new Promise((resolve, reject) => {
TransactionConfirmActions.confirm(
tr,
resolve,
reject
);
});
return p;
} else return tr.broadcast();
} else return tr.serialize();
});
调用到TransactionBuilder的broadcast
bitsharesjs/dist/chain/src/TransactionBuilder.js
function _broadcast(was_broadcast_callback) {
var _this5 = this;
return new Promise(function (resolve, reject) {
...
var tr_object = ops.signed_transaction.toObject(_this5);
// console.log('... broadcast_transaction_with_callback !!!')
Apis.instance().network_api().exec("broadcast_transaction_with_callback", [function (res) {
return resolve(res);
}, tr_object]).then(function () {
//console.log('... broadcast success, waiting for callback')
if (was_broadcast_callback) was_broadcast_callback();
return;
}).catch(function (error) {
// console.log may be redundant for network errors, other errors could occur
console.log(error);
var message = error.message;
if (!message) {
message = "";
}
reject(new Error(message + "\n" + 'bitshares-crypto ' + ' digest ' + hash.sha256(_this5.tr_buffer).toString('hex') + ' transaction ' + _this5.tr_buffer.toString('hex') + ' ' + JSON.stringify(tr_object)));
return;
});
return;
});
}
在broadcast_transaction_with_callback执行指定了回调函数,交易的结果会在回调函数中返回。
GrapheneApi.prototype.exec = function exec(method, params) {
return this.ws_rpc.call([this.api_id, method, params]).catch(function (error) {
console.log("!!! GrapheneApi error: ", method, params, error, JSON.stringify(error));
throw error;
});
};
ChainWebSocket.prototype.call = function call(params) {
var _this2 = this;
if (this.ws.readyState !== 1) {
return Promise.reject(new Error('websocket state error:' + this.ws.readyState));
}
var method = params[1];
if (SOCKET_DEBUG) console.log("[ChainWebSocket] >---- call -----> \"id\":" + (this.cbId + 1), JSON.stringify(params));
this.cbId += 1;
if (method === "set_subscribe_callback" || method === "subscribe_to_market" || method === "broadcast_transaction_with_callback" || method === "set_pending_transaction_callback") {
// Store callback in subs map
this.subs[this.cbId] = {
callback: params[2][0]
};
// Replace callback with the callback id
params[2][0] = this.cbId;
}
if (method === "unsubscribe_from_market" || method === "unsubscribe_from_accounts") {
if (typeof params[2][0] !== "function") {
throw new Error("First parameter of unsub must be the original callback");
}
var unSubCb = params[2].splice(0, 1)[0];
// Find the corresponding subscription
for (var id in this.subs) {
if (this.subs[id].callback === unSubCb) {
this.unsub[this.cbId] = id;
break;
}
}
}
var request = {
method: "call",
params: params
};
request.id = this.cbId;
this.send_life = max_send_life;
return new Promise(function (resolve, reject) {
_this2.cbs[_this2.cbId] = {
time: new Date(),
resolve: resolve,
reject: reject
};
_this2.ws.send(JSON.stringify(request));
});
};
以上代码对"broadcast_transaction_with_callback"做了判断,并替换回调处理。
ChainWebSocket.prototype.listener = function listener(response) {
if (SOCKET_DEBUG) console.log("[ChainWebSocket] <---- reply ----<", JSON.stringify(response));
var sub = false,
callback = null;
if (response.method === "notice") {
sub = true;
response.id = response.params[0];
}
if (!sub) {
callback = this.cbs[response.id];
this.responseCbId = response.id;
} else {
callback = this.subs[response.id].callback;
}
if (callback && !sub) {
if (response.error) {
callback.reject(response.error);
} else {
callback.resolve(response.result);
}
delete this.cbs[response.id];
if (this.unsub[response.id]) {
delete this.subs[this.unsub[response.id]];
delete this.unsub[response.id];
}
} else if (callback && sub) {
callback(response.params[1]);
} else {
console.log("Warning: unknown websocket response: ", response);
}
};
transfer不是"notice"消息,会根据response.id找到回调函数,把结果消息callback后,从回调列表中删除。
注意这个函数中一个是cbs数组,一个是subs数组
感谢您阅读 @chaimyu 的帖子,期待您能留言交流!