Skip to content

Commit

Permalink
EVM: Add optional nonce parameter for transfer domain RPC (#2451)
Browse files Browse the repository at this point in the history
* Move RBF from mempool to miner

* Reformat Python

* lint: remove unused variable

* Fix feature_evm_miner test

* Add nonce option for transferdomain rpc

* Fix feature_dst20 test

---------

Co-authored-by: Bushstar <[email protected]>
  • Loading branch information
sieniven and Bushstar authored Sep 15, 2023
1 parent a3145b1 commit f030bd5
Show file tree
Hide file tree
Showing 23 changed files with 271 additions and 468 deletions.
9 changes: 3 additions & 6 deletions lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ impl EVMCoreService {
tx: &str,
queue_id: u64,
pre_validate: bool,
test_tx: bool,
) -> Result<ValidateTxInfo> {
debug!("[validate_raw_tx] queue_id {}", queue_id);
debug!("[validate_raw_tx] raw transaction : {:#?}", tx);
Expand Down Expand Up @@ -333,11 +332,9 @@ impl EVMCoreService {
.get_total_gas_used_in(queue_id)
.unwrap_or_default();

if !test_tx {
let block_gas_limit = self.storage.get_attributes_or_default()?.block_gas_limit;
if total_current_gas_used + U256::from(used_gas) > U256::from(block_gas_limit) {
return Err(format_err!("Tx can't make it in block. Block size limit {}, pending block gas used : {:x?}, tx used gas : {:x?}, total : {:x?}", block_gas_limit, total_current_gas_used, U256::from(used_gas), total_current_gas_used + U256::from(used_gas)).into());
}
let block_gas_limit = self.storage.get_attributes_or_default()?.block_gas_limit;
if total_current_gas_used + U256::from(used_gas) > U256::from(block_gas_limit) {
return Err(format_err!("Tx can't make it in block. Block size limit {}, pending block gas used : {:x?}, tx used gas : {:x?}, total : {:x?}", block_gas_limit, total_current_gas_used, U256::from(used_gas), total_current_gas_used + U256::from(used_gas)).into());
}

Ok(ValidateTxInfo {
Expand Down
18 changes: 11 additions & 7 deletions lib/ain-rs-exports/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,16 @@ pub fn evm_try_create_and_sign_transfer_domain_tx(
}
}
};
let Ok(nonce) = SERVICES.evm.get_nonce(from_address, state_root) else {
return cross_boundary_error_return(
result,
format!("Could not get nonce for {from_address:x?}"),
);
let nonce = if ctx.use_nonce {
U256::from(ctx.nonce)
} else {
let Ok(nonce) = SERVICES.evm.get_nonce(from_address, state_root) else {
return cross_boundary_error_return(
result,
format!("Could not get nonce for {from_address:x?}"),
);
};
nonce
};

let t = LegacyUnsignedTransaction {
Expand Down Expand Up @@ -498,7 +503,6 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q(
queue_id: u64,
raw_tx: &str,
pre_validate: bool,
test_tx: bool,
) -> ffi::ValidateTxMiner {
debug!("[evm_unsafe_try_validate_raw_tx_in_q]");
match SERVICES.evm.verify_tx_fees(raw_tx) {
Expand All @@ -512,7 +516,7 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q(
match SERVICES
.evm
.core
.validate_raw_tx(raw_tx, queue_id, pre_validate, test_tx)
.validate_raw_tx(raw_tx, queue_id, pre_validate)
{
Ok(ValidateTxInfo {
signed_tx,
Expand Down
7 changes: 4 additions & 3 deletions lib/ain-rs-exports/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ pub mod ffi {

#[derive(Default)]
pub struct TxSenderInfo {
address: String,
nonce: u64,
pub address: String,
pub nonce: u64,
}

// ========== Governance Variable ==========
Expand Down Expand Up @@ -99,6 +99,8 @@ pub mod ffi {
pub chain_id: u64,
pub priv_key: [u8; 32],
pub queue_id: u64,
pub use_nonce: bool,
pub nonce: u64,
}

#[derive(Default)]
Expand Down Expand Up @@ -169,7 +171,6 @@ pub mod ffi {
queue_id: u64,
raw_tx: &str,
pre_validate: bool,
test_tx: bool,
) -> ValidateTxMiner;
fn evm_unsafe_try_push_tx_in_q(
result: &mut CrossBoundaryResult,
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
// Note: TXs are already filtered. So we pass isEVMEnabled to false, but for future proof, refactor this enough,
// that it's propagated.
uint64_t gasUsed{};
auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight, gasUsed, 0, &canSpend, 0, 0, false);
auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight, gasUsed, 0, &canSpend, 0, 0, false, false);
if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg);
}
Expand Down
6 changes: 2 additions & 4 deletions src/masternodes/consensus/txvisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ CCustomTxVisitor::CCustomTxVisitor(const CTransaction &tx,
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock,
uint64_t &gasUsed,
const bool evmPreValidate,
const bool testTx)
const bool evmPreValidate)
: height(height),
mnview(mnview),
tx(tx),
Expand All @@ -75,8 +74,7 @@ CCustomTxVisitor::CCustomTxVisitor(const CTransaction &tx,
evmQueueId(evmQueueId),
isEvmEnabledForBlock(isEvmEnabledForBlock),
gasUsed(gasUsed),
evmPreValidate(evmPreValidate),
testTx(testTx) {}
evmPreValidate(evmPreValidate) {}

Res CCustomTxVisitor::HasAuth(const CScript &auth) const {
return ::HasAuth(tx, coins, auth);
Expand Down
4 changes: 1 addition & 3 deletions src/masternodes/consensus/txvisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class CCustomTxVisitor {
bool isEvmEnabledForBlock;
uint64_t &gasUsed;
bool evmPreValidate;
bool testTx;

public:
CCustomTxVisitor(const CTransaction &tx,
Expand All @@ -67,8 +66,7 @@ class CCustomTxVisitor {
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock,
uint64_t &gasUsed,
const bool evmPreValidate,
const bool testTx);
const bool evmPreValidate);

protected:
Res HasAuth(const CScript &auth) const;
Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/consensus/xvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ Res CXVMConsensus::operator()(const CEvmTxMessage &obj) const {
return Res::Err("evm tx size too large");

CrossBoundaryResult result;
auto validateResults = evm_unsafe_try_validate_raw_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), evmPreValidate, testTx);
auto validateResults = evm_unsafe_try_validate_raw_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), evmPreValidate);
if (!result.ok) {
LogPrintf("[evm_try_validate_raw_tx] failed, reason : %s\n", result.reason);
return Res::Err("evm tx failed to validate %s", result.reason);
Expand Down
19 changes: 8 additions & 11 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,15 +333,14 @@ class CCustomTxApplyVisitor {
bool isEvmEnabledForBlock;
uint64_t &gasUsed;
bool evmPreValidate;
bool testTx;

template<typename T, typename T1, typename ...Args>
Res ConsensusHandler(const T& obj) const {

static_assert(std::is_base_of_v<CCustomTxVisitor, T1>, "CCustomTxVisitor base required");

if constexpr (std::is_invocable_v<T1, T>)
return T1{tx, height, coins, mnview, consensus, time, txn, evmQueueId, isEvmEnabledForBlock, gasUsed, evmPreValidate, testTx}(obj);
return T1{tx, height, coins, mnview, consensus, time, txn, evmQueueId, isEvmEnabledForBlock, gasUsed, evmPreValidate}(obj);
else if constexpr (sizeof...(Args) != 0)
return ConsensusHandler<T, Args...>(obj);
else
Expand All @@ -361,8 +360,7 @@ class CCustomTxApplyVisitor {
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock,
uint64_t &gasUsed,
const bool evmPreValidate,
const bool testTx)
const bool evmPreValidate)

: tx(tx),
height(height),
Expand All @@ -374,8 +372,7 @@ class CCustomTxApplyVisitor {
evmQueueId(evmQueueId),
isEvmEnabledForBlock(isEvmEnabledForBlock),
gasUsed(gasUsed),
evmPreValidate(evmPreValidate),
testTx(testTx) {}
evmPreValidate(evmPreValidate) {}

template<typename T>
Res operator()(const T& obj) const {
Expand Down Expand Up @@ -454,8 +451,7 @@ Res CustomTxVisit(CCustomCSView &mnview,
const uint32_t txn,
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock,
const bool evmPreValidate,
const bool testTx) {
const bool evmPreValidate) {
if (IsDisabledTx(height, tx, consensus)) {
return Res::ErrCode(CustomTxErrCodes::Fatal, "Disabled custom transaction");
}
Expand All @@ -470,7 +466,7 @@ Res CustomTxVisit(CCustomCSView &mnview,

try {
auto res = std::visit(
CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, q, isEvmEnabledForBlock, gasUsed, evmPreValidate, testTx),
CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, q, isEvmEnabledForBlock, gasUsed, evmPreValidate),
txMessage);
if (wipeQueue) {
XResultStatusLogged(evm_unsafe_try_remove_queue(result, q));
Expand Down Expand Up @@ -569,7 +565,8 @@ Res ApplyCustomTx(CCustomCSView &mnview,
uint256 *canSpend,
uint32_t txn,
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock) {
const bool isEvmEnabledForBlock,
const bool evmPreValidate) {
auto res = Res::Ok();
if (tx.IsCoinBase() && height > 0) { // genesis contains custom coinbase txs
return res;
Expand Down Expand Up @@ -608,7 +605,7 @@ Res ApplyCustomTx(CCustomCSView &mnview,
PopulateVaultHistoryData(mnview.GetHistoryWriters(), view, txMessage, txType, height, txn, tx.GetHash());
}

res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, gasUsed, txn, evmQueueId, isEvmEnabledForBlock, false, false);
res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, gasUsed, txn, evmQueueId, isEvmEnabledForBlock, evmPreValidate);

if (res) {
if (canSpend && txType == CustomTxType::UpdateMasternode) {
Expand Down
6 changes: 3 additions & 3 deletions src/masternodes/mn_checks.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ Res ApplyCustomTx(CCustomCSView &mnview,
uint256 *canSpend,
uint32_t txn,
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock);
const bool isEvmEnabledForBlock,
const bool evmPreValidate);

Res CustomTxVisit(CCustomCSView &mnview,
const CCoinsViewCache &coins,
Expand All @@ -188,8 +189,7 @@ Res CustomTxVisit(CCustomCSView &mnview,
const uint32_t txn,
const uint64_t evmQueueId,
const bool isEvmEnabledForBlock,
const bool evmPreValidate,
const bool testTx);
const bool evmPreValidate);


ResVal<uint256> ApplyAnchorRewardTx(CCustomCSView &mnview,
Expand Down
3 changes: 1 addition & 2 deletions src/masternodes/mn_rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ void execTestTx(const CTransaction& tx, uint32_t height, CTransactionRef optAuth
auto consensus = Params().GetConsensus();
auto isEvmEnabledForBlock = IsEVMEnabled(height, view, consensus);
uint64_t gasUsed{};
res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, ::ChainActive().Tip()->nTime, gasUsed, 0, 0, isEvmEnabledForBlock, true, true);
res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, ::ChainActive().Tip()->nTime, gasUsed, 0, 0, isEvmEnabledForBlock, true);
}
if (!res) {
if (res.code == CustomTxErrCodes::NotEnoughBalance) {
Expand Down Expand Up @@ -1132,7 +1132,6 @@ static UniValue clearmempool(const JSONRPCRequest& request)
LOCK(mempool.cs);
mempool.queryHashes(vtxid);
mempool.clear();
mempool.wipeEvmQueueId();
}

{
Expand Down
25 changes: 21 additions & 4 deletions src/masternodes/rpc_accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,8 @@ UniValue transferdomain(const JSONRPCRequest& request) {
{"domain", RPCArg::Type::NUM, RPCArg::Optional::NO, "Domain of source: 2 - DVM, 3 - EVM"},
// {"data", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Optional data"},
},
}
},
{"nonce", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Optional parameter to specify the transaction nonce"},
},
},
},
Expand Down Expand Up @@ -2050,10 +2051,11 @@ UniValue transferdomain(const JSONRPCRequest& request) {
try {
for (unsigned int i=0; i < srcDstArray.size(); i++) {
const UniValue& elem = srcDstArray[i];
RPCTypeCheck(elem, {UniValue::VOBJ, UniValue::VOBJ}, false);
RPCTypeCheck(elem, {UniValue::VOBJ, UniValue::VOBJ, UniValue::VNUM}, false);

const UniValue& srcObj = elem["src"].get_obj();
const UniValue& dstObj = elem["dst"].get_obj();
const UniValue& nonceObj = elem["nonce"];

CTransferDomainItem src, dst;

Expand Down Expand Up @@ -2136,7 +2138,15 @@ UniValue transferdomain(const JSONRPCRequest& request) {
std::string from = ScriptToString(script);

CrossBoundaryResult result;
auto evmQueueId = mempool.getEvmQueueId();
auto evmQueueId = evm_unsafe_try_create_queue(result);
if (!result.ok) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to create EVM queue");
}
uint64_t nonce = 0;
bool useNonce = !nonceObj.isNull();
if (useNonce) {
nonce = nonceObj.get_int64();
}
const auto signedTx = evm_try_create_and_sign_transfer_domain_tx(result, CreateTransferDomainContext{std::move(from),
std::move(to),
nativeAddress,
Expand All @@ -2145,12 +2155,19 @@ UniValue transferdomain(const JSONRPCRequest& request) {
dst.amount.nTokenId.v,
Params().GetConsensus().evmChainId,
privKey,
evmQueueId
evmQueueId,
useNonce,
nonce
});
if (!result.ok) {
throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to create and sign TX: %s", result.reason.c_str()));
}

evm_unsafe_try_remove_queue(result, evmQueueId);
if (!result.ok) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to destroy EVM queue");
}

std::vector<uint8_t> evmTx(signedTx.size());
std::copy(signedTx.begin(), signedTx.end(), evmTx.begin());
if (isEVMIn) {
Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/rpc_tokens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ UniValue getcustomtx(const JSONRPCRequest& request)
auto isEvmEnabledForBlock = IsEVMEnabled(nHeight, mnview, consensus);

uint64_t gasUsed{};
auto res = ApplyCustomTx(mnview, view, *tx, consensus, nHeight, gasUsed, 0, nullptr, 0, 0, isEvmEnabledForBlock);
auto res = ApplyCustomTx(mnview, view, *tx, consensus, nHeight, gasUsed, 0, nullptr, 0, 0, isEvmEnabledForBlock, false);

result.pushKV("valid", res.ok);
} else {
Expand Down
Loading

0 comments on commit f030bd5

Please sign in to comment.