diff --git a/src/chainstate/burn/db/sortdb.rs b/src/chainstate/burn/db/sortdb.rs index 67ded0cff..c487d3ad2 100644 --- a/src/chainstate/burn/db/sortdb.rs +++ b/src/chainstate/burn/db/sortdb.rs @@ -35,6 +35,7 @@ use rusqlite::{Connection, OpenFlags, OptionalExtension, NO_PARAMS}; use sha2::{Digest, Sha512_256}; use crate::address::AddressHashMode; +use crate::burnchains::AssetType; use crate::burnchains::{Address, PublicKey, Txid}; use crate::burnchains::{ Burnchain, BurnchainBlockHeader, BurnchainRecipient, BurnchainStateTransition, @@ -276,6 +277,26 @@ impl FromRow for StacksEpoch { } } +impl FromRow for RegisterAssetOp { + fn from_row<'a>(row: &'a Row) -> Result { + let txid = Txid::from_column(row, "txid")?; + let burn_header_hash = BurnchainHeaderHash::from_column(row, "l1_block_id")?; + + let asset_str: String = row.get_unwrap("asset_type"); + let asset_type = AssetType::from_str(&asset_str).map_err(|_| db_error::ParseError)?; + let l1_contract_id = QualifiedContractIdentifier::from_column(row, "l1_contract_id")?; + let l2_contract_id = QualifiedContractIdentifier::from_column(row, "l2_contract_id")?; + + Ok(RegisterAssetOp { + txid, + burn_header_hash, + asset_type, + l1_contract_id, + l2_contract_id, + }) + } +} + impl FromRow for DepositStxOp { fn from_row<'a>(row: &'a Row) -> Result { let txid = Txid::from_column(row, "txid")?; @@ -2529,6 +2550,17 @@ impl SortitionDB { Ok(ops.into_iter().flatten().collect()) } + pub fn get_register_asset_ops( + conn: &Connection, + l1_block_id: &BurnchainHeaderHash, + ) -> Result, db_error> { + query_rows( + conn, + "SELECT * FROM register_asset WHERE l1_block_id = ?", + &[l1_block_id], + ) + } + pub fn get_deposit_stx_ops( conn: &Connection, l1_block_id: &BurnchainHeaderHash, diff --git a/src/chainstate/stacks/boot/subnet.clar b/src/chainstate/stacks/boot/subnet.clar index 3fd8bd483..742b6eafd 100644 --- a/src/chainstate/stacks/boot/subnet.clar +++ b/src/chainstate/stacks/boot/subnet.clar @@ -130,6 +130,7 @@ ERR_DISALLOWED_ASSET ) (print { + event: "withdraw", type: "ft", sender: sender, amount: amount, @@ -148,6 +149,7 @@ ERR_DISALLOWED_ASSET ) (print { + event: "withdraw", type: "nft", sender: sender, id: id, @@ -162,6 +164,7 @@ (define-public (stx-withdraw? (amount uint) (sender principal)) (begin (print { + event: "withdraw", type: "stx", sender: sender, amount: amount, diff --git a/src/chainstate/stacks/db/blocks.rs b/src/chainstate/stacks/db/blocks.rs index c1fb3bfec..f019ea35f 100644 --- a/src/chainstate/stacks/db/blocks.rs +++ b/src/chainstate/stacks/db/blocks.rs @@ -4922,6 +4922,12 @@ impl StacksChainState { &parent_consensus_hash )))? .burn_header_hash; + let register_asset_ops = SortitionDB::get_ops_between( + conn, + &parent_block_burn_block, + &burn_tip, + SortitionDB::get_register_asset_ops, + )?; let deposit_stx_ops = SortitionDB::get_ops_between( conn, &parent_block_burn_block, @@ -5054,6 +5060,11 @@ impl StacksChainState { let (applied_epoch_transition, mut tx_receipts) = StacksChainState::process_epoch_transition(&mut clarity_tx, burn_tip_height)?; + tx_receipts.extend(StacksChainState::process_register_asset_ops( + &mut clarity_tx, + register_asset_ops, + )); + tx_receipts.extend(StacksChainState::process_deposit_stx_ops( &mut clarity_tx, deposit_stx_ops, diff --git a/testnet/stacks-node/src/tests/l1_observer_test.rs b/testnet/stacks-node/src/tests/l1_observer_test.rs index c68a8768a..83acbc8b1 100644 --- a/testnet/stacks-node/src/tests/l1_observer_test.rs +++ b/testnet/stacks-node/src/tests/l1_observer_test.rs @@ -1001,16 +1001,21 @@ fn l1_deposit_and_withdraw_asset_integration_test() { serde_json::from_value(contract_event.get("value").unwrap().clone()) .unwrap(); let data_map = value.expect_tuple(); - match data_map - .get("type") - .unwrap() - .clone() - .expect_ascii() - .as_str() - { - "ft" | "nft" => Some((height, data_map.clone())), - _ => None, + if let Ok(event_type) = data_map.get("event") { + if event_type.clone().expect_ascii() == "withdraw" { + return match data_map + .get("type") + .unwrap() + .clone() + .expect_ascii() + .as_str() + { + "ft" | "nft" => Some((height, data_map.clone())), + _ => None, + }; + } } + return None; } _ => None, } @@ -1264,7 +1269,6 @@ fn l1_deposit_and_withdraw_asset_integration_test() { Value::list_from(nft_sib_data).unwrap(), ], ); - l1_nonce += 1; // Withdraw ft-token from subnet contract on L1 submit_tx(&l1_rpc_origin, &l1_withdraw_ft_tx); @@ -1536,10 +1540,14 @@ fn l1_deposit_and_withdraw_stx_integration_test() { serde_json::from_value(contract_event.get("value").unwrap().clone()) .unwrap(); let data_map = value.expect_tuple(); - if data_map.get("type").unwrap().clone().expect_ascii() != "stx" { - return None; + if let Ok(event_type) = data_map.get("event") { + if event_type.clone().expect_ascii() == "withdraw" { + if data_map.get("type").unwrap().clone().expect_ascii() == "stx" { + return Some((height, data_map.clone())); + } + } } - Some((height, data_map.clone())) + return None; } _ => None, } @@ -2314,10 +2322,14 @@ fn nft_deposit_and_withdraw_integration_test() { serde_json::from_value(contract_event.get("value").unwrap().clone()) .unwrap(); let data_map = value.expect_tuple(); - if data_map.get("type").unwrap().clone().expect_ascii() != "nft" { - return None; + if let Ok(event_type) = data_map.get("event") { + if event_type.clone().expect_ascii() == "withdraw" { + if data_map.get("type").unwrap().clone().expect_ascii() == "nft" { + return Some((height, data_map.clone())); + } + } } - Some((height, data_map.clone())) + return None; } _ => None, } @@ -2865,7 +2877,7 @@ fn ft_deposit_and_withdraw_integration_test() { l1_nonce += 1; // deposit 1 ft-token into subnet contract on L1 - let tx_res = submit_tx(&l1_rpc_origin, &l1_deposit_ft_tx); + submit_tx(&l1_rpc_origin, &l1_deposit_ft_tx); // Sleep to give the run loop time to mine a block wait_for_next_stacks_block(&sortition_db); @@ -3028,10 +3040,14 @@ fn ft_deposit_and_withdraw_integration_test() { serde_json::from_value(contract_event.get("value").unwrap().clone()) .unwrap(); let data_map = value.expect_tuple(); - if data_map.get("type").unwrap().clone().expect_ascii() != "ft" { - return None; + if let Ok(event_type) = data_map.get("event") { + if event_type.clone().expect_ascii() == "withdraw" { + if data_map.get("type").unwrap().clone().expect_ascii() == "ft" { + return Some((height, data_map.clone())); + } + } } - Some((height, data_map.clone())) + return None; } _ => None, } diff --git a/testnet/stacks-node/src/tests/l2_withdrawal.rs b/testnet/stacks-node/src/tests/l2_withdrawal.rs index b26c93744..c969f4ebb 100644 --- a/testnet/stacks-node/src/tests/l2_withdrawal.rs +++ b/testnet/stacks-node/src/tests/l2_withdrawal.rs @@ -109,7 +109,6 @@ fn withdraw_unregistered_asset() { "simple-nft", &nft_content, ); - let nft_contract_name = ContractName::from("simple-nft"); submit_tx(l1_rpc_origin, &nft_publish);