Skip to content

Commit ed0a507

Browse files
Merge pull request #168 from casper-network/release-2.0.4-patch
[BUG] Insufficient Funds for Fee (PaymentImputed + Refund + PayToProposer)
2 parents a134a41 + d8b6f07 commit ed0a507

13 files changed

Lines changed: 769 additions & 252 deletions

File tree

node/src/components/contract_runtime/operations.rs

Lines changed: 88 additions & 56 deletions
Large diffs are not rendered by default.

node/src/components/contract_runtime/types.rs

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,13 @@ pub(crate) struct ExecutionArtifactBuilder {
8585
}
8686

8787
impl ExecutionArtifactBuilder {
88-
pub fn new(transaction: &Transaction, min_cost: U512, current_price: u8) -> Self {
88+
pub fn new(
89+
transaction: &Transaction,
90+
limit: Gas,
91+
current_price: u8,
92+
initial_cost: U512,
93+
min_cost: U512,
94+
) -> Self {
8995
ExecutionArtifactBuilder {
9096
effects: Effects::new(),
9197
hash: transaction.hash(),
@@ -95,19 +101,50 @@ impl ExecutionArtifactBuilder {
95101
messages: Default::default(),
96102
initiator: transaction.initiator_addr(),
97103
current_price,
104+
cost: initial_cost,
105+
limit,
106+
consumed: Gas::zero(),
107+
refund: U512::zero(),
108+
size_estimate: transaction.size_estimate() as u64,
109+
min_cost,
110+
}
111+
}
112+
113+
pub fn pre_condition_failure(
114+
transaction: &Transaction,
115+
current_price: u8,
116+
invalid_transaction: InvalidTransaction,
117+
) -> Self {
118+
ExecutionArtifactBuilder {
119+
effects: Effects::new(),
120+
hash: transaction.hash(),
121+
header: transaction.into(),
122+
error_message: Some(format!("{}", invalid_transaction)),
123+
transfers: vec![],
124+
messages: Default::default(),
125+
initiator: transaction.initiator_addr(),
126+
current_price,
98127
cost: U512::zero(),
99128
limit: Gas::zero(),
100129
consumed: Gas::zero(),
101130
refund: U512::zero(),
102131
size_estimate: transaction.size_estimate() as u64,
103-
min_cost,
132+
min_cost: U512::zero(),
104133
}
105134
}
106135

107136
pub fn error_message(&self) -> Option<String> {
108137
self.error_message.clone()
109138
}
110139

140+
pub fn gas_limit(&self) -> Gas {
141+
self.limit
142+
}
143+
144+
pub fn limit(&self) -> U512 {
145+
self.limit.value()
146+
}
147+
111148
pub fn consumed(&self) -> U512 {
112149
self.consumed.value()
113150
}
@@ -123,6 +160,11 @@ impl ExecutionArtifactBuilder {
123160
}
124161
}
125162

163+
pub fn consume_limit(&mut self) -> &mut Self {
164+
self.consumed = self.consumed.saturating_add(self.limit);
165+
self
166+
}
167+
126168
pub fn with_added_consumed(&mut self, consumed: Gas) -> &mut Self {
127169
self.consumed = self.consumed.saturating_add(consumed);
128170
self
@@ -279,11 +321,17 @@ impl ExecutionArtifactBuilder {
279321
if let HandleFeeResult::RootNotFound = handle_fee_result {
280322
return Err(());
281323
}
282-
if let (None, HandleFeeResult::Failure(err)) = (&self.error_message, handle_fee_result) {
283-
self.error_message = Some(format!("{}", err));
324+
if let HandleFeeResult::Success {
325+
effects, transfers, ..
326+
} = handle_fee_result
327+
{
328+
self.with_appended_transfers(&mut transfers.clone())
329+
.with_appended_effects(effects.clone());
330+
}
331+
if let (None, HandleFeeResult::Failure(_)) = (&self.error_message, handle_fee_result) {
332+
self.error_message = handle_fee_result.error_message();
284333
return Ok(self);
285334
}
286-
self.with_appended_effects(handle_fee_result.effects());
287335
Ok(self)
288336
}
289337

@@ -294,26 +342,18 @@ impl ExecutionArtifactBuilder {
294342
if let BalanceHoldResult::RootNotFound = hold_result {
295343
return Err(());
296344
}
297-
if let (None, BalanceHoldResult::Failure(err)) = (&self.error_message, hold_result) {
298-
self.error_message = Some(format!("{}", err));
345+
if let BalanceHoldResult::Success { effects, .. } = hold_result {
346+
self.with_appended_effects(*effects.clone());
347+
}
348+
if let (None, BalanceHoldResult::Failure(_)) = (&self.error_message, hold_result) {
349+
self.error_message = hold_result.error_message();
299350
return Ok(self);
300351
}
301-
self.with_appended_effects(hold_result.effects());
302352
Ok(self)
303353
}
304354

305-
pub fn with_added_cost(&mut self, cost: U512) -> &mut Self {
306-
self.cost = self.cost.saturating_add(cost);
307-
self
308-
}
309-
310-
pub fn with_min_cost(&mut self, min_cost: U512) -> &mut Self {
311-
self.min_cost = min_cost;
312-
self
313-
}
314-
315-
pub fn with_gas_limit(&mut self, limit: Gas) -> &mut Self {
316-
self.limit = limit;
355+
pub fn with_cost(&mut self, new_cost: U512) -> &mut Self {
356+
self.cost = new_cost;
317357
self
318358
}
319359

@@ -322,16 +362,6 @@ impl ExecutionArtifactBuilder {
322362
self
323363
}
324364

325-
pub fn with_invalid_transaction(
326-
&mut self,
327-
invalid_transaction: &InvalidTransaction,
328-
) -> &mut Self {
329-
if self.error_message.is_none() {
330-
self.error_message = Some(format!("{}", invalid_transaction));
331-
}
332-
self
333-
}
334-
335365
pub fn with_invalid_wasm_v1_request(
336366
&mut self,
337367
invalid_request: &InvalidWasmV1Request,

node/src/reactor/main_reactor/tests/consensus_rules.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,18 @@ async fn run_equivocator_network() {
3434
let charlie_public_key = PublicKey::from(&*charlie_secret_key);
3535

3636
let mut stakes = BTreeMap::new();
37-
stakes.insert(alice_public_key.clone(), U512::from(1));
38-
stakes.insert(bob_public_key.clone(), U512::from(1));
39-
stakes.insert(charlie_public_key, U512::from(u64::MAX));
37+
stakes.insert(
38+
alice_public_key.clone(),
39+
(U512::from(u64::MAX), U512::from(1)),
40+
);
41+
stakes.insert(
42+
bob_public_key.clone(),
43+
(U512::from(u64::MAX), U512::from(1)),
44+
);
45+
stakes.insert(
46+
charlie_public_key,
47+
(U512::from(u64::MAX), U512::from(u64::MAX)),
48+
);
4049

4150
// Here's where things go wrong: Bob doesn't run a node at all, and Alice runs two!
4251
let secret_keys = vec![
@@ -205,12 +214,12 @@ async fn run_equivocator_network() {
205214
.expect("should have bid for public key {public_key} in era {era}");
206215
let staked_amount = bid.staked_amount();
207216
assert!(
208-
staked_amount >= *stake,
217+
staked_amount >= stake.1,
209218
"expected stake {} for public key {} in era {}, found {}",
210219
staked_amount,
211220
public_key,
212221
era,
213-
stake
222+
stake.1
214223
);
215224
}
216225
}

node/src/reactor/main_reactor/tests/fixture.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,21 @@ impl TestFixture {
100100
let stakes = secret_keys
101101
.iter()
102102
.zip(stake_values)
103-
.map(|(secret_key, stake)| (PublicKey::from(secret_key.as_ref()), stake))
103+
.map(|(secret_key, stake)| {
104+
(
105+
PublicKey::from(secret_key.as_ref()),
106+
(U512::from(100_000_000_000_000_000u64), stake),
107+
)
108+
})
104109
.collect();
110+
105111
Self::new_with_keys(rng, secret_keys, stakes, spec_override).await
106112
}
107113

108114
pub(crate) async fn new_with_keys(
109-
mut rng: TestRng,
115+
rng: TestRng,
110116
secret_keys: Vec<Arc<SecretKey>>,
111-
stakes: BTreeMap<PublicKey, U512>,
117+
stakes: BTreeMap<PublicKey, (U512, U512)>,
112118
spec_override: Option<ConfigsOverride>,
113119
) -> Self {
114120
testing::init_logging();
@@ -117,14 +123,10 @@ impl TestFixture {
117123
let (mut chainspec, chainspec_raw_bytes) =
118124
<(Chainspec, ChainspecRawBytes)>::from_resources("local");
119125

120-
let min_motes = 100_000_000_000_000_000u64;
121-
let max_motes = min_motes * 100;
122-
let balance = U512::from(rng.gen_range(min_motes..max_motes));
123-
124126
// Override accounts with those generated from the keys.
125127
let accounts = stakes
126128
.into_iter()
127-
.map(|(public_key, bonded_amount)| {
129+
.map(|(public_key, (balance, bonded_amount))| {
128130
let validator_config =
129131
ValidatorConfig::new(Motes::new(bonded_amount), DelegationRate::zero());
130132
AccountConfig::new(public_key, Motes::new(balance), Some(validator_config))
@@ -952,3 +954,27 @@ impl TestFixture {
952954
})
953955
}
954956
}
957+
958+
pub(crate) fn standard_stakes(
959+
alice_public_key: PublicKey,
960+
bob_public_key: PublicKey,
961+
charlie_public_key: Option<PublicKey>,
962+
) -> BTreeMap<PublicKey, (U512, U512)> {
963+
let mut ret = BTreeMap::new();
964+
ret.insert(
965+
alice_public_key.clone(),
966+
(
967+
U512::from(100_000_000_000_000_000u64),
968+
U512::from(u128::MAX),
969+
),
970+
);
971+
ret.insert(
972+
bob_public_key.clone(),
973+
(U512::from(100_000_000_000_000_000u64), U512::from(1)),
974+
);
975+
976+
if let Some(pub_k) = charlie_public_key {
977+
ret.insert(pub_k, (U512::from(u32::MAX - 1), U512::from(1)));
978+
}
979+
ret
980+
}

node/src/reactor/main_reactor/tests/gas_price.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ async fn run_gas_price_scenario(gas_price_scenario: GasPriceScenario) {
2424
let alice_stake = 200_000_000_000_u64;
2525
let bob_stake = 300_000_000_000_u64;
2626
let charlie_stake = 300_000_000_000_u64;
27-
let initial_stakes: Vec<U512> =
28-
vec![alice_stake.into(), bob_stake.into(), charlie_stake.into()];
27+
let initial_stakes: Vec<(U512, U512)> = vec![
28+
(U512::from(u64::MAX), alice_stake.into()),
29+
(U512::from(u64::MAX), bob_stake.into()),
30+
(U512::from(u64::MAX), charlie_stake.into()),
31+
];
2932

3033
let mut secret_keys: Vec<Arc<SecretKey>> = (0..3)
3134
.map(|_| Arc::new(SecretKey::random(&mut rng)))
@@ -34,7 +37,7 @@ async fn run_gas_price_scenario(gas_price_scenario: GasPriceScenario) {
3437
let stakes = secret_keys
3538
.iter()
3639
.zip(initial_stakes)
37-
.map(|(secret_key, stake)| (PublicKey::from(secret_key.as_ref()), stake))
40+
.map(|(secret_key, (bal, stake))| (PublicKey::from(secret_key.as_ref()), (bal, stake)))
3841
.collect();
3942

4043
let non_validating_secret_key = SecretKey::random(&mut rng);

node/src/reactor/main_reactor/tests/transaction_scenario.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use utils::{build_wasm_transction, RunUntilCondition, TestScenarioBuilder};
1313

1414
use crate::{
1515
reactor::main_reactor::tests::{
16+
transaction_scenario::asertions::BalanceChange,
1617
transactions::{
1718
invalid_wasm_txn, ALICE_PUBLIC_KEY, ALICE_SECRET_KEY, BOB_PUBLIC_KEY, BOB_SECRET_KEY,
1819
CHARLIE_PUBLIC_KEY, MIN_GAS_PRICE,
@@ -98,19 +99,25 @@ async fn should_native_transfer_nofee_norefund_fixed() {
9899
Gas::new(expected_transfer_gas),
99100
))
100101
.await;
102+
103+
let transfer_amount = U512::from(TRANSFER_AMOUNT);
104+
let transfer_amount_and_gas: U512 = transfer_amount
105+
.checked_add(expected_transfer_gas)
106+
.expect("should math");
107+
101108
test_scenario
102109
.assert(PublicKeyBalanceChange::new(
103110
ALICE_PUBLIC_KEY.clone(),
104-
-(TRANSFER_AMOUNT as i64),
105-
-((TRANSFER_AMOUNT + expected_transfer_gas.as_u64()) as i64),
111+
BalanceChange::Down(transfer_amount),
112+
BalanceChange::Down(transfer_amount_and_gas),
106113
))
107114
.await;
108115
//Charlie should have the transfer amount at his disposal
109116
test_scenario
110117
.assert(PublicKeyBalanceChange::new(
111118
CHARLIE_PUBLIC_KEY.clone(),
112-
TRANSFER_AMOUNT as i64,
113-
TRANSFER_AMOUNT as i64,
119+
BalanceChange::Up(transfer_amount),
120+
BalanceChange::Up(transfer_amount),
114121
))
115122
.await;
116123
// Check if the hold is released.
@@ -190,11 +197,17 @@ async fn erroneous_native_transfer_nofee_norefund_fixed() {
190197
.await;
191198
// Even though the transaction failed, a hold must still be in place for the transfer cost.
192199
// The hold will show up in "available" being smaller than "total"
200+
201+
let transfer_amount_x = U512::from(transfer_amount);
202+
let transfer_amount_y = transfer_amount_x
203+
.checked_sub(U512::from(expected_transfer_cost))
204+
.expect("should sub transfer from transfer amount");
205+
193206
test_scenario
194207
.assert(PublicKeyBalanceChange::new(
195208
CHARLIE_PUBLIC_KEY.clone(),
196-
transfer_amount as i64,
197-
(transfer_amount - expected_transfer_cost) as i64,
209+
BalanceChange::Up(transfer_amount_x),
210+
BalanceChange::Up(transfer_amount_y),
198211
))
199212
.await;
200213
}
@@ -233,24 +246,20 @@ async fn should_cancel_refund_for_erroneous_wasm() {
233246
))
234247
.await;
235248

236-
test_scenario.assert(TransactionFailure::new(hash)).await; // transaction should have failed.
237-
// Bob gets no refund because the wasm errored
249+
// transaction should have failed.
250+
test_scenario.assert(TransactionFailure::new(hash)).await;
251+
252+
let x = BalanceChange::Down(U512::from(expected_transaction_cost));
253+
// Bob gets no refund because the wasm errored
238254
test_scenario
239-
.assert(PublicKeyBalanceChange::new(
240-
BOB_PUBLIC_KEY.clone(),
241-
-(expected_transaction_cost as i64),
242-
-(expected_transaction_cost as i64),
243-
))
255+
.assert(PublicKeyBalanceChange::new(BOB_PUBLIC_KEY.clone(), x, x))
244256
.await;
245257

258+
let y = BalanceChange::Up(U512::from(expected_transaction_cost));
246259
// Alice should get the all the fee since it's set to pay to proposer
247260
// AND Bob didn't get a refund
248261
test_scenario
249-
.assert(PublicKeyBalanceChange::new(
250-
ALICE_PUBLIC_KEY.clone(),
251-
expected_transaction_cost as i64,
252-
expected_transaction_cost as i64,
253-
))
262+
.assert(PublicKeyBalanceChange::new(ALICE_PUBLIC_KEY.clone(), y, y))
254263
.await;
255264
}
256265

@@ -291,19 +300,21 @@ async fn should_not_refund_erroneous_wasm_burn_fixed() {
291300
// Bobs transaction was invalid. He should get NO refund. But also -
292301
// since no refund is calculated nothing will be burned (despite
293302
// RefundHandling::Burn - we don't calculate refunds for erroneous wasms)
303+
let gas_limit_x = BalanceChange::Down(U512::from(gas_limit));
294304
test_scenario
295305
.assert(PublicKeyBalanceChange::new(
296306
BOB_PUBLIC_KEY.clone(),
297-
-(gas_limit as i64),
298-
-(gas_limit as i64),
307+
gas_limit_x,
308+
gas_limit_x,
299309
))
300310
.await;
311+
let gas_limit_y = BalanceChange::Up(U512::from(gas_limit));
301312
// Alice gets payed for executing the transaction since it's set to pay to proposer
302313
test_scenario
303314
.assert(PublicKeyBalanceChange::new(
304315
ALICE_PUBLIC_KEY.clone(),
305-
gas_limit as i64,
306-
gas_limit as i64,
316+
gas_limit_y,
317+
gas_limit_y,
307318
))
308319
.await;
309320
}

0 commit comments

Comments
 (0)