Skip to content

Commit

Permalink
Merge pull request #1829 from mintlayer/fix/htlc_api_server
Browse files Browse the repository at this point in the history
Fix spending htlc output in api server
  • Loading branch information
azarovh authored Oct 28, 2024
2 parents 6a8917e + cb79940 commit 3ef9bf4
Show file tree
Hide file tree
Showing 12 changed files with 523 additions and 38 deletions.
2 changes: 1 addition & 1 deletion api-server/api-server-common/src/storage/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

pub const CURRENT_STORAGE_VERSION: u32 = 14;
pub const CURRENT_STORAGE_VERSION: u32 = 15;

pub mod in_memory;
pub mod postgres;
42 changes: 36 additions & 6 deletions api-server/scanner-lib/src/blockchain_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,9 @@ async fn calculate_fees<T: ApiServerStorageWrite>(
.zip(input_utxos.iter())
.filter_map(|(inp, utxo)| match inp {
TxInput::Utxo(_) => match utxo.as_ref().expect("must be present") {
TxOutput::Transfer(v, _) | TxOutput::LockThenTransfer(v, _, _) => match v {
TxOutput::Transfer(v, _)
| TxOutput::LockThenTransfer(v, _, _)
| TxOutput::Htlc(v, _) => match v {
OutputValue::TokenV1(token_id, _) => Some(*token_id),
OutputValue::Coin(_) | OutputValue::TokenV0(_) => None,
},
Expand All @@ -607,8 +609,7 @@ async fn calculate_fees<T: ApiServerStorageWrite>(
| TxOutput::CreateDelegationId(_, _)
| TxOutput::IssueFungibleToken(_)
| TxOutput::ProduceBlockFromStake(_, _)
| TxOutput::Htlc(_, _)
| TxOutput::CreateOrder(_) => None,
| TxOutput::CreateOrder(_) => None, // TODO(orders)
},
TxInput::Account(_) => None,
TxInput::AccountCommand(_, cmd) => match cmd {
Expand Down Expand Up @@ -1314,7 +1315,16 @@ async fn update_tables_from_transaction_inputs<T: ApiServerStorageWrite>(
)
.await;
}
TxOutput::Htlc(_, _) => {} // TODO(HTLC)
TxOutput::Htlc(_, htlc) => {
let address =
Address::<Destination>::new(&chain_config, htlc.spend_key)
.expect("Unable to encode destination");

address_transactions
.entry(address.clone())
.or_default()
.insert(tx.get_id());
}
TxOutput::LockThenTransfer(output_value, destination, _)
| TxOutput::Transfer(output_value, destination) => {
let address = Address::<Destination>::new(&chain_config, destination)
Expand Down Expand Up @@ -1729,7 +1739,27 @@ async fn update_tables_from_transaction_outputs<T: ApiServerStorageWrite>(
.expect("Unable to set locked utxo");
}
}
TxOutput::Htlc(_, _) => {} // TODO(HTLC)
TxOutput::Htlc(output_value, htlc) => {
let address = Address::<Destination>::new(&chain_config, htlc.spend_key.clone())
.expect("Unable to encode destination");

address_transactions.entry(address.clone()).or_default().insert(transaction_id);

let token_decimals = match output_value {
OutputValue::Coin(_) | OutputValue::TokenV0(_) => None,
OutputValue::TokenV1(token_id, _) => {
Some(token_decimals(*token_id, &BTreeMap::new(), db_tx).await?.1)
}
};

let outpoint =
UtxoOutPoint::new(OutPointSourceId::Transaction(transaction_id), idx as u32);
let utxo = Utxo::new(output.clone(), token_decimals, false);
db_tx
.set_utxo_at_height(outpoint, utxo, address.as_str(), block_height)
.await
.expect("Unable to set utxo");
}
TxOutput::CreateOrder(_) => {
// TODO(orders)
}
Expand Down Expand Up @@ -1928,11 +1958,11 @@ fn get_tx_output_destination(txo: &TxOutput) -> Option<&Destination> {
| TxOutput::IssueNft(_, _, d)
| TxOutput::ProduceBlockFromStake(d, _) => Some(d),
TxOutput::CreateStakePool(_, data) => Some(data.decommission_key()),
TxOutput::Htlc(_, htlc) => Some(&htlc.spend_key),
TxOutput::IssueFungibleToken(_)
| TxOutput::Burn(_)
| TxOutput::DelegateStaking(_, _)
| TxOutput::DataDeposit(_)
| TxOutput::CreateOrder(_) => None,
TxOutput::Htlc(_, _) => None, // TODO(HTLC)
}
}
2 changes: 1 addition & 1 deletion api-server/scanner-lib/src/sync/tests/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ async fn simulation(
let mut block_builder = tf.make_pos_block_builder().with_random_staking_pool(&mut rng);

for _ in 0..rng.gen_range(10..max_tx_per_block) {
block_builder = block_builder.add_test_transaction(&mut rng, false, false);
block_builder = block_builder.add_test_transaction(&mut rng, false);
}

let block = block_builder.build(&mut rng);
Expand Down
2 changes: 1 addition & 1 deletion api-server/stack-test-suite/tests/v2/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ async fn ok(#[case] seed: Seed) {
"transactions": block.transactions()
.iter()
.zip(tx_additional_data.iter())
.map(|(tx, additinal_data)| tx_to_json(tx.transaction(), additinal_data, tf.chain_config()))
.map(|(tx, additional_data)| tx_to_json(tx.transaction(), additional_data, tf.chain_config()))
.collect::<Vec<_>>(),
},
});
Expand Down
91 changes: 91 additions & 0 deletions api-server/stack-test-suite/tests/v2/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

use chainstate_test_framework::empty_witness;
use chainstate_test_framework::{TestFramework, TransactionBuilder};
use common::chain::tokens::{make_token_id, TokenId, TokenIssuance};
use common::chain::{AccountCommand, AccountNonce, TxInput};
use common::primitives::BlockHeight;
use common::{
address::pubkeyhash::PublicKeyHash,
chain::{
Expand Down Expand Up @@ -137,3 +140,91 @@ pub fn stake_delegation(

(amount_to_delegate, transfer_outpoint, block)
}

#[allow(dead_code)]
pub struct IssueAndMintTokensResult {
pub token_id: TokenId,

pub issue_block: Block,
pub mint_block: Block,

pub change_outpoint: UtxoOutPoint,
pub tokens_outpoint: UtxoOutPoint,
}

pub fn issue_and_mint_tokens_from_genesis(
rng: &mut (impl Rng + CryptoRng),
tf: &mut TestFramework,
) -> IssueAndMintTokensResult {
let token_issuance_fee = tf.chainstate.get_chain_config().fungible_token_issuance_fee();

let issuance = test_utils::nft_utils::random_token_issuance_v1(
tf.chain_config(),
Destination::AnyoneCanSpend,
rng,
);

let genesis_outpoint = UtxoOutPoint::new(tf.best_block_id().into(), 0);
let genesis_coins = chainstate_test_framework::get_output_value(
tf.chainstate.utxo(&genesis_outpoint).unwrap().unwrap().output(),
)
.unwrap()
.coin_amount()
.unwrap();
let coins_after_issue = (genesis_coins - token_issuance_fee).unwrap();

// Issue token
let tx1 = TransactionBuilder::new()
.add_input(genesis_outpoint.into(), empty_witness(rng))
.add_output(TxOutput::Transfer(
OutputValue::Coin(coins_after_issue),
Destination::AnyoneCanSpend,
))
.add_output(TxOutput::IssueFungibleToken(Box::new(TokenIssuance::V1(
issuance,
))))
.build();
let token_id = make_token_id(tx1.transaction().inputs()).unwrap();
let tx1_id = tx1.transaction().get_id();
let block1 = tf.make_block_builder().add_transaction(tx1).build(rng);

tf.process_block(block1.clone(), chainstate::BlockSource::Local).unwrap();

// Mint tokens
let token_supply_change_fee =
tf.chainstate.get_chain_config().token_supply_change_fee(BlockHeight::zero());
let coins_after_mint = (coins_after_issue - token_supply_change_fee).unwrap();
let amount_to_mint = Amount::from_atoms(1000);

let tx2 = TransactionBuilder::new()
.add_input(
TxInput::from_command(
AccountNonce::new(0),
AccountCommand::MintTokens(token_id, amount_to_mint),
),
empty_witness(rng),
)
.add_input(TxInput::from_utxo(tx1_id.into(), 0), empty_witness(rng))
.add_output(TxOutput::Transfer(
OutputValue::Coin(coins_after_mint),
Destination::AnyoneCanSpend,
))
.add_output(TxOutput::Transfer(
OutputValue::TokenV1(token_id, amount_to_mint),
Destination::AnyoneCanSpend,
))
.build();

let tx2_id = tx2.transaction().get_id();
let block2 = tf.make_block_builder().add_transaction(tx2).build(rng);

tf.process_block(block2.clone(), chainstate::BlockSource::Local).unwrap();

IssueAndMintTokensResult {
token_id,
issue_block: block1,
mint_block: block2,
change_outpoint: UtxoOutPoint::new(tx2_id.into(), 0),
tokens_outpoint: UtxoOutPoint::new(tx2_id.into(), 1),
}
}
Loading

0 comments on commit 3ef9bf4

Please sign in to comment.