场景
由于一些场景需要提前计算出上传的交易ID,
类似问题,已提交issue https://github.com/EOSIO/eos/issues/7816
由于一些问题,(猜测单个nodeos推送了太多事务)导致事务推送返回超时,但实际上事务已成功推送。我暂时想到的解决方案是,我希望在提交交易之前预先计算交易的ID,以便在重复交易时首先确定交易ID是否已经存在。搜索之后,我发现'cleos get transaction_id'(#6830)似乎是我想要的功能,但是测试不同的数据,总是返回相同的id。我用方法问题?或者这个功能没有像这样使用
跟进
先提前跟一下代码
cleos get transaction_id
https://github.com/EOSIO/eos/blob/1418543149b7caf8fc69a23621e3db7f3c6d18ad/programs/cleos/main.cpp#L1306
struct get_transaction_id_subcommand {
string trx_to_check;
get_transaction_id_subcommand(CLI::App* actionRoot) {
auto get_transaction_id = actionRoot->add_subcommand("transaction_id", localized("Get transaction id given transaction object"));
get_transaction_id->add_option("transaction", trx_to_check, localized("The JSON string or filename defining the transaction which transaction id we want to retrieve"))->required();
get_transaction_id->set_callback([&] {
try {
fc::variant trx_var = json_from_file_or_string(trx_to_check);
if( trx_var.is_object() ) {
fc::variant_object& vo = trx_var.get_object();
// if actions.data & actions.hex_data provided, use the hex_data since only currently support unexploded data
if( vo.contains("actions") ) {
if( vo["actions"].is_array() ) {
fc::mutable_variant_object mvo = vo;
fc::variants& action_variants = mvo["actions"].get_array();
for( auto& action_v : action_variants ) {
if( !action_v.is_object() ) {
std::cerr << "Empty 'action' in transaction" << endl;
return;
}
fc::variant_object& action_vo = action_v.get_object();
if( action_vo.contains( "data" ) && action_vo.contains( "hex_data" ) ) {
fc::mutable_variant_object maction_vo = action_vo;
maction_vo["data"] = maction_vo["hex_data"];
action_vo = maction_vo;
vo = mvo;
} else if( action_vo.contains( "data" ) ) {
if( !action_vo["data"].is_string() ) {
std::cerr << "get transaction_id only supports un-exploded 'data' (hex form)" << std::endl;
return;
}
}
}
} else {
std::cerr << "transaction json 'actions' is not an array" << std::endl;
return;
}
} else {
std::cerr << "transaction json does not include 'actions'" << std::endl;
return;
}
auto trx = trx_var.as<transaction>();
transaction_id_type id = trx.id(); // 计算交易id
if( id == transaction().id() ) {
std::cerr << "file/string does not represent a transaction" << std::endl;
} else {
std::cout << string( id ) << std::endl;
}
} else {
std::cerr << "file/string does not represent a transaction" << std::endl;
}
} EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON '${data}'", ("data",trx_to_check))
});
}
};
transaction_id_type transaction::id() const {
digest_type::encoder enc;
fc::raw::pack( enc, *this );
return enc.result();
}
digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector<bytes>& cfd )const {
digest_type::encoder enc;
fc::raw::pack( enc, chain_id );
fc::raw::pack( enc, *this );
if( cfd.size() ) {
fc::raw::pack( enc, digest_type::hash(cfd) );
} else {
fc::raw::pack( enc, digest_type() );
}
return enc.result();
}
看实现代码,应该没问题
再看看关键词,每次都是返回374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
搜一下
https://github.com/EOSIO/eos/issues/6603
过期交易错误,会返回这种?
猜测是当前获取交易id的数据过期了,那使用新的交易体计算下。
待补充
等等,先去eosjs 那边看下,
反向到eosjs找下线索
const serializedTransaction = await api.transact({
....
}, {
blocksBehind: 3,
expireSeconds: 3600,
broadcast: false
});
console.log(Crypto.createHash("sha256").update(serializedTransaction).digest("hex"));
前端可使用 Crypto https://github.com/crypto-browserify/createHash
public static byte[] sha256(final byte[] b) {
Objects.requireNonNull(b);
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(b);
return messageDigest.digest();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
添加 contextFreeActions
https://github.com/EOSIO/eosio-java/blob/a9202879f31edb4122e768df0dc7fca391eff7e7/eosiojava/src/main/java/one/block/eosiojava/session/TransactionProcessor.java#L261
public void prepare(@NotNull List<Action> actions, @NotNull List<Action> contextFreeActions) throws TransactionPrepareError {
serializedTransaction 计算
https://github.com/EOSIO/eosio-java/blob/a9202879f31edb4122e768df0dc7fca391eff7e7/eosiojava/src/test/java/one/block/eosiojava/session/TransactionProcessorTest.java#L175
@Test
public void serialize() {
this.mockDefaultSuccessData();
TransactionProcessor processor = createAndPrepareTransaction(this.defaultActions());
assertNotNull(processor);
try {
String serializedTransaction = processor.serialize();
assertEquals(MOCKED_TRANSACTION_HEX, serializedTransaction);
} catch (TransactionSerializeError transactionSerializeError) {
transactionSerializeError.printStackTrace();
}
}
参考
https://github.com/EOSIO/eosjs/issues/460
https://github.com/EOSIO/eos/issues/5935
https://github.com/EOSIO/eos/issues/6830
https://eosio.stackexchange.com/questions/1941/transaction-id-is-a-hash-of-what
https://github.com/EOSIO/eos/issues/7816