diff --git a/core/Cargo.toml b/core/Cargo.toml index 4776bfb6..a43fa082 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -26,9 +26,9 @@ crossbeam = "0.8" tokio = { version = "1", features = ["full"] } tower-http = { version = "0.3.0", features = ["cors"] } axum = "0.5" -ergo-lib = { version = "0.17.0" } +ergo-lib = { version = "0.20.0" } # ergo-lib = { git = "https://github.com/ergoplatform/sigma-rust", rev = "3ada03f6a803a4541ae6d36c28a74efe87c2325b" } -ergo-node-interface = { git = "https://github.com/ergoplatform/ergo-node-interface-rust", rev = "84ac6ed680cf3a33b4089fea5e377a07d4df64b4" } +ergo-node-interface = { git = "https://github.com/ergoplatform/ergo-node-interface-rust", rev = "f10aa6ab8392524363faa2916a2b61ad6d99cb62" } derive_more = "0.99" # bounded-vec = { version = "^0.5.0" } clap = {version = "=3.1.18", features = ["derive"]} @@ -38,7 +38,7 @@ lazy_static = "1.4.0" [dev-dependencies] # sigma-test-util = { version = "^0.3.0", path = "../../sigma-rust/sigma-test-util" } # ergo-lib = { git = "https://github.com/ergoplatform/sigma-rust", rev = "3ada03f6a803a4541ae6d36c28a74efe87c2325b" , features = ["arbitrary"]} -ergo-lib = { version = "0.17.0", features = ["arbitrary"]} +ergo-lib = { version = "0.20.0", features = ["arbitrary"]} proptest = {version = "1.0.0"} proptest-derive = {version = "0.3.0"} sigma-test-util = {version = "0.3.0"} diff --git a/core/src/actions.rs b/core/src/actions.rs index ff67a009..dbca3fae 100644 --- a/core/src/actions.rs +++ b/core/src/actions.rs @@ -2,7 +2,6 @@ /// by an oracle part of the oracle pool. These actions /// are implemented on the `OraclePool` struct. use crate::node_interface::sign_and_submit_transaction; -use crate::oracle_state::OraclePool; use ergo_lib::chain::transaction::unsigned::UnsignedTransaction; use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox; @@ -50,8 +49,14 @@ pub enum ActionExecError { pub fn execute_action(action: PoolAction) -> Result<(), ActionExecError> { match action { - PoolAction::Refresh(action) => execute_refresh_action(action), - PoolAction::PublishDatapoint(action) => execute_publish_datapoint_action(action), + PoolAction::Refresh(action) => { + log::info!("Executing refresh action: {:?}", action); + execute_refresh_action(action) + } + PoolAction::PublishDatapoint(action) => { + log::info!("Executing publish datapoint action: {:?}", action); + execute_publish_datapoint_action(action) + } } } @@ -65,223 +70,6 @@ fn execute_publish_datapoint_action(action: PublishDataPointAction) -> Result<() Ok(()) } -impl<'a> OraclePool<'a> { - // /// Generates and submits the "Collect Funds" action tx - // pub fn action_collect_funds(&self) -> Result { - // let mut req = json::parse(BASIC_TRANSACTION_SEND_REQUEST).unwrap(); - - // // Defining the registers of the output box - // let epoch_prep_state = self.get_preparation_state()?; - // let registers = object! { - // "R4": Constant::from(epoch_prep_state.latest_pool_datapoint as i64).base16_str().unwrap(), - - // "R5": Constant::from(epoch_prep_state.next_epoch_ends as i32).base16_str().unwrap(), - // }; - // // Defining the tokens to be spent - // let token_json = object! { - // "tokenId": self.oracle_pool_nft.to_string(), - // "amount": 1 - // }; - - // // Create input boxes Vec with serialized Epoch Preparation box inside - // let mut unserialized_input_boxes = vec![self.epoch_preparation_stage.get_box()?]; - // // Acquire all Pool Deposit boxes - // let mut initial_deposit_boxes = self.pool_deposit_stage.get_boxes()?; - // // Only append up to 27 boxes for now. This is to prevent exceeding execution limit for txs. - // if initial_deposit_boxes.len() > 27 { - // unserialized_input_boxes.append(&mut initial_deposit_boxes[..27].to_vec()); - // } else { - // unserialized_input_boxes.append(&mut initial_deposit_boxes); - // } - - // // Define the fee for the current action - // let action_fee = 500000 * unserialized_input_boxes.len() as u64; - - // // Serialize boxes and add extra box for paying fee - // let mut serialized_input_boxes = serialize_boxes(&unserialized_input_boxes)?; - // serialized_input_boxes.append(&mut serialized_unspent_boxes_with_min_total(action_fee)?); - - // // Sum up the new total minus tx fee - // let total_input_ergs = unserialized_input_boxes - // .iter() - // .fold(0, |acc, b| acc + b.value.as_u64()); - - // // Filling out the json tx request template - // req["requests"][0]["value"] = total_input_ergs.into(); - // req["requests"][0]["address"] = - // self.epoch_preparation_stage.contract_address.clone().into(); - // req["requests"][0]["registers"] = registers; - // req["requests"][0]["assets"] = vec![token_json].into(); - // req["inputsRaw"] = serialized_input_boxes.into(); - // req["fee"] = action_fee.into(); - - // let result = send_transaction(&req)?; - // Ok(result) - // } - - // /// Generates and submits the "Start Next Epoch" action tx - // pub fn action_start_next_epoch(&self) -> Result { - // let parameters = PoolParameters::new(); - // let mut req = json::parse(BASIC_TRANSACTION_SEND_REQUEST)?; - - // // Defining the registers of the output box - // let epoch_prep_state = self.get_preparation_state()?; - // let registers = object! { - // "R4": Constant::from(epoch_prep_state.latest_pool_datapoint as i64).base16_str().unwrap(), - // "R5": Constant::from(epoch_prep_state.next_epoch_ends as i32).base16_str().unwrap(), - // "R6": serialize_hex_encoded_string(&string_to_blake2b_hash(address_to_tree(&self.epoch_preparation_stage.contract_address)?)?)?.base16_str().unwrap(), - // }; - // // Defining the tokens to be spent - // let token_json = object! { - // "tokenId": self.oracle_pool_nft.to_string(), - // "amount": 1 - // }; - - // let mut inputs_raw = vec![self.epoch_preparation_stage.get_serialized_box()?]; - // inputs_raw.append(&mut serialized_unspent_boxes_with_min_total( - // parameters.base_fee, - // )?); - - // // Filling out the json tx request template - // req["requests"][0]["value"] = epoch_prep_state.funds.into(); - // req["requests"][0]["address"] = self.live_epoch_stage.contract_address.clone().into(); - // req["requests"][0]["registers"] = registers; - // req["requests"][0]["assets"] = vec![token_json].into(); - // req["inputsRaw"] = inputs_raw.into(); - // req["fee"] = parameters.base_fee.into(); - - // let result = send_transaction(&req)?; - // Ok(result) - // } - - // /// Generates and submits the "Create New Epoch" action tx - // pub fn action_create_new_epoch(&self) -> Result { - // let parameters = PoolParameters::new(); - // let mut req = json::parse(BASIC_TRANSACTION_SEND_REQUEST)?; - - // // Define the new epoch finish height based off of current height - // let new_finish_height = current_block_height()? - // + parameters.epoch_preparation_length - // + parameters.live_epoch_length - // + parameters.buffer_length; - - // // Defining the registers of the output box - // let epoch_prep_state = self.get_preparation_state()?; - // let registers = object! { - // "R4": Constant::from(epoch_prep_state.latest_pool_datapoint as i64).base16_str().unwrap(), - // "R5": Constant::from(new_finish_height as i32).base16_str().unwrap(), - // "R6": serialize_hex_encoded_string(&string_to_blake2b_hash(address_to_tree(&self.epoch_preparation_stage.contract_address)?)?)?.base16_str().unwrap(), - // }; - // // Defining the tokens to be spent - // let token_json = object! { - // "tokenId": self.oracle_pool_nft.to_string(), - // "amount": 1 - // }; - - // let mut inputs_raw = vec![self.epoch_preparation_stage.get_serialized_box()?]; - // inputs_raw.append(&mut serialized_unspent_boxes_with_min_total( - // parameters.base_fee, - // )?); - - // // Filling out the json tx request template - // req["requests"][0]["value"] = epoch_prep_state.funds.into(); - // req["requests"][0]["address"] = self.live_epoch_stage.contract_address.clone().into(); - // req["requests"][0]["registers"] = registers; - // req["requests"][0]["assets"] = vec![token_json].into(); - // req["inputsRaw"] = inputs_raw.into(); - // req["fee"] = parameters.base_fee.into(); - - // let result = send_transaction(&req)?; - // Ok(result) - // } - - /* - /// Generates and submits the "Collect Datapoints" action tx - pub fn action_collect_datapoints(&self) -> Result { - let parameters = PoolParameters::new(); - let mut req = json::parse(BASIC_TRANSACTION_SEND_REQUEST)?; - - let live_epoch_state = self.get_live_epoch_state()?; - - // Filter out Datapoint boxes not from the latest epoch - let current_epoch_datapoint_boxes = - current_epoch_boxes_filter(&self.datapoint_stage.get_boxes()?, &live_epoch_state); - // Sort Datapoint boxes in decreasing order - let sorted_datapoint_boxes = sort_datapoint_boxes(¤t_epoch_datapoint_boxes); - - // Acquire the finalized oracle pool datapoint and the list of successful datapoint boxes which were within the deviation range - let (finalized_datapoint, successful_boxes) = finalize_datapoint( - &sorted_datapoint_boxes, - parameters.deviation_range as i64, // Make sure to change this to config # - parameters.consensus_num as i64, // Make sure to change this to config # - )?; - - // Find the index of the local oracle's Datapoint box in the successful boxes list - let local_datapoint_box_index = find_box_index_in_list( - self.local_oracle_datapoint_scan.get_box()?, - &successful_boxes, - ) - .ok_or(CollectionError::LocalOracleFailedToPostDatapointWithinDeviation())?; - - // Tx fee for the transaction - let tx_fee = (parameters.base_fee) * sorted_datapoint_boxes.len() as u64; - // Define the new value of the oracle pool box after payouts/tx fee - let new_box_value = live_epoch_state.funds - - (parameters.oracle_payout_price * (successful_boxes.len() as u64 + 1)); - // Define the finish height of the following epoch - let new_finish_height = self.get_live_epoch_state()?.epoch_ends - + parameters.epoch_preparation_length - + parameters.live_epoch_length; - - // Defining json request for the oracle pool box - let token_json = object! { - "tokenId": self.oracle_pool_nft.to_string(), - "amount": 1 - }; - let registers = object! { - "R4": Constant::from(finalized_datapoint as i64).base16_str().unwrap(), - "R5": Constant::from(new_finish_height as i32).base16_str().unwrap(), - }; - let mut inputs_raw = vec![self.live_epoch_stage.get_serialized_box()?]; - inputs_raw.append(&mut serialized_unspent_boxes_with_min_total(tx_fee)?); - - req["requests"][0]["value"] = new_box_value.into(); - req["requests"][0]["address"] = - self.epoch_preparation_stage.contract_address.clone().into(); - req["requests"][0]["registers"] = registers; - req["requests"][0]["assets"] = vec![token_json].into(); - - // Filling out requests for the oracle payout outputs - for b in &successful_boxes { - // Get the P2PK from the hex encoded constant string minus the first two characters which are a register type descriptor - let oracle_address = raw_from_register_to_address( - &b.additional_registers.get_ordered_values()[0].base16_str().unwrap(), - )?; - req["requests"] - .push(object! { - "address": oracle_address, - "value": parameters.oracle_payout_price, - }) - .ok(); - } - // Add the local oracle Datapoint box index into R4 of the first oracle payout box - req["requests"][1]["registers"] = object! { - "R4": Constant::from(local_datapoint_box_index as i32).base16_str().unwrap() - }; - // Pay the local oracle double due to being Collector - req["requests"][local_datapoint_box_index + 1]["value"] = - (parameters.oracle_payout_price * 2).into(); - // Filling out the rest of the json request - req["inputsRaw"] = inputs_raw.into(); - req["dataInputsRaw"] = serialize_boxes(&successful_boxes)?.into(); - req["fee"] = tx_fee.into(); - - let result = send_transaction(&req)?; - Ok(result) - } - */ -} - /// Given an `ErgoBox`, find its index in the input `Vec` /// If index cannot be found, then local oracle has not submit their /// own datapoint, and thus the function returns `None` diff --git a/core/src/api.rs b/core/src/api.rs index 8ac1e069..0993d26f 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -1,5 +1,6 @@ use std::net::SocketAddr; +use crate::box_kind::OracleBox; use crate::node_interface::current_block_height; use crate::oracle_config::{get_core_api_port, get_node_ip, get_node_port, ORACLE_CONFIG}; use crate::oracle_state::{OraclePool, StageDataSource}; @@ -33,18 +34,21 @@ async fn oracle_status() -> impl IntoResponse { Err(_) => false, }; // Get latest datapoint the local oracle produced/submit - let self_datapoint = match op.get_datapoint_state() { - Ok(Some(d)) => d.datapoint, + let latest_oracle_box = op + .get_local_datapoint_box_source() + .get_local_oracle_datapoint_box(); + let self_datapoint = match latest_oracle_box { + Ok(Some(ref d)) => d.rate(), Ok(None) | Err(_) => 0, }; // Get latest datapoint submit epoch - let datapoint_epoch = match op.get_datapoint_state() { - Ok(Some(d)) => d.origin_epoch_id, + let datapoint_epoch = match latest_oracle_box { + Ok(Some(ref d)) => d.epoch_counter(), Ok(None) | Err(_) => 0, }; // Get latest datapoint submit epoch - let datapoint_creation = match op.get_datapoint_state() { - Ok(Some(d)) => d.creation_height, + let datapoint_creation = match latest_oracle_box { + Ok(Some(ref d)) => d.get_box().creation_height, Ok(None) | Err(_) => 0, }; diff --git a/core/src/box_kind/pool_box.rs b/core/src/box_kind/pool_box.rs index 367c17bb..b82d501e 100644 --- a/core/src/box_kind/pool_box.rs +++ b/core/src/box_kind/pool_box.rs @@ -41,7 +41,7 @@ pub enum PoolBoxError { UnknownRewardTokenId, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct PoolBoxWrapper(ErgoBox, PoolContract); impl PoolBoxWrapper { diff --git a/core/src/box_kind/refresh_box.rs b/core/src/box_kind/refresh_box.rs index ad8b658b..03412079 100644 --- a/core/src/box_kind/refresh_box.rs +++ b/core/src/box_kind/refresh_box.rs @@ -79,7 +79,7 @@ impl RefreshBoxWrapperInputs { } impl RefreshBoxWrapper { - pub fn new(b: ErgoBox, inputs: RefreshBoxWrapperInputs) -> Result { + pub fn new(b: ErgoBox, inputs: &RefreshBoxWrapperInputs) -> Result { let refresh_token_id = b .tokens .as_ref() diff --git a/core/src/cli_commands/bootstrap.rs b/core/src/cli_commands/bootstrap.rs index 4ecbe46b..82df4795 100644 --- a/core/src/cli_commands/bootstrap.rs +++ b/core/src/cli_commands/bootstrap.rs @@ -225,7 +225,6 @@ pub(crate) fn perform_bootstrap_chained_transaction( height, tx_fee, change_address.clone(), - BoxValue::MIN, ); let mint_token_tx = tx_builder.build()?; debug!("Mint token unsigned transaction: {:?}", mint_token_tx); @@ -388,7 +387,7 @@ pub(crate) fn perform_bootstrap_chained_transaction( 0, 1, pool_nft_token.clone(), - reward_tokens_for_pool_box, + reward_tokens_for_pool_box.clone(), erg_value_per_box, height, )?; @@ -424,7 +423,7 @@ pub(crate) fn perform_bootstrap_chained_transaction( let box_selection = box_selector.select( inputs, target_balance, - &[pool_nft_token.clone(), reward_token.clone()], + &[pool_nft_token.clone(), reward_tokens_for_pool_box.clone()], )?; let inputs = box_selection.boxes.clone(); let tx_builder = TxBuilder::new( @@ -433,7 +432,6 @@ pub(crate) fn perform_bootstrap_chained_transaction( height, tx_fee, change_address.clone(), - BoxValue::MIN, ); let pool_box_tx = tx_builder.build()?; debug!("unsigned pool_box_tx: {:?}", pool_box_tx); @@ -490,7 +488,6 @@ pub(crate) fn perform_bootstrap_chained_transaction( height, tx_fee, change_address.clone(), - BoxValue::MIN, ); let refresh_box_tx = tx_builder.build()?; debug!("unsigned refresh_box_tx: {:?}", refresh_box_tx); diff --git a/core/src/cli_commands/extract_reward_tokens.rs b/core/src/cli_commands/extract_reward_tokens.rs index cf5a4de8..d6d6f5bb 100644 --- a/core/src/cli_commands/extract_reward_tokens.rs +++ b/core/src/cli_commands/extract_reward_tokens.rs @@ -10,7 +10,6 @@ use ergo_lib::{ ergotree_ir::{ chain::{ address::{Address, AddressEncoder, AddressEncoderError}, - ergo_box::box_value::BoxValue, token::Token, }, serialization::SigmaParsingError, @@ -62,47 +61,43 @@ pub enum ExtractRewardTokensActionError { pub fn extract_reward_tokens( wallet: &dyn WalletDataSource, - local_datapoint_box_source: Option<&dyn LocalDatapointBoxSource>, + local_datapoint_box_source: &dyn LocalDatapointBoxSource, rewards_destination_str: String, ) -> Result<(), ExtractRewardTokensActionError> { - if let Some(local_datapoint_box_source) = local_datapoint_box_source { - let rewards_destination = - AddressEncoder::unchecked_parse_network_address_from_str(&rewards_destination_str)?; - let network_prefix = rewards_destination.network(); + let rewards_destination = + AddressEncoder::unchecked_parse_network_address_from_str(&rewards_destination_str)?; + let network_prefix = rewards_destination.network(); - let change_address_str = get_wallet_status()? - .change_address - .ok_or(ExtractRewardTokensActionError::NoChangeAddressSetInNode)?; + let change_address_str = get_wallet_status()? + .change_address + .ok_or(ExtractRewardTokensActionError::NoChangeAddressSetInNode)?; - let change_address = - AddressEncoder::new(network_prefix).parse_address_from_str(&change_address_str)?; - let (unsigned_tx, num_reward_tokens) = build_extract_reward_tokens_tx( - local_datapoint_box_source, - wallet, - rewards_destination.address(), - current_block_height()? as u32, - change_address, - )?; + let change_address = + AddressEncoder::new(network_prefix).parse_address_from_str(&change_address_str)?; + let (unsigned_tx, num_reward_tokens) = build_extract_reward_tokens_tx( + local_datapoint_box_source, + wallet, + rewards_destination.address(), + current_block_height()? as u32, + change_address, + )?; + println!( + "YOU WILL BE TRANSFERRING {} REWARD TOKENS TO {}. TYPE 'YES' TO INITIATE THE TRANSACTION.", + num_reward_tokens, rewards_destination_str + ); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + if input == "YES" { + let tx_id_str = sign_and_submit_transaction(&unsigned_tx)?; println!( - "YOU WILL BE TRANSFERRING {} REWARD TOKENS TO {}. TYPE 'YES' TO INITIATE THE TRANSACTION.", - num_reward_tokens, rewards_destination_str + "Transaction made. Check status here: {}", + ergo_explorer_transaction_link(tx_id_str, network_prefix) ); - let mut input = String::new(); - std::io::stdin().read_line(&mut input)?; - if input == "YES" { - let tx_id_str = sign_and_submit_transaction(&unsigned_tx)?; - println!( - "Transaction made. Check status here: {}", - ergo_explorer_transaction_link(tx_id_str, network_prefix) - ); - } else { - println!("Aborting the transaction.") - } - Ok(()) } else { - Err(ExtractRewardTokensActionError::NoLocalDatapointBox) + println!("Aborting the transaction.") } + Ok(()) } fn build_extract_reward_tokens_tx( @@ -112,7 +107,9 @@ fn build_extract_reward_tokens_tx( height: u32, change_address: Address, ) -> Result<(UnsignedTransaction, u64), ExtractRewardTokensActionError> { - let in_oracle_box = local_datapoint_box_source.get_local_oracle_datapoint_box()?; + let in_oracle_box = local_datapoint_box_source + .get_local_oracle_datapoint_box()? + .ok_or(ExtractRewardTokensActionError::NoLocalDatapointBox)?; let num_reward_tokens = *in_oracle_box.reward_token().amount.as_u64(); if num_reward_tokens <= 1 { return Err( @@ -168,7 +165,6 @@ fn build_extract_reward_tokens_tx( height, *BASE_FEE, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the oracle contract is properly set. let ctx_ext = ContextExtension { @@ -255,6 +251,7 @@ mod tests { let mut possible_input_boxes = vec![local_datapoint_box_source .get_local_oracle_datapoint_box() .unwrap() + .unwrap() .get_box() .clone()]; possible_input_boxes.append(&mut wallet_mock.get_unspent_wallet_boxes().unwrap()); diff --git a/core/src/cli_commands/prepare_update.rs b/core/src/cli_commands/prepare_update.rs index 213d3e17..12ab9853 100644 --- a/core/src/cli_commands/prepare_update.rs +++ b/core/src/cli_commands/prepare_update.rs @@ -211,7 +211,6 @@ pub(crate) fn perform_update_chained_transaction( height, tx_fee, change_address.clone(), - BoxValue::MIN, ); let mint_token_tx = tx_builder.build()?; debug!("Mint token unsigned transaction: {:?}", mint_token_tx); diff --git a/core/src/cli_commands/print_reward_tokens.rs b/core/src/cli_commands/print_reward_tokens.rs index 592500e9..b2c203c8 100644 --- a/core/src/cli_commands/print_reward_tokens.rs +++ b/core/src/cli_commands/print_reward_tokens.rs @@ -4,10 +4,9 @@ use crate::{ }; pub fn print_reward_tokens( - local_datapoint_box_source: Option<&dyn LocalDatapointBoxSource>, + local_datapoint_box_source: &dyn LocalDatapointBoxSource, ) -> Result<(), StageError> { - if let Some(loc) = local_datapoint_box_source { - let oracle_box = loc.get_local_oracle_datapoint_box()?; + if let Some(oracle_box) = local_datapoint_box_source.get_local_oracle_datapoint_box()? { let num_tokens = *oracle_box.reward_token().amount.as_u64(); if num_tokens == 0 { println!("Oracle box contains zero reward tokens"); diff --git a/core/src/cli_commands/transfer_oracle_token.rs b/core/src/cli_commands/transfer_oracle_token.rs index 33c07081..2bcaf413 100644 --- a/core/src/cli_commands/transfer_oracle_token.rs +++ b/core/src/cli_commands/transfer_oracle_token.rs @@ -8,10 +8,7 @@ use ergo_lib::{ }, ergotree_interpreter::sigma_protocol::prover::ContextExtension, ergotree_ir::{ - chain::{ - address::{Address, AddressEncoder, AddressEncoderError}, - ergo_box::box_value::BoxValue, - }, + chain::address::{Address, AddressEncoder, AddressEncoderError}, serialization::SigmaParsingError, }, wallet::{ @@ -61,48 +58,44 @@ pub enum TransferOracleTokenActionError { pub fn transfer_oracle_token( wallet: &dyn WalletDataSource, - local_datapoint_box_source: Option<&dyn LocalDatapointBoxSource>, + local_datapoint_box_source: &dyn LocalDatapointBoxSource, rewards_destination_str: String, ) -> Result<(), TransferOracleTokenActionError> { - if let Some(local_datapoint_box_source) = local_datapoint_box_source { - let rewards_destination = - AddressEncoder::unchecked_parse_network_address_from_str(&rewards_destination_str)?; + let rewards_destination = + AddressEncoder::unchecked_parse_network_address_from_str(&rewards_destination_str)?; - let change_address_str = get_wallet_status()? - .change_address - .ok_or(TransferOracleTokenActionError::NoChangeAddressSetInNode)?; - - let (change_address, network_prefix) = { - let a = AddressEncoder::unchecked_parse_network_address_from_str(&change_address_str)?; - (a.address(), a.network()) - }; - let unsigned_tx = build_transfer_oracle_token_tx( - local_datapoint_box_source, - wallet, - rewards_destination.address(), - current_block_height()? as u32, - change_address, - )?; + let change_address_str = get_wallet_status()? + .change_address + .ok_or(TransferOracleTokenActionError::NoChangeAddressSetInNode)?; + let (change_address, network_prefix) = { + let a = AddressEncoder::unchecked_parse_network_address_from_str(&change_address_str)?; + (a.address(), a.network()) + }; + let unsigned_tx = build_transfer_oracle_token_tx( + local_datapoint_box_source, + wallet, + rewards_destination.address(), + current_block_height()? as u32, + change_address, + )?; + + println!( + "YOU WILL BE TRANSFERRING YOUR ORACLE TOKEN TO {}. TYPE 'YES' TO INITIATE THE TRANSACTION.", + rewards_destination_str + ); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + if input == "YES" { + let tx_id_str = sign_and_submit_transaction(&unsigned_tx)?; println!( - "YOU WILL BE TRANSFERRING YOUR ORACLE TOKEN TO {}. TYPE 'YES' TO INITIATE THE TRANSACTION.", - rewards_destination_str + "Transaction made. Check status here: {}", + ergo_explorer_transaction_link(tx_id_str, network_prefix) ); - let mut input = String::new(); - std::io::stdin().read_line(&mut input)?; - if input == "YES" { - let tx_id_str = sign_and_submit_transaction(&unsigned_tx)?; - println!( - "Transaction made. Check status here: {}", - ergo_explorer_transaction_link(tx_id_str, network_prefix) - ); - } else { - println!("Aborting the transaction.") - } - Ok(()) } else { - Err(TransferOracleTokenActionError::NoLocalDatapointBox) + println!("Aborting the transaction.") } + Ok(()) } fn build_transfer_oracle_token_tx( local_datapoint_box_source: &dyn LocalDatapointBoxSource, @@ -111,7 +104,9 @@ fn build_transfer_oracle_token_tx( height: u32, change_address: Address, ) -> Result { - let in_oracle_box = local_datapoint_box_source.get_local_oracle_datapoint_box()?; + let in_oracle_box = local_datapoint_box_source + .get_local_oracle_datapoint_box()? + .ok_or(TransferOracleTokenActionError::NoLocalDatapointBox)?; let num_reward_tokens = *in_oracle_box.reward_token().amount.as_u64(); if num_reward_tokens <= 1 { return Err( @@ -150,7 +145,6 @@ fn build_transfer_oracle_token_tx( height, target_balance, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the oracle contract is properly set. let ctx_ext = ContextExtension { @@ -234,6 +228,7 @@ mod tests { let mut possible_input_boxes = vec![local_datapoint_box_source .get_local_oracle_datapoint_box() .unwrap() + .unwrap() .get_box() .clone()]; possible_input_boxes.append(&mut wallet_mock.get_unspent_wallet_boxes().unwrap()); diff --git a/core/src/cli_commands/update_pool.rs b/core/src/cli_commands/update_pool.rs index ce6ae1f8..f56d1f65 100644 --- a/core/src/cli_commands/update_pool.rs +++ b/core/src/cli_commands/update_pool.rs @@ -8,7 +8,7 @@ use ergo_lib::{ ergotree_interpreter::sigma_protocol::prover::ContextExtension, ergotree_ir::chain::{ address::{Address, AddressEncoder, AddressEncoderError}, - ergo_box::{box_value::BoxValue, ErgoBox, NonMandatoryRegisterId}, + ergo_box::{ErgoBox, NonMandatoryRegisterId}, token::Token, }, ergotree_ir::serialization::SigmaSerializable, @@ -312,9 +312,12 @@ fn build_update_pool_box_tx( height, *BASE_FEE, change_address, - BoxValue::MIN, ); + if reward_tokens.token_id != old_pool_box.reward_token().token_id { + tx_builder.set_token_burn_permit(vec![old_pool_box.reward_token().clone()]); + } + for (i, input_ballot) in vote_ballot_boxes.iter().enumerate() { tx_builder.set_context_extension( input_ballot.get_box().box_id(), @@ -363,9 +366,10 @@ mod tests { pool::{PoolContract, PoolContractInputs}, update::{UpdateContract, UpdateContractInputs, UpdateContractParameters}, }, - oracle_config::{TokenIds, BASE_FEE}, + oracle_config::BASE_FEE, pool_commands::test_utils::{ - make_wallet_unspent_box, BallotBoxesMock, PoolBoxMock, UpdateBoxMock, WalletDataMock, + generate_token_ids, make_wallet_unspent_box, BallotBoxesMock, PoolBoxMock, + UpdateBoxMock, WalletDataMock, }, }; @@ -380,19 +384,14 @@ mod tests { .unwrap() .current() } + #[test] fn test_update_pool_box() { let ctx = force_any_val::(); let height = ctx.pre_header.height; - let token_ids = TokenIds { - pool_nft_token_id: force_any_tokenid(), - update_nft_token_id: force_any_tokenid(), - refresh_nft_token_id: force_any_tokenid(), - reward_token_id: force_any_tokenid(), - oracle_token_id: force_any_tokenid(), - ballot_token_id: force_any_tokenid(), - }; + let token_ids = generate_token_ids(); + dbg!(&token_ids); let reward_tokens = Token { token_id: token_ids.reward_token_id.clone(), amount: 1500.try_into().unwrap(), @@ -401,6 +400,7 @@ mod tests { token_id: force_any_tokenid(), amount: force_any_val(), }; + dbg!(&new_reward_tokens); let default_update_contract_parameters = UpdateContractParameters::default(); let update_contract_parameters = UpdateContractParameters::build_with( diff --git a/core/src/cli_commands/vote_update_pool.rs b/core/src/cli_commands/vote_update_pool.rs index 8398ee5e..75c804dd 100644 --- a/core/src/cli_commands/vote_update_pool.rs +++ b/core/src/cli_commands/vote_update_pool.rs @@ -20,7 +20,7 @@ use ergo_lib::{ use ergo_node_interface::node_interface::NodeError; use crate::{ - box_kind::{make_local_ballot_box_candidate, BallotBox}, + box_kind::{make_local_ballot_box_candidate, BallotBox, BallotBoxWrapper}, cli_commands::ergo_explorer_transaction_link, contracts::ballot::{ BallotContract, BallotContractError, BallotContractInputs, BallotContractParameters, @@ -61,7 +61,7 @@ pub enum VoteUpdatePoolError { pub fn vote_update_pool( wallet: &dyn WalletDataSource, - local_ballot_box_source: Option<&dyn LocalBallotBoxSource>, + local_ballot_box_source: &dyn LocalBallotBoxSource, new_pool_box_address_hash_str: String, reward_token_id_str: String, reward_token_amount: u32, @@ -77,11 +77,11 @@ pub fn vote_update_pool( let height = current_block_height()? as u32; let new_pool_box_address_hash = Digest32::try_from(new_pool_box_address_hash_str)?; let reward_token_id = TokenId::from_base64(&reward_token_id_str)?; - let unsigned_tx = if let Some(local_ballot_box_source) = local_ballot_box_source { + let unsigned_tx = if let Some(local_ballot_box) = local_ballot_box_source.get_ballot_box()? { // Note: the ballot box contains the ballot token, but the box is guarded by the contract, // which stipulates that the address in R4 is the 'owner' of the token build_tx_with_existing_ballot_box( - local_ballot_box_source, + local_ballot_box, wallet, new_pool_box_address_hash.clone(), reward_token_id.clone(), @@ -135,7 +135,7 @@ pub fn vote_update_pool( #[allow(clippy::too_many_arguments)] fn build_tx_with_existing_ballot_box( - local_ballot_box_source: &dyn LocalBallotBoxSource, + in_ballot_box: BallotBoxWrapper, wallet: &dyn WalletDataSource, new_pool_box_address_hash: Digest32, reward_token_id: TokenId, @@ -144,10 +144,7 @@ fn build_tx_with_existing_ballot_box( height: u32, change_address: Address, ) -> Result { - let in_ballot_box = local_ballot_box_source.get_ballot_box()?; - let unspent_boxes = wallet.get_unspent_wallet_boxes()?; - let target_balance = BoxValue::try_from(in_ballot_box.min_storage_rent()).unwrap(); let reward_token = Token { token_id: reward_token_id, amount: TokenAmount::try_from(reward_token_amount as u64).unwrap(), @@ -159,11 +156,11 @@ fn build_tx_with_existing_ballot_box( in_ballot_box.ballot_token(), new_pool_box_address_hash, reward_token, - target_balance, + in_ballot_box.get_box().value, update_box_creation_height, )?; let box_selector = SimpleBoxSelector::new(); - let selection = box_selector.select(unspent_boxes, target_balance, &[])?; + let selection = box_selector.select(unspent_boxes, *BASE_FEE, &[])?; let mut input_boxes = vec![in_ballot_box.get_box().clone()]; input_boxes.append(selection.boxes.as_vec().clone().as_mut()); let box_selection = BoxSelection { @@ -176,7 +173,6 @@ fn build_tx_with_existing_ballot_box( height, *BASE_FEE, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the ballot contract is properly set. let ctx_ext = ContextExtension { @@ -201,7 +197,8 @@ fn build_tx_for_first_ballot_box( change_address: Address, ) -> Result { let unspent_boxes = wallet.get_unspent_wallet_boxes()?; - let target_balance = BoxValue::try_from(ballot_contract_parameters.min_storage_rent()).unwrap(); + let out_ballot_box_value = + BoxValue::try_from(ballot_contract_parameters.min_storage_rent()).unwrap(); let reward_token = Token { token_id: reward_token_id, amount: TokenAmount::try_from(reward_token_amount as u64).unwrap(), @@ -223,11 +220,11 @@ fn build_tx_for_first_ballot_box( ballot_token.clone(), new_pool_box_address_hash, reward_token, - target_balance, + out_ballot_box_value, height, )?; let box_selector = SimpleBoxSelector::new(); - let selection_target_balance = target_balance.checked_add(&*BASE_FEE).unwrap(); + let selection_target_balance = out_ballot_box_value.checked_add(&*BASE_FEE).unwrap(); let selection = box_selector.select(unspent_boxes, selection_target_balance, &[ballot_token])?; let box_selection = BoxSelection { @@ -240,7 +237,6 @@ fn build_tx_for_first_ballot_box( height, *BASE_FEE, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the ballot contract is properly set. let ctx_ext = ContextExtension { @@ -276,8 +272,7 @@ mod tests { contracts::ballot::{BallotContract, BallotContractInputs, BallotContractParameters}, oracle_config::BASE_FEE, pool_commands::test_utils::{ - find_input_boxes, generate_token_ids, make_wallet_unspent_box, BallotBoxMock, - WalletDataMock, + find_input_boxes, generate_token_ids, make_wallet_unspent_box, WalletDataMock, }, wallet::WalletDataSource, }; @@ -390,14 +385,12 @@ mod tests { 0, ) .unwrap(); - let ballot_box_mock = BallotBoxMock { - ballot_box: BallotBoxWrapper::new( - in_ballot_box.clone(), - &inputs, - &Address::P2Pk(secret.public_image()), - ) - .unwrap(), - }; + let ballot_box = BallotBoxWrapper::new( + in_ballot_box.clone(), + &inputs, + &Address::P2Pk(secret.public_image()), + ) + .unwrap(); let wallet_unspent_box = make_wallet_unspent_box( secret.public_image(), BASE_FEE.checked_mul_u32(100_000_000).unwrap(), @@ -407,7 +400,7 @@ mod tests { unspent_boxes: vec![wallet_unspent_box], }; let unsigned_tx = build_tx_with_existing_ballot_box( - &ballot_box_mock, + ballot_box, &wallet_mock, new_pool_box_address_hash, token_ids.reward_token_id, diff --git a/core/src/contracts/ballot.rs b/core/src/contracts/ballot.rs index 40571d25..7e58d241 100644 --- a/core/src/contracts/ballot.rs +++ b/core/src/contracts/ballot.rs @@ -107,7 +107,7 @@ impl BallotContract { ergo_tree: ErgoTree, inputs: &BallotContractInputs, ) -> Result { - dbg!(ergo_tree.get_constants().unwrap()); + // dbg!(ergo_tree.get_constants().unwrap()); let parameters = inputs.contract_parameters.clone(); let min_storage_rent = ergo_tree .get_constant(parameters.min_storage_rent_index) diff --git a/core/src/contracts/oracle.rs b/core/src/contracts/oracle.rs index 41f4a7a1..d1812656 100644 --- a/core/src/contracts/oracle.rs +++ b/core/src/contracts/oracle.rs @@ -101,7 +101,7 @@ impl OracleContract { ergo_tree: ErgoTree, inputs: &OracleContractInputs, ) -> Result { - dbg!(ergo_tree.get_constants().unwrap()); + // dbg!(ergo_tree.get_constants().unwrap()); let pool_nft_token_id = ergo_tree .get_constant(inputs.contract_parameters.pool_nft_index) diff --git a/core/src/contracts/pool.rs b/core/src/contracts/pool.rs index b26f7d4a..bd761a7b 100644 --- a/core/src/contracts/pool.rs +++ b/core/src/contracts/pool.rs @@ -9,7 +9,7 @@ use ergo_lib::ergotree_ir::serialization::SigmaParsingError; use ergo_lib::ergotree_ir::serialization::SigmaSerializable; use thiserror::Error; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct PoolContract { ergo_tree: ErgoTree, refresh_nft_index: usize, @@ -113,7 +113,7 @@ impl PoolContract { ergo_tree: ErgoTree, inputs: &PoolContractInputs, ) -> Result { - dbg!(ergo_tree.get_constants().unwrap()); + // dbg!(ergo_tree.get_constants().unwrap()); let refresh_nft_token_id = ergo_tree .get_constant(inputs.contract_parameters.refresh_nft_index) .map_err(|_| { diff --git a/core/src/contracts/refresh.rs b/core/src/contracts/refresh.rs index 990e947c..e1c6db6d 100644 --- a/core/src/contracts/refresh.rs +++ b/core/src/contracts/refresh.rs @@ -62,7 +62,7 @@ impl RefreshContract { ergo_tree: ErgoTree, inputs: &RefreshContractInputs, ) -> Result { - dbg!(ergo_tree.get_constants().unwrap()); + // dbg!(ergo_tree.get_constants().unwrap()); let parameters = inputs.contract_parameters.clone(); let pool_nft_token_id = ergo_tree diff --git a/core/src/contracts/update.rs b/core/src/contracts/update.rs index 1826d15a..2e1ba4cf 100644 --- a/core/src/contracts/update.rs +++ b/core/src/contracts/update.rs @@ -127,7 +127,7 @@ impl UpdateContract { ergo_tree: ErgoTree, inputs: &UpdateContractInputs, ) -> Result { - dbg!(ergo_tree.get_constants().unwrap()); + // dbg!(ergo_tree.get_constants().unwrap()); let pool_nft_token_id = ergo_tree .get_constant(inputs.contract_parameters.pool_nft_index) .map_err(|_| UpdateContractError::NoPoolNftId)? diff --git a/core/src/main.rs b/core/src/main.rs index eed731cf..0a6a6274 100644 --- a/core/src/main.rs +++ b/core/src/main.rs @@ -169,7 +169,6 @@ enum Command { fn main() { let args = Args::parse(); - log::info!("{}", APP_VERSION); let cmdline_log_level = if args.verbose { Some(LevelFilter::Trace) @@ -177,6 +176,7 @@ fn main() { None }; logging::setup_log(cmdline_log_level); + log::info!("{}", APP_VERSION); debug!("Args: {:?}", args); @@ -324,7 +324,10 @@ fn main_loop_iteration(op: &OraclePool, read_only: bool) -> std::result::Result< let wallet = WalletData::new(); let pool_state = match op.get_live_epoch_state() { Ok(live_epoch_state) => PoolState::LiveEpoch(live_epoch_state), - Err(_) => PoolState::NeedsBootstrap, + Err(error) => { + log::debug!("error getting live epoch state: {}", error); + PoolState::NeedsBootstrap + } }; if let Some(cmd) = process(pool_state, height)? { let action = build_action( diff --git a/core/src/node_interface.rs b/core/src/node_interface.rs index bc486a9b..a765e37a 100644 --- a/core/src/node_interface.rs +++ b/core/src/node_interface.rs @@ -88,10 +88,6 @@ pub fn unspent_boxes_with_min_total(total: u64) -> Result> { new_node_interface().unspent_boxes_with_min_total(total) } -pub fn serialized_unspent_boxes_with_min_total(total: u64) -> Result> { - new_node_interface().serialized_unspent_boxes_with_min_total(total) -} - /// Acquires the unspent box with the highest value of Ergs inside /// from the wallet and serializes it pub fn get_serialized_highest_value_unspent_box() -> Result { @@ -100,7 +96,9 @@ pub fn get_serialized_highest_value_unspent_box() -> Result { /// Using the `scan_id` of a registered scan, acquires unspent boxes which have been found by said scan pub fn get_scan_boxes(scan_id: &String) -> Result> { - new_node_interface().scan_boxes(scan_id) + let res = new_node_interface().scan_boxes(scan_id); + debug!("Scan boxes: {:?}", res); + res } pub fn rescan_from_height(height: u32) -> Result<()> { @@ -111,34 +109,6 @@ pub fn rescan_from_height(height: u32) -> Result<()> { Ok(()) } -/// Generates (and sends) a tx using the node endpoints. -/// Input must be a json formatted request with rawInputs (and rawDataInputs) -/// manually selected or will be automatically selected by wallet. -/// Returns the resulting `TxId`. -// pub fn send_transaction(tx_request_json: &JsonValue) -> Result { -// new_node_interface().generate_and_submit_transaction(&tx_request_json.dump()) -// } - -/// Given a `Vec` return the given boxes (which must be part of the UTXO-set) as -/// a vec of serialized strings in Base16 encoding -pub fn serialize_boxes(b: &Vec) -> Result> { - Ok(b.iter() - .map(|b| serialized_box_from_id(&b.box_id().into()).unwrap_or_else(|_| "".to_string())) - .collect()) -} - -/// Given an `ErgoBox` return the given box (which must be part of the UTXO-set) as -/// a serialized string in Base16 encoding -pub fn serialize_box(b: &ErgoBox) -> Result { - serialized_box_from_id(&b.box_id().into()) -} - -/// Given a box id return the given box (which must be part of the UTXO-set) as -/// a serialized string in Base16 encoding -pub fn serialized_box_from_id(box_id: &String) -> Result { - new_node_interface().serialized_box_from_id(box_id) -} - /// Get the current block height of the chain pub fn current_block_height() -> Result { new_node_interface().current_block_height() @@ -160,7 +130,11 @@ pub fn submit_transaction(signed_tx: &Transaction) -> Result { /// Sign an `UnsignedTransaction` and then submit it to the mempool. pub fn sign_and_submit_transaction(unsigned_tx: &UnsignedTransaction) -> Result { - new_node_interface().sign_and_submit_transaction(unsigned_tx) + let node = new_node_interface(); + log::debug!("Signing transaction: {:?}", unsigned_tx); + let signed_tx = node.sign_transaction(unsigned_tx, None, None)?; + log::debug!("Submitting signed transaction: {:?}", signed_tx); + node.submit_transaction(&signed_tx) } pub fn assert_wallet_unlocked(node: &NodeInterface) { diff --git a/core/src/oracle_config.rs b/core/src/oracle_config.rs index 16e29109..ae937e58 100644 --- a/core/src/oracle_config.rs +++ b/core/src/oracle_config.rs @@ -220,21 +220,14 @@ pub fn get_node_api_key() -> String { #[cfg(test)] mod tests { - use sigma_test_util::force_any_val; + + use crate::pool_commands::test_utils::generate_token_ids; use super::*; #[test] fn token_ids_roundtrip() { - let token_ids = TokenIds { - pool_nft_token_id: force_any_val::(), - refresh_nft_token_id: force_any_val::(), - update_nft_token_id: force_any_val::(), - oracle_token_id: force_any_val::(), - reward_token_id: force_any_val::(), - ballot_token_id: force_any_val::(), - }; - + let token_ids = generate_token_ids(); let s = serde_yaml::to_string(&token_ids).unwrap(); assert_eq!(token_ids, serde_yaml::from_str::(&s).unwrap()); } diff --git a/core/src/oracle_state.rs b/core/src/oracle_state.rs index 3a9e6f10..00fd0909 100644 --- a/core/src/oracle_state.rs +++ b/core/src/oracle_state.rs @@ -16,7 +16,7 @@ use crate::scans::{ register_update_box_scan, save_scan_ids_locally, Scan, ScanError, }; use crate::state::PoolState; -use crate::{BlockHeight, EpochID, NanoErg}; +use crate::{BlockHeight, NanoErg}; use anyhow::Error; use derive_more::From; @@ -41,16 +41,22 @@ pub enum StageError { ScanError(ScanError), #[error("pool box error: {0}")] PoolBoxError(PoolBoxError), + #[error("pool box not found")] + PoolBoxNotFoundError, #[error("ballot box error: {0}")] BallotBoxError(BallotBoxError), #[error("refresh box error: {0}")] RefreshBoxError(RefreshBoxError), + #[error("refresh box not found")] + RefreshBoxNotFoundError, #[error("oracle box error: {0}")] OracleBoxError(OracleBoxError), #[error("datapoint source error: {0}")] DataPointSource(DataPointSourceError), #[error("update box error: {0}")] UpdateBoxError(UpdateBoxError), + #[error("update box not found")] + UpdateBoxNotFoundError, } pub trait StageDataSource { @@ -58,15 +64,7 @@ pub trait StageDataSource { fn get_boxes(&self) -> Result>; /// Returns the first box found by the registered scan for a given `Stage` - fn get_box(&self) -> Result; - - /// Returns all boxes held at the given stage based on the registered scan - /// serialized and ready to be used as rawInputs - fn get_serialized_boxes(&self) -> Result>; - - /// Returns the first box found by the registered scan for a given `Stage` - /// serialized and ready to be used as a rawInput - fn get_serialized_box(&self) -> Result; + fn get_box(&self) -> Result>; /// Returns the number of boxes held at the given stage based on the registered scan fn number_of_boxes(&self) -> Result; @@ -77,7 +75,7 @@ pub trait PoolBoxSource { } pub trait LocalBallotBoxSource { - fn get_ballot_box(&self) -> Result; + fn get_ballot_box(&self) -> Result>; } pub trait RefreshBoxSource { @@ -89,7 +87,7 @@ pub trait DatapointBoxesSource { } pub trait LocalDatapointBoxSource { - fn get_local_oracle_datapoint_box(&self) -> Result; + fn get_local_oracle_datapoint_box(&self) -> Result>; } pub trait VoteBallotBoxesSource { @@ -113,8 +111,8 @@ pub struct OraclePool<'a> { pub data_point_source: Box, /// Stages pub datapoint_stage: DatapointStage<'a>, - local_oracle_datapoint_scan: Option>, - local_ballot_box_scan: Option>, + local_oracle_datapoint_scan: LocalOracleDatapointScan<'a>, + local_ballot_box_scan: LocalBallotBoxScan<'a>, pool_box_scan: PoolBoxScan<'a>, refresh_box_scan: RefreshBoxScan<'a>, ballot_boxes_scan: BallotBoxesScan<'a>, @@ -180,16 +178,6 @@ pub struct PreparationState { pub latest_pool_datapoint: u64, } -/// The state of the local oracle's Datapoint box -#[derive(Debug, Clone)] -pub struct DatapointState { - pub datapoint: u64, - /// epoch counter of the epoch which the datapoint was posted in/originates from - pub origin_epoch_id: EpochID, - /// Height that the datapoint was declared as being created - pub creation_height: BlockHeight, -} - /// The current UTXO-set state of all of the Pool Deposit boxes #[derive(Debug, Clone)] pub struct PoolDepositsState { @@ -206,7 +194,7 @@ impl<'a> OraclePool<'a> { let refresh_box_scan_name = "Refresh Box Scan"; - let datapoint_contract_address = + let datapoint_contract = OracleContract::checked_load(&config.oracle_box_wrapper_inputs.contract_inputs)? .ergo_tree(); @@ -222,26 +210,20 @@ impl<'a> OraclePool<'a> { &scan_json["All Datapoints Scan"].to_string(), ); let local_scan_str = "Local Oracle Datapoint Scan"; - let mut local_oracle_datapoint_scan = None; - if scan_json.has_key(local_scan_str) { - local_oracle_datapoint_scan = Some(LocalOracleDatapointScan { - scan: Scan::new( - "Local Oracle Datapoint Scan", - &scan_json[local_scan_str].to_string(), - ), - oracle_box_wrapper_inputs: &config.oracle_box_wrapper_inputs, - }); + let local_oracle_datapoint_scan = LocalOracleDatapointScan { + scan: Scan::new( + "Local Oracle Datapoint Scan", + &scan_json[local_scan_str].to_string(), + ), + oracle_box_wrapper_inputs: &config.oracle_box_wrapper_inputs, }; let local_scan_str = "Local Ballot Box Scan"; - let mut local_ballot_box_scan = None; - if scan_json.has_key(local_scan_str) { - local_ballot_box_scan = Some(LocalBallotBoxScan { - scan: Scan::new(local_scan_str, &scan_json[local_scan_str].to_string()), - ballot_box_wrapper_inputs: &config.ballot_box_wrapper_inputs, - ballot_token_owner_address: config.oracle_address.address(), - }); - } + let local_ballot_box_scan = LocalBallotBoxScan { + scan: Scan::new(local_scan_str, &scan_json[local_scan_str].to_string()), + ballot_box_wrapper_inputs: &config.ballot_box_wrapper_inputs, + ballot_token_owner_address: config.oracle_address.address(), + }; let ballot_boxes_scan = BallotBoxesScan { scan: Scan::new("Ballot Box Scan", &scan_json["Ballot Box Scan"].to_string()), @@ -266,12 +248,14 @@ impl<'a> OraclePool<'a> { update_box_wrapper_inputs: &config.update_box_wrapper_inputs, }; + log::debug!("Scans loaded"); + // Create `OraclePool` struct Ok(OraclePool { data_point_source, datapoint_stage: DatapointStage { stage: Stage { - contract_address: datapoint_contract_address.to_base16_bytes().unwrap(), + contract_address: datapoint_contract.to_base16_bytes().unwrap(), scan: datapoint_scan, }, oracle_box_wrapper_inputs: &config.oracle_box_wrapper_inputs, @@ -297,11 +281,13 @@ impl<'a> OraclePool<'a> { pub fn get_live_epoch_state(&self) -> Result { let pool_box = self.get_pool_box_source().get_pool_box()?; let epoch_id: u32 = pool_box.epoch_counter(); - // let epoch_box_id: String = epoch_box.box_id().into(); // Whether datapoint was commit in the current Live Epoch - let commit_datapoint_in_epoch = if let Some(datapoint_state) = self.get_datapoint_state()? { - epoch_id == datapoint_state.origin_epoch_id + let commit_datapoint_in_epoch = if let Some(local_data_point_box) = self + .get_local_datapoint_box_source() + .get_local_oracle_datapoint_box()? + { + epoch_id == local_data_point_box.epoch_counter() } else { false }; @@ -326,72 +312,12 @@ impl<'a> OraclePool<'a> { Ok(epoch_state) } - // /// Get the state of the current epoch preparation box - // pub fn get_preparation_state(&self) -> Result { - // let epoch_prep_box = self.epoch_preparation_stage.get_box()?; - // let epoch_prep_box_regs = epoch_prep_box.additional_registers.get_ordered_values(); - - // // Latest pool datapoint is held in R4 - // let latest_pool_datapoint = unwrap_long(&epoch_prep_box_regs[0])?; - - // // Next epoch ends height held in R5 - // let next_epoch_ends = unwrap_int(&epoch_prep_box_regs[1])?; - - // let prep_state = PreparationState { - // funds: *epoch_prep_box.value.as_u64(), - // next_epoch_ends: next_epoch_ends as u64, - // latest_pool_datapoint: latest_pool_datapoint as u64, - // }; - - // Ok(prep_state) - // } - - /// Get the current state of the local oracle's datapoint - pub fn get_datapoint_state(&self) -> Result> { - if let Some(local_box) = &self.local_oracle_datapoint_scan { - let datapoint_box = local_box.get_local_oracle_datapoint_box()?; - - let origin_epoch_id = datapoint_box.epoch_counter(); - - let datapoint = datapoint_box.rate(); - - let datapoint_state = DatapointState { - datapoint, - origin_epoch_id, - creation_height: datapoint_box.get_box().creation_height as u64, - }; - - Ok(Some(datapoint_state)) - } else { - Ok(None) - } - } - - /// Get the current state of all of the pool deposit boxes - // pub fn get_pool_deposits_state(&self) -> Result { - // let deposits_box_list = self.pool_deposit_stage.get_boxes()?; - - // // Sum up all Ergs held in pool deposit boxes - // let sum_ergs = deposits_box_list - // .iter() - // .fold(0, |acc, b| acc + *b.value.as_u64()); - - // let deposits_state = PoolDepositsState { - // number_of_boxes: deposits_box_list.len() as u64, - // total_nanoergs: sum_ergs, - // }; - - // Ok(deposits_state) - // } - pub fn get_pool_box_source(&self) -> &dyn PoolBoxSource { &self.pool_box_scan as &dyn PoolBoxSource } - pub fn get_local_ballot_box_source(&self) -> Option<&dyn LocalBallotBoxSource> { - self.local_ballot_box_scan - .as_ref() - .map(|s| s as &dyn LocalBallotBoxSource) + pub fn get_local_ballot_box_source(&self) -> &dyn LocalBallotBoxSource { + &self.local_ballot_box_scan as &dyn LocalBallotBoxSource } pub fn get_ballot_boxes_source(&self) -> &dyn VoteBallotBoxesSource { @@ -406,10 +332,8 @@ impl<'a> OraclePool<'a> { &self.datapoint_stage as &dyn DatapointBoxesSource } - pub fn get_local_datapoint_box_source(&self) -> Option<&dyn LocalDatapointBoxSource> { - self.local_oracle_datapoint_scan - .as_ref() - .map(|s| s as &dyn LocalDatapointBoxSource) + pub fn get_local_datapoint_box_source(&self) -> &dyn LocalDatapointBoxSource { + &self.local_oracle_datapoint_scan as &dyn LocalDatapointBoxSource } pub fn get_update_box_source(&self) -> &dyn UpdateBoxSource { @@ -419,37 +343,50 @@ impl<'a> OraclePool<'a> { impl<'a> PoolBoxSource for PoolBoxScan<'a> { fn get_pool_box(&self) -> Result { - let box_wrapper = PoolBoxWrapper::new(self.scan.get_box()?, self.pool_box_wrapper_inputs)?; + let box_wrapper = PoolBoxWrapper::new( + self.scan + .get_box()? + .ok_or(StageError::PoolBoxNotFoundError)?, + self.pool_box_wrapper_inputs, + )?; Ok(box_wrapper) } } impl<'a> LocalBallotBoxSource for LocalBallotBoxScan<'a> { - fn get_ballot_box(&self) -> Result { - let box_wrapper = BallotBoxWrapper::new( - self.scan.get_box()?, - self.ballot_box_wrapper_inputs, - &self.ballot_token_owner_address, - )?; - Ok(box_wrapper) + fn get_ballot_box(&self) -> Result> { + self.scan + .get_box()? + .map(|b| { + BallotBoxWrapper::new( + b, + self.ballot_box_wrapper_inputs, + &self.ballot_token_owner_address, + ) + .map_err(Into::into) + }) + .transpose() } } impl<'a> RefreshBoxSource for RefreshBoxScan<'a> { fn get_refresh_box(&self) -> Result { let box_wrapper = RefreshBoxWrapper::new( - self.scan.get_box()?, - self.refresh_box_wrapper_inputs.clone(), + self.scan + .get_box()? + .ok_or(StageError::RefreshBoxNotFoundError)?, + self.refresh_box_wrapper_inputs, )?; Ok(box_wrapper) } } impl<'a> LocalDatapointBoxSource for LocalOracleDatapointScan<'a> { - fn get_local_oracle_datapoint_box(&self) -> Result { - let box_wrapper = - OracleBoxWrapper::new(self.scan.get_box()?, self.oracle_box_wrapper_inputs)?; - Ok(box_wrapper) + fn get_local_oracle_datapoint_box(&self) -> Result> { + self.scan + .get_box()? + .map(|b| OracleBoxWrapper::new(b, self.oracle_box_wrapper_inputs).map_err(Into::into)) + .transpose() } } @@ -472,8 +409,12 @@ impl<'a> VoteBallotBoxesSource for BallotBoxesScan<'a> { impl<'a> UpdateBoxSource for UpdateBoxScan<'a> { fn get_update_box(&self) -> Result { - let box_wrapper = - UpdateBoxWrapper::new(self.scan.get_box()?, self.update_box_wrapper_inputs)?; + let box_wrapper = UpdateBoxWrapper::new( + self.scan + .get_box()? + .ok_or(StageError::UpdateBoxNotFoundError)?, + self.update_box_wrapper_inputs, + )?; Ok(box_wrapper) } } @@ -485,22 +426,10 @@ impl StageDataSource for Stage { } /// Returns the first box found by the registered scan for a given `Stage` - fn get_box(&self) -> Result { + fn get_box(&self) -> Result> { self.scan.get_box().map_err(Into::into) } - /// Returns all boxes held at the given stage based on the registered scan - /// serialized and ready to be used as rawInputs - fn get_serialized_boxes(&self) -> Result> { - self.scan.get_serialized_boxes().map_err(Into::into) - } - - /// Returns the first box found by the registered scan for a given `Stage` - /// serialized and ready to be used as a rawInput - fn get_serialized_box(&self) -> Result { - self.scan.get_serialized_box().map_err(Into::into) - } - /// Returns the number of boxes held at the given stage based on the registered scan fn number_of_boxes(&self) -> Result { Ok(self.get_boxes()?.len() as u64) @@ -622,20 +551,9 @@ fn register_and_save_scans_inner() -> std::result::Result<(), Error> { .unwrap(), ); - let res = save_scan_ids_locally(scans); + log::info!("Registering UTXO-Set Scans"); + save_scan_ids_locally(scans)?; + log::info!("Triggering wallet rescan"); rescan_from_height(ORACLE_CONFIG.rescan_height)?; - if res.is_ok() { - // Congrats scans registered screen here - print!("\x1B[2J\x1B[1;1H"); - println!("===================================================================="); - println!("UTXO-Set Scans Have Been Successfully Registered With The Ergo Node"); - println!("===================================================================="); - println!("Press Enter To Continue..."); - let mut line = String::new(); - std::io::stdin().read_line(&mut line).ok(); - } else if let Err(e) = res { - // Failed, post error - panic!("{:?}", e); - } Ok(()) } diff --git a/core/src/pool_commands.rs b/core/src/pool_commands.rs index b2493f05..2318c050 100644 --- a/core/src/pool_commands.rs +++ b/core/src/pool_commands.rs @@ -5,9 +5,9 @@ use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog; use thiserror::Error; use crate::actions::PoolAction; -use crate::box_kind::OracleBoxWrapperInputs; +use crate::box_kind::{OracleBoxWrapper, OracleBoxWrapperInputs}; use crate::oracle_config::ORACLE_CONFIG; -use crate::oracle_state::{LocalDatapointBoxSource, OraclePool, StageError}; +use crate::oracle_state::{OraclePool, StageError}; use crate::wallet::WalletDataSource; use self::publish_datapoint::build_publish_datapoint_action; @@ -53,6 +53,13 @@ pub fn build_action( let pool_box_source = op.get_pool_box_source(); let refresh_box_source = op.get_refresh_box_source(); let datapoint_stage_src = op.get_datapoint_boxes_source(); + let oracle_public_key = + if let Address::P2Pk(public_key) = ORACLE_CONFIG.oracle_address.address() { + public_key + } else { + return Err(PoolCommandError::WrongOracleAddressType); + }; + match cmd { PoolCommand::Refresh => build_refresh_action( pool_box_source, @@ -71,21 +78,21 @@ pub fn build_action( wallet, height, change_address, + oracle_public_key.h.as_ref(), ) .map_err(Into::into) .map(Into::into), PoolCommand::PublishDataPoint => { - let inputs = if let Some(local_datapoint_box_source) = - op.get_local_datapoint_box_source() + let inputs = if let Some(local_datapoint_box) = op + .get_local_datapoint_box_source() + .get_local_oracle_datapoint_box()? { - PublishDataPointCommandInputs::LocalDataPointBoxExists(local_datapoint_box_source) - } else if let Address::P2Pk(public_key) = ORACLE_CONFIG.oracle_address.address() { + PublishDataPointCommandInputs::LocalDataPointBoxExists(local_datapoint_box.into()) + } else { PublishDataPointCommandInputs::FirstDataPoint { - public_key, + public_key: oracle_public_key.clone(), oracle_box_wrapper_inputs: ORACLE_CONFIG.oracle_box_wrapper_inputs.clone(), } - } else { - return Err(PoolCommandError::WrongOracleAddressType); }; build_publish_datapoint_action( pool_box_source, @@ -101,10 +108,9 @@ pub fn build_action( } } -pub enum PublishDataPointCommandInputs<'a> { - /// Local datapoint box already exists so pass in the associated `LocalDatapoinBoxSource` - /// instance - LocalDataPointBoxExists(&'a dyn LocalDatapointBoxSource), +pub enum PublishDataPointCommandInputs { + /// Local datapoint box already exists + LocalDataPointBoxExists(Box), /// The first datapoint will be submitted, so there doesn't exist a local datapoint box now. FirstDataPoint { oracle_box_wrapper_inputs: OracleBoxWrapperInputs, diff --git a/core/src/pool_commands/publish_datapoint.rs b/core/src/pool_commands/publish_datapoint.rs index a7bcc324..145b5e7b 100644 --- a/core/src/pool_commands/publish_datapoint.rs +++ b/core/src/pool_commands/publish_datapoint.rs @@ -7,7 +7,6 @@ use ergo_lib::{ ergotree_ir::{ chain::{ address::Address, - ergo_box::box_value::BoxValue, token::{Token, TokenAmount}, }, sigma_protocol::sigma_boolean::ProveDlog, @@ -22,11 +21,13 @@ use thiserror::Error; use crate::{ actions::PublishDataPointAction, - box_kind::{make_oracle_box_candidate, OracleBox, OracleBoxWrapperInputs, PoolBox}, + box_kind::{ + make_oracle_box_candidate, OracleBox, OracleBoxWrapper, OracleBoxWrapperInputs, PoolBox, + }, contracts::oracle::{OracleContract, OracleContractError}, datapoint_source::{DataPointSource, DataPointSourceError}, oracle_config::BASE_FEE, - oracle_state::{LocalDatapointBoxSource, PoolBoxSource, StageError}, + oracle_state::{PoolBoxSource, StageError}, wallet::WalletDataSource, }; @@ -63,9 +64,9 @@ pub fn build_publish_datapoint_action( let new_datapoint = datapoint_source.get_datapoint()?; let epoch_counter = pool_box_source.get_pool_box()?.epoch_counter(); match inputs { - PublishDataPointCommandInputs::LocalDataPointBoxExists(local_datapoint_box_source) => { + PublishDataPointCommandInputs::LocalDataPointBoxExists(local_datapoint_box) => { build_subsequent_publish_datapoint_action( - local_datapoint_box_source, + *local_datapoint_box, wallet, epoch_counter, height, @@ -88,14 +89,14 @@ pub fn build_publish_datapoint_action( } pub fn build_subsequent_publish_datapoint_action( - local_datapoint_box_source: &dyn LocalDatapointBoxSource, + local_datapoint_box: OracleBoxWrapper, wallet: &dyn WalletDataSource, current_epoch_counter: u32, height: u32, change_address: Address, new_datapoint: i64, ) -> Result { - let in_oracle_box = local_datapoint_box_source.get_local_oracle_datapoint_box()?; + let in_oracle_box = local_datapoint_box; if *in_oracle_box.reward_token().amount.as_u64() == 0 { return Err(PublishDatapointActionError::NoRewardTokenInOracleBox); } @@ -128,7 +129,6 @@ pub fn build_subsequent_publish_datapoint_action( height, tx_fee, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the oracle contract is properly set. @@ -189,7 +189,6 @@ pub fn build_publish_first_datapoint_action( height, tx_fee, change_address, - BoxValue::MIN, ); // The following context value ensures that `outIndex` in the oracle contract is properly set. @@ -242,7 +241,7 @@ mod tests { use crate::contracts::pool::PoolContractParameters; use crate::pool_commands::test_utils::{ find_input_boxes, generate_token_ids, make_datapoint_box, make_pool_box, - make_wallet_unspent_box, OracleBoxMock, PoolBoxMock, WalletDataMock, + make_wallet_unspent_box, PoolBoxMock, WalletDataMock, }; use ergo_lib::chain::ergo_state_context::ErgoStateContext; use ergo_lib::chain::transaction::TxId; @@ -305,7 +304,6 @@ mod tests { &oracle_box_wrapper_inputs, ) .unwrap(); - let local_datapoint_box_source = OracleBoxMock { oracle_box }; let change_address = AddressEncoder::new(ergo_lib::ergotree_ir::chain::address::NetworkPrefix::Mainnet) @@ -324,9 +322,7 @@ mod tests { let datapoint_source = MockDatapointSource {}; let action = build_publish_datapoint_action( &pool_box_mock, - PublishDataPointCommandInputs::LocalDataPointBoxExists( - &local_datapoint_box_source as &dyn LocalDatapointBoxSource, - ), + PublishDataPointCommandInputs::LocalDataPointBoxExists(oracle_box.clone().into()), &wallet_mock, &datapoint_source, height, @@ -336,11 +332,7 @@ mod tests { let mut possible_input_boxes = vec![ pool_box_mock.get_pool_box().unwrap().get_box().clone(), - local_datapoint_box_source - .get_local_oracle_datapoint_box() - .unwrap() - .get_box() - .clone(), + oracle_box.get_box().clone(), ]; possible_input_boxes.append(&mut wallet_mock.get_unspent_wallet_boxes().unwrap()); diff --git a/core/src/pool_commands/refresh.rs b/core/src/pool_commands/refresh.rs index 7c7b139f..400af659 100644 --- a/core/src/pool_commands/refresh.rs +++ b/core/src/pool_commands/refresh.rs @@ -17,11 +17,12 @@ use crate::wallet::WalletDataSource; use derive_more::From; use ergo_lib::chain::ergo_box::box_builder::ErgoBoxCandidateBuilderError; +use ergo_lib::ergo_chain_types::EcPoint; use ergo_lib::ergotree_interpreter::sigma_protocol::prover::ContextExtension; use ergo_lib::ergotree_ir::chain::address::Address; -use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValue; use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBoxCandidate; use ergo_lib::ergotree_ir::chain::token::Token; +use ergo_lib::ergotree_ir::chain::token::TokenAmount; use ergo_lib::wallet::box_selector::BoxSelection; use ergo_lib::wallet::box_selector::BoxSelector; use ergo_lib::wallet::box_selector::BoxSelectorError; @@ -61,6 +62,7 @@ pub fn build_refresh_action( wallet: &dyn WalletDataSource, height: u32, change_address: Address, + my_oracle_pk: &EcPoint, ) -> Result { let tx_fee = *BASE_FEE; @@ -87,7 +89,8 @@ pub fn build_refresh_action( let reward_decrement = valid_in_oracle_boxes.len() as u64 * 2; let out_pool_box = build_out_pool_box(&in_pool_box, height, rate, reward_decrement)?; let out_refresh_box = build_out_refresh_box(&in_refresh_box, height)?; - let mut out_oracle_boxes = build_out_oracle_boxes(&valid_in_oracle_boxes, height)?; + let mut out_oracle_boxes = + build_out_oracle_boxes(&valid_in_oracle_boxes, height, my_oracle_pk)?; let unspent_boxes = wallet.get_unspent_wallet_boxes()?; let box_selector = SimpleBoxSelector::new(); @@ -118,7 +121,6 @@ pub fn build_refresh_action( height as u32, tx_fee, change_address, - BoxValue::MIN, ); let in_refresh_box_ctx_ext = ContextExtension { values: vec![(0, 0i32.into())].into_iter().collect(), @@ -148,7 +150,7 @@ fn filtered_oracle_boxes( // Removing largest deviation outlier successful_boxes = remove_largest_local_deviation_datapoint(successful_boxes)?; } - dbg!(&successful_boxes); + // dbg!(&successful_boxes); Ok(successful_boxes) } @@ -240,15 +242,23 @@ fn build_out_refresh_box( fn build_out_oracle_boxes( valid_oracle_boxes: &Vec, creation_height: u32, + my_public_key: &EcPoint, ) -> Result, RefrechActionError> { valid_oracle_boxes .iter() .map(|in_ob| { let mut reward_token_new = in_ob.reward_token(); - reward_token_new.amount = reward_token_new - .amount - .checked_add(&1u64.try_into().unwrap()) - .unwrap(); + reward_token_new.amount = if in_ob.public_key().h.as_ref() == my_public_key { + let increment: TokenAmount = + // additional 1 reward token per collected oracle box goes to the collector + (1 + valid_oracle_boxes.len() as u64).try_into().unwrap(); + reward_token_new.amount.checked_add(&increment).unwrap() + } else { + reward_token_new + .amount + .checked_add(&1u64.try_into().unwrap()) + .unwrap() + }; make_collected_oracle_box_candidate( in_ob.contract(), in_ob.public_key(), @@ -276,7 +286,6 @@ mod tests { use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox; use ergo_lib::ergotree_ir::chain::ergo_box::NonMandatoryRegisters; use ergo_lib::ergotree_ir::chain::token::Token; - use ergo_lib::ergotree_ir::chain::token::TokenId; use ergo_lib::wallet::signing::TransactionContext; use ergo_lib::wallet::Wallet; use sigma_test_util::force_any_val; @@ -327,7 +336,7 @@ mod tests { fn make_refresh_box( value: BoxValue, - inputs: RefreshBoxWrapperInputs, + inputs: &RefreshBoxWrapperInputs, creation_height: u32, ) -> RefreshBoxWrapper { let tokens = vec![Token::from(( @@ -391,12 +400,11 @@ mod tests { fn test_refresh_pool() { let ctx = force_any_val::(); let height = ctx.pre_header.height; - let reward_token_id = force_any_val::(); - dbg!(&reward_token_id); let pool_contract_parameters = PoolContractParameters::default(); let oracle_contract_parameters = OracleContractParameters::default(); let refresh_contract_parameters = RefreshContractParameters::default(); let token_ids = generate_token_ids(); + dbg!(&token_ids); let refresh_contract_inputs = RefreshContractInputs::build_with( refresh_contract_parameters, @@ -409,7 +417,7 @@ mod tests { refresh_nft_token_id: token_ids.refresh_nft_token_id.clone(), contract_inputs: refresh_contract_inputs, }; - let in_refresh_box = make_refresh_box(*BASE_FEE, inputs, height - 32); + let in_refresh_box = make_refresh_box(*BASE_FEE, &inputs, height - 32); let in_pool_box = make_pool_box( 200, 1, @@ -423,7 +431,7 @@ mod tests { let oracle_pub_key = secret.public_image().h; let oracle_pub_keys = vec![ - *oracle_pub_key, + *oracle_pub_key.clone(), force_any_val::(), force_any_val::(), force_any_val::(), @@ -473,6 +481,7 @@ mod tests { &wallet_mock, height, change_address, + &oracle_pub_key, ) .unwrap(); diff --git a/core/src/pool_commands/test_utils.rs b/core/src/pool_commands/test_utils.rs index 4cfee1f6..34c9faf7 100644 --- a/core/src/pool_commands/test_utils.rs +++ b/core/src/pool_commands/test_utils.rs @@ -6,6 +6,7 @@ use ergo_lib::chain::ergo_state_context::ErgoStateContext; use ergo_lib::chain::transaction::unsigned::UnsignedTransaction; use ergo_lib::chain::transaction::TxId; use ergo_lib::chain::transaction::TxIoVec; +use ergo_lib::ergo_chain_types::Digest32; use ergo_lib::ergo_chain_types::EcPoint; use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValue; use ergo_lib::ergotree_ir::chain::ergo_box::BoxTokens; @@ -13,7 +14,6 @@ use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox; use ergo_lib::ergotree_ir::chain::ergo_box::NonMandatoryRegisterId; use ergo_lib::ergotree_ir::chain::ergo_box::NonMandatoryRegisters; use ergo_lib::ergotree_ir::chain::token::Token; -use ergo_lib::ergotree_ir::chain::token::TokenId; use ergo_lib::ergotree_ir::ergo_tree::ErgoTree; use ergo_lib::ergotree_ir::mir::constant::Constant; use ergo_lib::ergotree_ir::mir::expr::Expr; @@ -62,8 +62,10 @@ pub(crate) struct OracleBoxMock { } impl LocalDatapointBoxSource for OracleBoxMock { - fn get_local_oracle_datapoint_box(&self) -> std::result::Result { - Ok(self.oracle_box.clone()) + fn get_local_oracle_datapoint_box( + &self, + ) -> std::result::Result, StageError> { + Ok(Some(self.oracle_box.clone())) } } @@ -73,8 +75,8 @@ pub(crate) struct BallotBoxMock { } impl LocalBallotBoxSource for BallotBoxMock { - fn get_ballot_box(&self) -> std::result::Result { - Ok(self.ballot_box.clone()) + fn get_ballot_box(&self) -> std::result::Result, StageError> { + Ok(Some(self.ballot_box.clone())) } } @@ -281,12 +283,12 @@ pub fn init_log_tests() { pub fn generate_token_ids() -> TokenIds { TokenIds { - pool_nft_token_id: force_any_val::(), - refresh_nft_token_id: force_any_val::(), - update_nft_token_id: force_any_val::(), - oracle_token_id: force_any_val::(), - reward_token_id: force_any_val::(), - ballot_token_id: force_any_val::(), + pool_nft_token_id: force_any_val::().into(), + refresh_nft_token_id: force_any_val::().into(), + update_nft_token_id: force_any_val::().into(), + oracle_token_id: force_any_val::().into(), + reward_token_id: force_any_val::().into(), + ballot_token_id: force_any_val::().into(), } } diff --git a/core/src/scans.rs b/core/src/scans.rs index ef207f37..a8d3b82a 100644 --- a/core/src/scans.rs +++ b/core/src/scans.rs @@ -3,7 +3,7 @@ use crate::box_kind::{PoolBoxWrapperInputs, RefreshBoxWrapperInputs}; use crate::contracts::pool::{PoolContract, PoolContractError}; use crate::contracts::refresh::{RefreshContract, RefreshContractError}; /// This file holds logic related to UTXO-set scans -use crate::node_interface::{get_scan_boxes, register_scan, serialize_box, serialize_boxes}; +use crate::node_interface::{get_scan_boxes, register_scan}; use derive_more::From; use ergo_lib::ergotree_ir::chain::address::NetworkAddress; @@ -81,30 +81,13 @@ impl Scan { } /// Returns the first box found by the scan - pub fn get_box(&self) -> Result { - self.get_boxes()? - .into_iter() - .next() - .ok_or(ScanError::NoBoxesFound) - } - - /// Returns all boxes found by the scan - /// serialized and ready to be used as rawInputs - pub fn get_serialized_boxes(&self) -> Result> { - let boxes = serialize_boxes(&self.get_boxes()?)?; - Ok(boxes) - } - - /// Returns the first box found by the registered scan - /// serialized and ready to be used as a rawInput - pub fn get_serialized_box(&self) -> Result { - let ser_box = serialize_box(&self.get_box()?)?; - Ok(ser_box) + pub fn get_box(&self) -> Result> { + Ok(self.get_boxes()?.first().cloned()) } } /// Saves UTXO-set scans (specifically id) to scanIDs.json -pub fn save_scan_ids_locally(scans: Vec) -> Result { +pub fn save_scan_ids_locally(scans: Vec) -> Result<()> { let mut id_json = json!({}); for scan in scans { if &scan.id == "null" { @@ -116,7 +99,7 @@ pub fn save_scan_ids_locally(scans: Vec) -> Result { "scanIDs.json", serde_json::to_string_pretty(&id_json).unwrap(), )?; - Ok(true) + Ok(()) } /// This function registers scanning for the pool box diff --git a/core/src/state.rs b/core/src/state.rs index d7072542..8dbaf405 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -2,7 +2,6 @@ use crate::actions::CollectionError; use crate::datapoint_source::DataPointSource; -use crate::oracle_state::DatapointState; use crate::oracle_state::LiveEpochState; use crate::oracle_state::OraclePool; use crate::oracle_state::PreparationState; @@ -24,13 +23,20 @@ pub enum PoolState { pub fn process(pool_state: PoolState, height: u64) -> Result, StageError> { match pool_state { - PoolState::NeedsBootstrap => Ok(None), + PoolState::NeedsBootstrap => { + log::warn!( + "No oracle pool found, needs bootstrap or wait for bootstrap txs to be on-chain" + ); + Ok(None) + } PoolState::LiveEpoch(live_epoch) => { let epoch_is_over = height >= live_epoch.epoch_ends && live_epoch.commit_datapoint_in_epoch; if epoch_is_over { + log::info!("Epoch is over, calling refresh"); Ok(Some(PoolCommand::Refresh)) } else if !live_epoch.commit_datapoint_in_epoch { + log::info!("Commiting datapoint..."); Ok(Some(PoolCommand::PublishDataPoint)) } else { Ok(None) diff --git a/ergo-chain-sim/Cargo.toml b/ergo-chain-sim/Cargo.toml index fff34203..7484f508 100644 --- a/ergo-chain-sim/Cargo.toml +++ b/ergo-chain-sim/Cargo.toml @@ -10,7 +10,7 @@ description = "Simulator of the Ergo blockchain" crate-type = ["cdylib", "rlib"] [dependencies] -ergo-lib = { version = "0.17.0" } +ergo-lib = { version = "0.20.0" } [dev-dependencies]