Skip to content

Commit c176dda

Browse files
author
Aaron Blankstein
authored
Merge pull request #2112 from blockstack/fix/2097
Fix: #2097, event dispatcher should not unpack response results
2 parents cdc5614 + ff93610 commit c176dda

File tree

3 files changed

+172
-18
lines changed

3 files changed

+172
-18
lines changed

src/chainstate/stacks/db/transactions.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,6 +3555,120 @@ pub mod test {
35553555
conn.commit_block();
35563556
}
35573557

3558+
#[test]
3559+
fn process_post_conditions_tokens_deny_2097() {
3560+
let privk_origin = StacksPrivateKey::from_hex(
3561+
"027682d2f7b05c3801fe4467883ab4cff0568b5e36412b5289e83ea5b519de8a01",
3562+
)
3563+
.unwrap();
3564+
let privk_recipient = StacksPrivateKey::from_hex(
3565+
"7e3af4db6af6b3c67e2c6c6d7d5983b519f4d9b3a6e00580ae96dcace3bde8bc01",
3566+
)
3567+
.unwrap();
3568+
let auth_origin = TransactionAuth::from_p2pkh(&privk_origin).unwrap();
3569+
let auth_recv = TransactionAuth::from_p2pkh(&privk_recipient).unwrap();
3570+
let addr_publisher = auth_origin.origin().address_testnet();
3571+
let addr_principal = addr_publisher.to_account_principal();
3572+
3573+
let contract = "
3574+
(define-constant owner 'ST3X2W2SH9XQZRHHYJ21KWGTT1N6WX3D48K1NSTPE)
3575+
(define-fungible-token connect-token)
3576+
(begin (ft-mint? connect-token u100000000 owner))
3577+
(define-public (transfer (recipient principal) (amount uint))
3578+
(ok (ft-transfer? connect-token amount tx-sender recipient)))
3579+
"
3580+
.to_string();
3581+
3582+
let contract_name = ContractName::try_from("hello-world").unwrap();
3583+
3584+
let recv_addr = StacksAddress::from_public_keys(
3585+
C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
3586+
&AddressHashMode::SerializeP2PKH,
3587+
1,
3588+
&vec![StacksPublicKey::from_private(&privk_recipient)],
3589+
)
3590+
.unwrap();
3591+
let recv_principal = recv_addr.to_account_principal();
3592+
let contract_id = QualifiedContractIdentifier::new(
3593+
StandardPrincipalData::from(addr_publisher.clone()),
3594+
contract_name.clone(),
3595+
);
3596+
let _contract_principal = PrincipalData::Contract(contract_id.clone());
3597+
3598+
let asset_info = AssetInfo {
3599+
contract_address: addr_publisher.clone(),
3600+
contract_name: contract_name.clone(),
3601+
asset_name: ClarityName::try_from("connect-token").unwrap(),
3602+
};
3603+
3604+
let mut tx_contract = StacksTransaction::new(
3605+
TransactionVersion::Testnet,
3606+
auth_origin.clone(),
3607+
TransactionPayload::new_smart_contract(&"hello-world".to_string(), &contract).unwrap(),
3608+
);
3609+
3610+
tx_contract.chain_id = 0x80000000;
3611+
tx_contract.set_fee_rate(0);
3612+
3613+
let mut signer = StacksTransactionSigner::new(&tx_contract);
3614+
signer.sign_origin(&privk_origin).unwrap();
3615+
3616+
let signed_contract_tx = signer.get_tx().unwrap();
3617+
3618+
let mut tx_contract_call = StacksTransaction::new(
3619+
TransactionVersion::Testnet,
3620+
auth_origin.clone(),
3621+
TransactionPayload::new_contract_call(
3622+
addr_publisher.clone(),
3623+
"hello-world",
3624+
"transfer",
3625+
vec![Value::Principal(recv_principal.clone()), Value::UInt(10)],
3626+
)
3627+
.unwrap(),
3628+
);
3629+
3630+
tx_contract_call.chain_id = 0x80000000;
3631+
tx_contract_call.set_fee_rate(0);
3632+
tx_contract_call.set_origin_nonce(1);
3633+
3634+
tx_contract_call.post_condition_mode = TransactionPostConditionMode::Deny;
3635+
tx_contract_call.add_post_condition(TransactionPostCondition::Fungible(
3636+
PostConditionPrincipal::Origin,
3637+
asset_info.clone(),
3638+
FungibleConditionCode::SentEq,
3639+
10,
3640+
));
3641+
3642+
let mut signer = StacksTransactionSigner::new(&tx_contract_call);
3643+
signer.sign_origin(&privk_origin).unwrap();
3644+
let contract_call_tx = signer.get_tx().unwrap();
3645+
3646+
let mut chainstate = instantiate_chainstate(
3647+
false,
3648+
0x80000000,
3649+
"process-post-conditions-tokens-deny-2097",
3650+
);
3651+
let mut conn = chainstate.block_begin(
3652+
&NULL_BURN_STATE_DB,
3653+
&FIRST_BURNCHAIN_CONSENSUS_HASH,
3654+
&FIRST_STACKS_BLOCK_HASH,
3655+
&ConsensusHash([1u8; 20]),
3656+
&BlockHeaderHash([1u8; 32]),
3657+
);
3658+
3659+
// publish contract
3660+
let _ =
3661+
StacksChainState::process_transaction(&mut conn, &signed_contract_tx, false).unwrap();
3662+
3663+
let (_fee, receipt) =
3664+
StacksChainState::process_transaction(&mut conn, &contract_call_tx, false).unwrap();
3665+
3666+
assert_eq!(receipt.post_condition_aborted, true);
3667+
assert_eq!(receipt.result.to_string(), "(ok (err u1))");
3668+
3669+
conn.commit_block();
3670+
}
3671+
35583672
fn make_account(principal: &PrincipalData, nonce: u64, balance: u128) -> StacksAccount {
35593673
let mut stx_balance = STXBalance::zero();
35603674
stx_balance.credit(balance, 0).unwrap();

testnet/stacks-node/src/event_dispatcher.rs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -145,38 +145,30 @@ impl EventObserver {
145145
) -> serde_json::Value {
146146
let tx = &receipt.transaction;
147147

148-
let (success, result) = match (receipt.post_condition_aborted, &receipt.result) {
148+
let success = match (receipt.post_condition_aborted, &receipt.result) {
149149
(false, Value::Response(response_data)) => {
150-
let status = if response_data.committed {
150+
if response_data.committed {
151151
STATUS_RESP_TRUE
152152
} else {
153153
STATUS_RESP_NOT_COMMITTED
154-
};
155-
(status, response_data.data.clone())
156-
}
157-
(true, Value::Response(response_data)) => {
158-
(STATUS_RESP_POST_CONDITION, response_data.data.clone())
154+
}
159155
}
156+
(true, Value::Response(_)) => STATUS_RESP_POST_CONDITION,
160157
_ => unreachable!(), // Transaction results should always be a Value::Response type
161158
};
162159

163160
let (txid, raw_tx) = match tx {
164161
TransactionOrigin::Burn(txid) => (txid.to_string(), "00".to_string()),
165162
TransactionOrigin::Stacks(ref tx) => {
166163
let txid = tx.txid().to_string();
167-
let mut bytes = vec![];
168-
tx.consensus_serialize(&mut bytes).unwrap();
169-
let formatted_bytes: Vec<String> =
170-
bytes.iter().map(|b| format!("{:02x}", b)).collect();
171-
(txid, formatted_bytes.join(""))
164+
let bytes = tx.serialize_to_vec();
165+
(txid, bytes_to_hex(&bytes))
172166
}
173167
};
174168

175169
let raw_result = {
176-
let mut bytes = vec![];
177-
result.consensus_serialize(&mut bytes).unwrap();
178-
let formatted_bytes: Vec<String> = bytes.iter().map(|b| format!("{:02x}", b)).collect();
179-
formatted_bytes
170+
let bytes = receipt.result.serialize_to_vec();
171+
bytes_to_hex(&bytes)
180172
};
181173
let contract_interface_json = {
182174
match &receipt.contract_analysis {
@@ -188,7 +180,7 @@ impl EventObserver {
188180
"txid": format!("0x{}", &txid),
189181
"tx_index": tx_index,
190182
"status": success,
191-
"raw_result": format!("0x{}", raw_result.join("")),
183+
"raw_result": format!("0x{}", &raw_result),
192184
"raw_tx": format!("0x{}", &raw_tx),
193185
"contract_abi": contract_interface_json,
194186
})

testnet/stacks-node/src/tests/neon_integrations.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@ use stacks::burnchains::{Address, Burnchain, PoxConstants};
66
use stacks::chainstate::burn::ConsensusHash;
77
use stacks::chainstate::stacks::{
88
db::StacksChainState, StacksAddress, StacksBlock, StacksBlockHeader, StacksPrivateKey,
9-
StacksPublicKey, StacksTransaction,
9+
StacksPublicKey, StacksTransaction, TransactionPayload,
1010
};
1111
use stacks::core;
1212
use stacks::net::StacksMessageCodec;
13+
use stacks::util::hash::hex_bytes;
1314
use stacks::util::secp256k1::Secp256k1PublicKey;
1415
use stacks::vm::costs::ExecutionCost;
1516
use stacks::vm::execute;
1617
use stacks::vm::types::PrincipalData;
1718
use stacks::vm::Value;
1819

20+
use stacks::vm::database::ClarityDeserializable;
21+
1922
use super::bitcoin_regtest::BitcoinCoreController;
2023
use crate::{
2124
config::EventKeyType, config::EventObserverConfig, config::InitialBalance, neon,
@@ -772,6 +775,13 @@ fn pox_integration_test() {
772775

773776
let (mut conf, miner_account) = neon_integration_test_conf();
774777

778+
test_observer::spawn();
779+
780+
conf.events_observers.push(EventObserverConfig {
781+
endpoint: format!("localhost:{}", test_observer::EVENT_OBSERVER_PORT),
782+
events_keys: vec![EventKeyType::AnyEvent],
783+
});
784+
775785
let first_bal = 6_000_000_000 * (core::MICROSTACKS_PER_STACKS as u64);
776786
let second_bal = 2_000_000_000 * (core::MICROSTACKS_PER_STACKS as u64);
777787
let third_bal = 2_000_000_000 * (core::MICROSTACKS_PER_STACKS as u64);
@@ -917,6 +927,44 @@ fn pox_integration_test() {
917927
eprintln!("Sort height: {}", sort_height);
918928
}
919929

930+
let blocks_observed = test_observer::get_blocks();
931+
assert!(
932+
blocks_observed.len() >= 2,
933+
"Blocks observed {} should be >= 2",
934+
blocks_observed.len()
935+
);
936+
937+
// look up the return value of our stacking operation...
938+
let mut tested = false;
939+
for block in blocks_observed.iter() {
940+
if tested {
941+
break;
942+
}
943+
let transactions = block.get("transactions").unwrap().as_array().unwrap();
944+
eprintln!("{}", transactions.len());
945+
for tx in transactions.iter() {
946+
let raw_tx = tx.get("raw_tx").unwrap().as_str().unwrap();
947+
if raw_tx == "0x00" {
948+
continue;
949+
}
950+
let tx_bytes = hex_bytes(&raw_tx[2..]).unwrap();
951+
let parsed = StacksTransaction::consensus_deserialize(&mut &tx_bytes[..]).unwrap();
952+
if let TransactionPayload::ContractCall(_) = parsed.payload {
953+
} else {
954+
continue;
955+
}
956+
957+
let raw_result = tx.get("raw_result").unwrap().as_str().unwrap();
958+
let parsed = <Value as ClarityDeserializable<Value>>::deserialize(&raw_result[2..]);
959+
assert_eq!(parsed.to_string(),
960+
format!("(ok (tuple (lock-amount u1000000000000000) (stacker {}) (unlock-burn-height u270)))",
961+
&spender_addr));
962+
tested = true;
963+
}
964+
}
965+
966+
assert!(tested);
967+
920968
// let's stack with spender 2 and spender 3...
921969

922970
// now let's have sender_2 and sender_3 stack to pox addr 2 in

0 commit comments

Comments
 (0)