mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-29 04:05:21 +08:00
Make filtering of signer transactions global and use in miner
Signed-off-by: Jacinta Ferrant <jacinta@trustmachines.co>
This commit is contained in:
@@ -49,7 +49,7 @@ use stacks::chainstate::nakamoto::{
|
||||
NakamotoBlock, NakamotoBlockHeader, NakamotoChainState, SetupBlockResult,
|
||||
};
|
||||
use stacks::chainstate::stacks::address::PoxAddress;
|
||||
use stacks::chainstate::stacks::boot::SIGNERS_VOTING_NAME;
|
||||
use stacks::chainstate::stacks::boot::{SIGNERS_VOTING_FUNCTION_NAME, SIGNERS_VOTING_NAME};
|
||||
use stacks::chainstate::stacks::db::{ChainStateBootData, ClarityTx, StacksChainState};
|
||||
use stacks::chainstate::stacks::miner::{
|
||||
BlockBuilder, BlockBuilderSettings, BlockLimitFunction, MinerStatus, TransactionResult,
|
||||
@@ -934,7 +934,7 @@ impl MockamotoNode {
|
||||
let vote_payload = TransactionPayload::new_contract_call(
|
||||
boot_code_addr(false),
|
||||
SIGNERS_VOTING_NAME,
|
||||
"vote-for-aggregate-public-key",
|
||||
SIGNERS_VOTING_FUNCTION_NAME,
|
||||
vec![
|
||||
ClarityValue::UInt(0),
|
||||
aggregate_public_key_val,
|
||||
|
||||
@@ -331,48 +331,43 @@ impl BlockMinerThread {
|
||||
})
|
||||
.collect();
|
||||
|
||||
// There may be more than signer messages, but odds are there is only one transacton per signer
|
||||
let mut transactions_to_include = Vec::with_capacity(signer_messages.len());
|
||||
if signer_messages.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
// Get all nonces for the signers from clarity DB to use to validate transactions
|
||||
let account_nonces = chainstate
|
||||
.with_read_only_clarity_tx(&sortdb.index_conn(), &self.parent_tenure_id, |clarity_tx| {
|
||||
clarity_tx.with_clarity_db_readonly(|clarity_db| {
|
||||
addresses
|
||||
.iter()
|
||||
.map(|address| {
|
||||
(
|
||||
address.clone(),
|
||||
clarity_db
|
||||
.get_account_nonce(&address.clone().into())
|
||||
.unwrap_or(0),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<StacksAddress, u64>>()
|
||||
})
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let mut filtered_transactions: HashMap<StacksAddress, StacksTransaction> = HashMap::new();
|
||||
for (_slot, signer_message) in signer_messages {
|
||||
match signer_message {
|
||||
SignerMessage::Transactions(transactions) => {
|
||||
for transaction in transactions {
|
||||
let address = transaction.origin_address();
|
||||
let nonce = transaction.get_origin_nonce();
|
||||
if !addresses.contains(&address) {
|
||||
test_debug!("Miner: ignoring transaction ({:?}) with nonce {nonce} from address {address}", transaction.txid());
|
||||
continue;
|
||||
}
|
||||
|
||||
let cur_nonce = chainstate
|
||||
.with_read_only_clarity_tx(
|
||||
&sortdb.index_conn(),
|
||||
&self.parent_tenure_id,
|
||||
|clarity_tx| {
|
||||
clarity_tx.with_clarity_db_readonly(|clarity_db| {
|
||||
clarity_db.get_account_nonce(&address.into()).unwrap_or(0)
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap_or(0);
|
||||
|
||||
if cur_nonce > nonce {
|
||||
test_debug!("Miner: ignoring transaction ({:?}) with nonce {nonce} from address {address}", transaction.txid());
|
||||
continue;
|
||||
}
|
||||
debug!("Miner: including signer transaction.";
|
||||
"nonce" => {nonce},
|
||||
"origin_address" => %address,
|
||||
"txid" => %transaction.txid()
|
||||
);
|
||||
// TODO : filter out transactions that are not valid votes. Do not include transactions with invalid/duplicate nonces for the same address.
|
||||
transactions_to_include.push(transaction);
|
||||
}
|
||||
NakamotoSigners::update_filtered_transactions(
|
||||
&mut filtered_transactions,
|
||||
&account_nonces,
|
||||
self.config.is_mainnet(),
|
||||
transactions,
|
||||
)
|
||||
}
|
||||
_ => {} // Any other message is ignored
|
||||
}
|
||||
}
|
||||
Ok(transactions_to_include)
|
||||
Ok(filtered_transactions.into_values().collect())
|
||||
}
|
||||
|
||||
fn wait_for_signer_signature(
|
||||
|
||||
@@ -30,7 +30,9 @@ use stacks::chainstate::nakamoto::miner::NakamotoBlockBuilder;
|
||||
use stacks::chainstate::nakamoto::test_signers::TestSigners;
|
||||
use stacks::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState};
|
||||
use stacks::chainstate::stacks::address::PoxAddress;
|
||||
use stacks::chainstate::stacks::boot::{MINERS_NAME, SIGNERS_VOTING_NAME};
|
||||
use stacks::chainstate::stacks::boot::{
|
||||
MINERS_NAME, SIGNERS_VOTING_FUNCTION_NAME, SIGNERS_VOTING_NAME,
|
||||
};
|
||||
use stacks::chainstate::stacks::db::StacksChainState;
|
||||
use stacks::chainstate::stacks::miner::{BlockBuilder, BlockLimitFunction, TransactionResult};
|
||||
use stacks::chainstate::stacks::{StacksTransaction, ThresholdSignature, TransactionPayload};
|
||||
@@ -455,7 +457,7 @@ pub fn boot_to_epoch_3(
|
||||
300,
|
||||
&StacksAddress::burn_address(false),
|
||||
SIGNERS_VOTING_NAME,
|
||||
"vote-for-aggregate-public-key",
|
||||
SIGNERS_VOTING_FUNCTION_NAME,
|
||||
&[
|
||||
clarity::vm::Value::UInt(i as u128),
|
||||
aggregate_public_key.clone(),
|
||||
@@ -564,7 +566,7 @@ fn signer_vote_if_needed(
|
||||
300,
|
||||
&StacksAddress::burn_address(false),
|
||||
SIGNERS_VOTING_NAME,
|
||||
"vote-for-aggregate-public-key",
|
||||
SIGNERS_VOTING_FUNCTION_NAME,
|
||||
&[
|
||||
clarity::vm::Value::UInt(i as u128),
|
||||
aggregate_public_key.clone(),
|
||||
|
||||
@@ -7,23 +7,35 @@ use std::time::{Duration, Instant};
|
||||
use std::{env, thread};
|
||||
|
||||
use clarity::boot_util::boot_code_id;
|
||||
use clarity::vm::Value;
|
||||
use libsigner::{
|
||||
BlockResponse, RejectCode, RunningSigner, Signer, SignerEventReceiver, SignerMessage,
|
||||
BLOCK_MSG_ID,
|
||||
};
|
||||
use rand::thread_rng;
|
||||
use rand_core::RngCore;
|
||||
use stacks::burnchains::Txid;
|
||||
use stacks::chainstate::coordinator::comm::CoordinatorChannels;
|
||||
use stacks::chainstate::nakamoto::signer_set::NakamotoSigners;
|
||||
use stacks::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader, NakamotoBlockVote};
|
||||
use stacks::chainstate::stacks::boot::SIGNERS_NAME;
|
||||
use stacks::chainstate::stacks::boot::{
|
||||
SIGNERS_NAME, SIGNERS_VOTING_FUNCTION_NAME, SIGNERS_VOTING_NAME,
|
||||
};
|
||||
use stacks::chainstate::stacks::miner::TransactionEvent;
|
||||
use stacks::chainstate::stacks::{StacksPrivateKey, StacksTransaction, ThresholdSignature};
|
||||
use stacks::chainstate::stacks::{
|
||||
StacksPrivateKey, StacksTransaction, ThresholdSignature, TransactionAnchorMode,
|
||||
TransactionAuth, TransactionPayload, TransactionPostConditionMode, TransactionSmartContract,
|
||||
TransactionVersion,
|
||||
};
|
||||
use stacks::core::StacksEpoch;
|
||||
use stacks::net::api::postblock_proposal::BlockValidateResponse;
|
||||
use stacks::util_lib::strings::StacksString;
|
||||
use stacks_common::bitvec::BitVec;
|
||||
use stacks_common::codec::{read_next, StacksMessageCodec};
|
||||
use stacks_common::consts::SIGNER_SLOTS_PER_USER;
|
||||
use stacks_common::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash};
|
||||
use stacks_common::consts::{CHAIN_ID_TESTNET, SIGNER_SLOTS_PER_USER};
|
||||
use stacks_common::types::chainstate::{
|
||||
ConsensusHash, StacksAddress, StacksBlockId, StacksPublicKey, TrieHash,
|
||||
};
|
||||
use stacks_common::types::StacksEpochId;
|
||||
use stacks_common::util::hash::{MerkleTree, Sha512Trunc256Sum};
|
||||
use stacks_common::util::secp256k1::MessageSignature;
|
||||
@@ -545,38 +557,190 @@ impl SignerTest {
|
||||
.unwrap();
|
||||
// Get the signer indices
|
||||
let reward_cycle = self.get_current_reward_cycle();
|
||||
let valid_signer_index = self.get_signer_index(reward_cycle);
|
||||
let round = self
|
||||
.stacks_client
|
||||
.get_last_round(reward_cycle)
|
||||
.expect("FATAL: failed to get round")
|
||||
.unwrap_or(0)
|
||||
.saturating_add(1);
|
||||
let point = Point::from(Scalar::random(&mut rand::thread_rng()));
|
||||
let invalid_nonce_tx = self
|
||||
.stacks_client
|
||||
.build_vote_for_aggregate_public_key(
|
||||
valid_signer_index,
|
||||
round,
|
||||
point,
|
||||
reward_cycle,
|
||||
|
||||
let signer_private_key = self.signer_stacks_private_keys[0];
|
||||
|
||||
let vote_contract_id = boot_code_id(SIGNERS_VOTING_NAME, false);
|
||||
let contract_addr = vote_contract_id.issuer.into();
|
||||
let contract_name = vote_contract_id.name.clone();
|
||||
|
||||
let signer_index = thread_rng().next_u64();
|
||||
let signer_index_arg = Value::UInt(signer_index as u128);
|
||||
|
||||
let point = Point::from(Scalar::random(&mut thread_rng()));
|
||||
let point_arg =
|
||||
Value::buff_from(point.compress().data.to_vec()).expect("Failed to create buff");
|
||||
|
||||
let round = thread_rng().next_u64();
|
||||
let round_arg = Value::UInt(round as u128);
|
||||
|
||||
let reward_cycle_arg = Value::UInt(reward_cycle as u128);
|
||||
let valid_function_args = vec![
|
||||
signer_index_arg.clone(),
|
||||
point_arg.clone(),
|
||||
round_arg.clone(),
|
||||
reward_cycle_arg.clone(),
|
||||
];
|
||||
|
||||
// Create a invalid transaction that is not a contract call
|
||||
let invalid_not_contract_call = StacksTransaction {
|
||||
version: TransactionVersion::Testnet,
|
||||
chain_id: CHAIN_ID_TESTNET,
|
||||
auth: TransactionAuth::from_p2pkh(&signer_private_key).unwrap(),
|
||||
anchor_mode: TransactionAnchorMode::Any,
|
||||
post_condition_mode: TransactionPostConditionMode::Allow,
|
||||
post_conditions: vec![],
|
||||
payload: TransactionPayload::SmartContract(
|
||||
TransactionSmartContract {
|
||||
name: "test-contract".into(),
|
||||
code_body: StacksString::from_str("(/ 1 0)").unwrap(),
|
||||
},
|
||||
None,
|
||||
0, // Old nonce
|
||||
),
|
||||
};
|
||||
let invalid_contract_address = StacksClient::build_signed_contract_call_transaction(
|
||||
&StacksAddress::p2pkh(false, &StacksPublicKey::from_private(&signer_private_key)),
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&valid_function_args,
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_contract_name = StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
"bad-signers-contract-name".into(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&valid_function_args,
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_signers_vote_function = StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
"some-other-function".into(),
|
||||
&valid_function_args,
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_function_arg_signer_index =
|
||||
StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&[
|
||||
point_arg.clone(),
|
||||
point_arg.clone(),
|
||||
round_arg.clone(),
|
||||
reward_cycle_arg.clone(),
|
||||
],
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.expect("FATAL: failed to build vote for aggregate public key");
|
||||
.unwrap();
|
||||
|
||||
let invalid_function_arg_key = StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&[
|
||||
signer_index_arg.clone(),
|
||||
signer_index_arg.clone(),
|
||||
round_arg.clone(),
|
||||
reward_cycle_arg.clone(),
|
||||
],
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_function_arg_round = StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&[
|
||||
signer_index_arg.clone(),
|
||||
point_arg.clone(),
|
||||
point_arg.clone(),
|
||||
reward_cycle_arg.clone(),
|
||||
],
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_function_arg_reward_cycle =
|
||||
StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&[
|
||||
signer_index_arg.clone(),
|
||||
point_arg.clone(),
|
||||
round_arg.clone(),
|
||||
point_arg.clone(),
|
||||
],
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
1,
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_nonce = StacksClient::build_signed_contract_call_transaction(
|
||||
&contract_addr,
|
||||
contract_name.clone(),
|
||||
SIGNERS_VOTING_FUNCTION_NAME.into(),
|
||||
&valid_function_args,
|
||||
&signer_private_key,
|
||||
TransactionVersion::Testnet,
|
||||
CHAIN_ID_TESTNET,
|
||||
0, // Old nonce
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invalid_stacks_client = StacksClient::new(StacksPrivateKey::new(), host, false);
|
||||
let invalid_signer_tx = invalid_stacks_client
|
||||
.build_vote_for_aggregate_public_key(
|
||||
valid_signer_index,
|
||||
round,
|
||||
point,
|
||||
reward_cycle,
|
||||
None,
|
||||
0,
|
||||
)
|
||||
.build_vote_for_aggregate_public_key(0, round, point, reward_cycle, None, 0)
|
||||
.expect("FATAL: failed to build vote for aggregate public key");
|
||||
// TODO: add invalid contract calls (one with non 'vote-for-aggregate-public-key' function call and one with invalid function args)
|
||||
vec![invalid_nonce_tx, invalid_signer_tx]
|
||||
|
||||
vec![
|
||||
invalid_nonce,
|
||||
invalid_not_contract_call,
|
||||
invalid_contract_name,
|
||||
invalid_contract_address,
|
||||
invalid_signers_vote_function,
|
||||
invalid_function_arg_key,
|
||||
invalid_function_arg_reward_cycle,
|
||||
invalid_function_arg_round,
|
||||
invalid_function_arg_signer_index,
|
||||
invalid_signer_tx,
|
||||
]
|
||||
}
|
||||
|
||||
fn shutdown(self) {
|
||||
|
||||
Reference in New Issue
Block a user