From d073f50baa7e6ecf8cf16733ce80b13efea6553c Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Wed, 17 Nov 2021 12:04:04 +0200 Subject: [PATCH 1/6] docs: rfc 0250_Covenants (#3574) Description --- Adds RFC for covenants on Tari [Rendered](https://demo.hedgedoc.org/s/Vwn0ZtWsS) Motivation and Context --- Allows sidechain checkpointing transactions and many other use-cases. --- RFC/src/BaseLayerExtensions.md | 4 +- RFC/src/RFC-0250_Covenants.md | 468 +++++++++++++++++++++++++++++++++ RFC/src/SUMMARY.md | 1 + 3 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 RFC/src/RFC-0250_Covenants.md diff --git a/RFC/src/BaseLayerExtensions.md b/RFC/src/BaseLayerExtensions.md index 32d4c415af..d799f1dca4 100644 --- a/RFC/src/BaseLayerExtensions.md +++ b/RFC/src/BaseLayerExtensions.md @@ -5,5 +5,7 @@ Tari Base layer token and Digital Asset network. * [RFC-0220: Asset Checkpoints](RFC-0220_AssetCheckpoints.md) * [RFC-0230: Time related transactions](RFC-0230_HTLC.md) +* [RFC-0201: TariScript](RFC-0201_TariScript.md) +* [RFC-0250: Covenants](RFC-0250_Covenants.md) * [RFC-0322: Validator Node Registration](RFC-0322_VNRegistration.md) -* [RFC-0322: Asset Registration](RFC-0341_AssetRegistration.md) +* [RFC-0341: Asset Registration](RFC-0341_AssetRegistration.md) diff --git a/RFC/src/RFC-0250_Covenants.md b/RFC/src/RFC-0250_Covenants.md new file mode 100644 index 0000000000..d2e90367db --- /dev/null +++ b/RFC/src/RFC-0250_Covenants.md @@ -0,0 +1,468 @@ +# RFC-0250/Covenants + +## Covenants + +![status: draft](theme/images/status-draft.svg) + +**Maintainer(s)**: [Stanley Bondi](https://github.com/sdbondi) + +# Licence + +[The 3-Clause BSD Licence](https://opensource.org/licenses/BSD-3-Clause). + +Copyright 2021 The Tari Development Community + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of this document must retain the above copyright notice, this list of conditions and the following + disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Language + +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT +RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in +[BCP 14](https://tools.ietf.org/html/bcp14) (covering RFC2119 and RFC8174) when, and only when, they appear in all +capitals, as shown here. + +## Disclaimer + +This document and its content are intended for information purposes only and may be subject to change or update without +notice. + +This document may include preliminary concepts that may or may not be in the process of being developed by the Tari +community. The release of this document is intended solely for review and discussion by the community of the +technological merits of the potential system outlined herein. + +## Goals + +This Request for Comment (RFC) presents a proposal for introducing _covenants_ into the Tari base layer protocol. Tari +Covenents aims to provide restrictions on the _future_ spending of subsequent transactions to enable a number of powerful +use-cases, such as +- [vaults] +- side-chain checkpointing transactions, +- commission on NFT transfers, and +- many others not thought of here. + +## Related Requests for Comment + +- [RFC-0200: Base Layer Extensions](BaseLayerExtensions.md) +- [RFC-0300: The Tari Digital Assets Network](RFC-0300_DAN.md) + +## Introduction + +The Tari protocol already provides programmable consensus, through [TariScript], that restricts whether a [UTXO] +may be included as an input to a transaction (a.k.a spent). The scope of information [TariScript] is inherently limited, +by the [TariScript Opcodes] and the input data provided by a spender. Once the requirements of the script are met, +a spender may generate [UTXO]s of their choosing, within the constraints of [MimbleWimble]. + +This RFC aims to expand the capabilities of Tari protocol by adding _additional requirements_, called covenants +that allow the owner(s) of a [UTXO] to control the composition of a _subsequent_ transaction. + +Covenants are not a new idea and have been proposed and implemented in various forms by others. + +For example, +- [Bitcoin-NG covenents] put forward the `CheckOutputVerify` script opcode. +- [Handshake] has implemented covenants to add the [UTXO] state of their auctioning process. +- [Elements Covenants] + +## Covenants in MimbleWimble + +In block chains like Bitcoin, a block contains discrete transactions containing inputs and outputs. A covenant +in Bitcoin would be able to interrogate those outputs _belonging to the input_ to ensure that they adhere to rules. + +In [MimbleWimble], the body of a block and transaction can be expressed in an identical data structure. This +is indeed the case in the [Tari codebase], which defines a structure called `AggregateBody` containing inputs +and outputs (and kernels) for transactions and blocks. This is innate to [MimbleWimble], so even if we were +to put a "box" around these inputs/outputs there is nothing to stop someone from including inputs and +outputs from other boxes as long as balance is maintained. + +This results in an interesting dilemma: how do we allow rules that dictate how future outputs look only armed with +the knowledge that the rule must apply to one or more outputs? + +In this RFC, we propose a covenant scheme that allows the [UTXO] originator to express a _filter_ that must be +satisfied for a subsequent spending transaction to be considered valid. + +## Assumptions + +The following assumptions are made: +1. Duplicate commitments within a block are disallowed by consensus _prior_ to covenant execution, +2. all outputs in the output set are valid, and +3. all inputs are valid spends, save for covenent checks. + +## Protocol modifications + +Modifications to the existing protocol and consensus are as follows: + +- the covenant is recorded in the transaction [UTXO], +- the covenant is committed to in the output and input hashes to prevent malleability, +- transactions with covenants entering the mempool MUST be validated, and +- each covenant in a block must be validated before being included in the block chain. + +### Transaction input and output changes + +A `covenant` field would need to be added to the `TransactionOutput` and `TransactionInput` structs +and committed to in their hashes. + +### Covenant definition + +We define a clear notation for covenants that mirrors the [miniscript] project. + +#### Execution Context and Scope + +Covenants execute within a limited read-only context and scope. This is both to reduce complexity (and therefore +the possibility of bugs) and maintain reasonable performance. + +A covenant's context is limited to: +- a immutable reference to the current input, +- a vector of immutable _references_ to outputs in the current block/transaction (called, the output set), +- the current input's mined height, and +- the current block height. + +Each output's covenant is executed with this context, filtering on the output set and returning the result. +The output set given to each covenant at execution MUST be the same set for all covenants and MUST never be +influenced by other covenants. The stateless and immutable nature of this scheme has the benefit of being +able to execute covenants in parallel. + +A covenant passes if at least one output in the set is matched. Allowing more than one output to match allows for +covenants that restrict the characteristics of multiple outputs. A covenant that matches zero outputs _fails_ +which invalidates the transaction/block. + +If a covenant is empty (zero bytes) the `identity` operation is implied and therefore, no actual execution need occur. + +#### Argument types + +```rust,ignore +enum CovenantArg { + // byte code: 0x01 + // data size: 32 bytes + Hash([u8; 32]), + // byte code: 0x02 + // data size: 32 bytes + PublicKey(RistrettoPublicKey), + // byte code: 0x03 + // data size: 32 bytes + Commitment(PedersonCommitment), + // byte code: 0x04 + // data size: 64 bytes + Signature(Signature), + // byte code: 0x05 + // data size: variable + Script(TariScript), + // byte code: 0x06 + // data size: variable + Covenant(Covenant), + // byte code: 0x07 + // data size: variable + VarInt(VarInt), + // byte code: 0x08 + // data size: 1 byte + Field(FieldKey), + // byte code: 0x09 + // data size: variable + Fields(Vec), +} +``` + +##### Output field tags + +Fields from each output in the output set may be brought into a covenant filter. +The available fields are defined as follows: + + +| Tag Name | Byte Code | Returns | +|---------------------------------------|---------------|---------------------------------------| +| `field::commitment` | 0x00 | output.commitment | +| `field::script` | 0x01 | output.script | +| `field::sender_offset_public_key` | 0x02 | output.sender_offset_public_key | +| `field::covenant` | 0x03 | output.covenant | +| `field::features` | 0x04 | output.features | +| `field::features_flags` | 0x05 | output.features.flags | +| `field::features_maturity` | 0x06 | output.features.maturity | +| `field::features_unique_id` | 0x07 | output.features.unique_id | +| `field::features_parent_public_key` | 0x08 | output.features.parent_public_key | +| `field::features_metadata` | 0x09 | output.features.metadata | + +Each field tag returns a consensus encoded byte representation of the value contained in the field. +How those bytes are interpreted depends on the covenant. For instance, `filter_fields_hashed_eq` will +concatenate the bytes and hash the result whereas `filter_field_int_eq` will interpret the bytes as a +little-endian 64-byte unsigned integer. + +#### Set operations + +##### identity() + +The output set is returned unaltered. This rule is implicit for an empty (0 byte) covenant. + +```yaml +op_byte: 0x20 +args: [] +``` + +##### and(A, B) + +The intersection (\\(A \cap B\\)) of the resulting output set for covenant rules \\(A\\) and \\(B\\). + +```yaml +op_byte: 0x21 +args: [Covenant, Covenant] +``` + +##### or(A, B) + +The union (\\(A \cup B\\)) of the resulting output set for covenant rules \\(A\\) and \\(B\\). + +```yaml +op_byte: 0x22 +args: [Covenant, Covenant] +``` + +##### xor(A, B) + +The symmetric difference (\\(A \triangle B\\)) of the resulting output set for covenant rules \\(A\\) and \\(B\\). +This is, outputs that match either \\(A\\) or \\(B\\) but not both. + +```yaml +op_byte: 0x23 +args: [Covenant, Covenant] +``` + +##### not(A) + +Returns the compliment of `A`. That is, all the elements of `A` are removed from the +resultant output set. + +```yaml +op_byte: 0x24 +args: [Covenant] +``` + +##### empty() + +Returns an empty set. This will always fail and, if used alone, prevents the UTXO from ever being spent. +A more useful reason to use `empty` is in conjunction a conditional e.g. `if_else(Condition(older_rel(10)), A, empty)` + +```yaml +op_byte: 0x25 +args: [] +``` + +#### Filters + +##### filter_output_hash_eq(hash) + +Filters for a single output that matches the hash. This filter only returns zero or one outputs. + +```yaml +op_byte: 0x30 +args: [Hash] +``` + +##### filter_fields_preserved(fields) + +Filter for outputs where all given fields in the input are preserved in the output. + +```yaml +op_byte: 0x31 +args: [Fields] +``` + +##### filter_field_int_eq(field, int) + +Filters for outputs whose field value matches the given integer value. If the given field cannot be cast +to an unsigned 64-bit integer, the transaction/block is rejected. + +```yaml +op_byte: 0x32 +args: [Field, VarInt] +``` + +##### filter_fields_hashed_eq(fields, hash) + +```yaml +op_byte: 0x33 +args: [Fields, VarInt] +``` + +##### filter_relative_height(height) + +Checks the block height that current [UTXO] (i.e. the current input) was mined plus `height` is greater than or +equal to the current block height. If so, the `identity()` is returned, otherwise `empty()`. + +```yaml +op_byte: 0x34 +args: [VarInt] +``` + +#### Encoding / Decoding + +Convenants can be encoded to/decoded from bytes as a token stream. Each token is consumed and interpreted serially +before being executed. + +For instance, + +``` +xor( + filter_output_hash_eq(Hash(0e0411c70df0ea4243a363fcbf161ebe6e2c1f074faf1c6a316a386823c3753c)), + filter_relative_height(10), +) +``` + +is represented in hex bytes as `23 30 01 a8b3f48e39449e89f7ff699b3eb2b080a2479b09a600a19d8ba48d765fe5d47d 35 07 0a`. +Let's unpack that as follows: +``` +23 // xor - consume two covenant args +30 // filter_output_hash_eq - consume a hash arg +01 // 32-byte hash +a8b3f48e39449e89f7ff699b3eb2b080a2479b09a600a19d8ba48d765fe5d47d // data +// end filter_output_hash_eq +35 // 2nd covenant - filter_relative_height +07 // varint +0A // 10 +// end varint, filter_relative_height, xor +``` + +Some functions can take any number of arguments, such as `filter_fields_hashed_eq` which defines the `Fields` type. +This type is encoded first by its byte code `34` followed by a varint encoded number that indicates the number +of field identifiers to consume. To mitigate misuse, the maximum allowed arguments are limited. + +### Covenant Validation + +A covenant and therefore the block/transaction MUST be regarded as invalid if: + +1. an unrecognised byte code is encountered +2. the end of the byte stream is reached unexpectedly +3. there are bytes remaining on the stream after interpreting +4. an invalid argument type is encountered +5. the `Fields` type encounters more than 9 arguments (i.e. the number of fields tags available) +6. the depth of the calls exceeds 16. + +### Consensus changes + +The covenant is executed once all other validations, including [TariScript], are complete. This ensures that +invalid transactions in a block cannot influence the results. + +## Considerations + +### Complexity + +This introduces additional validation complexity. We avoid stacks, loop, and conditionals (covenants are basically +one conditional), there are overheads both in terms of complexity and performance as a trade-off for the +power given by covenants. + +The worst case complexity for covenant validation is `O(num_inputs*num_outputs)`, although as mentioned above +validation for each input can be executed in parallel. To compensate for the additional workload the network +encounters, use of covenants should incur heavily-weighted fees to discourage needlessly using them. + +### Cut-through + +The same arguments made in the [TariScript RFC](./RFC-0201_TariScript.md#cut-through) for the need to prevent +[cut-through] apply to covenants. + +### Chain analysis + +The same arguments made in the [TariScript RFC](./RFC-0201_TariScript.md#fodder-for-chain-analysis) apply. + +### Security + +As all outputs in a block are in the scope of an input to be checked, any unrelated/malicious output in a block +_could_ pass an unrelated covenant rule if given the chance. A secure covenant is one that _uniquely_ identifies +one or more outputs. + +## Examples + +### Now or never + +Spend within 10 blocks or burn + +``` +not(filter_relative_height(10)) +``` + +Note, this covenant may be valid when submitted to the mempool, but invalid by the time it is put in a block for +the miner. + +### NFT transfer + +Output features as detailed in [RFC-310-AssetImplementation] (early draft stages, still to be finalised) contain the +NFT details. This covenant preserves both the covenant protecting the token, and the token itself. + +``` +filter_fields_preserved([field::features, field::covenant]) +``` + +### Side-chain checkpointing + +``` +and( + filter_field_int_eq(field::feature_flags, 16) // SIDECHAIN CHECKPOINT = 16 + filter_fields_preserved([field::features, field::covenant, field::script]) +) +``` + +### Restrict spending to a particular commitment if not spent within 100 blocks + +``` +or( + not(filter_relative_height(100)), + filter_fields_hashed_eq([field::commmitment], Hash(xxxx)) +) +``` + +### Output must preserve covenant, features and script or be burnt + +``` +xor( + filter_fields_preserved([field::features, field::covenant, field::script]), + and( + filter_field_int_eq(field::features_flags, 128), // FLAG_BURN = 128 + filter_fields_hashed_eq([field::commitment, field::script], Hash(...)), + ), +) +``` + +### Commission for NFT transfer + +``` +// Must be different outputs +xor( + and( + // Relavant input fields preserved in subsequent output + filter_fields_preserved([fields::features, fields::covenant, fields::script]), + // The spender must obtain the covenent for the subsequent output + filter_fields_hashed_eq([fields::covenant], Hash(xxxx)), + ), + // The spender must obtain and submit the output that matches this hash + filter_output_hash_eq(Hash(xxxx)), +) +``` + +### Other potential covenants + +- `filter_script_eq(script)` +- `filter_covenant_eq(covenant)` +- `filter_script_match()` +- `filter_covenant_match()` + +[commitment]: (./Glossary.md#commitment) +[Tari codebase]: (https://github.com/tari-project/tari) +[Handshake]: https://handshake.org/files/handshake.txt +[cut-through]: https://tlu.tarilabs.com/protocols/grin-protocol-overview/MainReport.html#cut-through +[RFC-0310_AssetImplementation]: https://github.com/tari-project/tari/pull/3340 +[Bitcoin-NG covenants](https://maltemoeser.de/paper/covenants.pdf) +[UTXO](./Glossary.md#unspent-transaction-outputs) +[miniscript](https://medium.com/blockstream/miniscript-bitcoin-scripting-3aeff3853620) +[Elements Covenants](https://blockstream.com/2016/11/02/en-covenants-in-elements-alpha/) +[vaults](https://hackingdistributed.com/2016/02/26/how-to-implement-secure-bitcoin-vaults/) diff --git a/RFC/src/SUMMARY.md b/RFC/src/SUMMARY.md index 7075ac1276..57ef0b72a3 100644 --- a/RFC/src/SUMMARY.md +++ b/RFC/src/SUMMARY.md @@ -27,6 +27,7 @@ - [RFC-0202: TariScript Opcodes](RFC-0202_TariScriptOpcodes.md) - [RFC-0230: Hash time locked contracts](RFC-0230_HTLC.md) - [RFC-0240: Atomic swap](RFC-0240_AtomicSwap.md) + - [RFC-0250: Covenants](RFC-0250_Covenants.md) - [RFC-0322: Validator Node Registration](RFC-0322_VNRegistration.md) - [RFC-0341: Asset registration](RFC-0341_AssetRegistration.md) - [RFC-0300: The Digital Assets Network](RFC-0300_DAN.md) From c286d408f5419620a63783c1ae9fe4d9f5cd68d2 Mon Sep 17 00:00:00 2001 From: Philip Robinson Date: Wed, 17 Nov 2021 12:37:28 +0200 Subject: [PATCH 2/6] =?UTF-8?q?feat(wallet):=20import=20utxo=E2=80=99s=20a?= =?UTF-8?q?s=20EncumberedToBeReceived=20rather=20than=20Unspent=20(#3575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description --- When the Wallet imports a UTXO it would set its status to Unspent making it immediately spendable. However, imported outputs are missing a number of pieces of data from the chain that a traditionally received output would have. Completing a validation cycle fills in this data. However, this caused some issues in the mobile clients when importing a UTXO and quickly spending it before the first validation was complete. There were unintended edge cases when a validation completed during an active transaction negotiation. This PR solves this problem by importing utxo’s into the wallet via the Wallet.import_utxo(…) method in the EncumberedToBeReceived status and triggering a new validation immediately. This stops the output from being selected for a transaction before the validation completes which should happen quickly if the wallet is connected to a base node. How Has This Been Tested? --- cargo test --- .../src/output_manager_service/handle.rs | 19 +++++++++++++++ .../src/output_manager_service/service.rs | 22 ++++++++++++++++- .../storage/database.rs | 15 ++++++++++++ .../storage/sqlite_db/mod.rs | 24 +++++++++++++++++++ base_layer/wallet/src/wallet.rs | 2 +- base_layer/wallet/tests/wallet/mod.rs | 4 +--- base_layer/wallet_ffi/src/lib.rs | 20 +++++++++++++++- 7 files changed, 100 insertions(+), 6 deletions(-) diff --git a/base_layer/wallet/src/output_manager_service/handle.rs b/base_layer/wallet/src/output_manager_service/handle.rs index ff483c8f3b..710f52307a 100644 --- a/base_layer/wallet/src/output_manager_service/handle.rs +++ b/base_layer/wallet/src/output_manager_service/handle.rs @@ -48,6 +48,7 @@ pub enum OutputManagerRequest { GetBalance, AddOutput(Box), AddOutputWithTxId((TxId, Box)), + AddUnvalidatedOutput((TxId, Box)), UpdateOutputMetadataSignature(Box), GetRecipientTransaction(TransactionSenderMessage), GetCoinbaseTransaction((u64, MicroTari, MicroTari, u64)), @@ -131,6 +132,9 @@ impl fmt::Display for OutputManagerRequest { pre_image, fee_per_gram, ), + OutputManagerRequest::AddUnvalidatedOutput((t, v)) => { + write!(f, "AddUnvalidatedOutput ({}: {})", t, v.value) + }, } } } @@ -234,6 +238,21 @@ impl OutputManagerHandle { } } + pub async fn add_unvalidated_output( + &mut self, + tx_id: TxId, + output: UnblindedOutput, + ) -> Result<(), OutputManagerError> { + match self + .handle + .call(OutputManagerRequest::AddUnvalidatedOutput((tx_id, Box::new(output)))) + .await?? + { + OutputManagerResponse::OutputAdded => Ok(()), + _ => Err(OutputManagerError::UnexpectedApiResponse), + } + } + pub async fn update_output_metadata_signature( &mut self, output: TransactionOutput, diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index e47cbe9db1..e4738d8d09 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -339,6 +339,10 @@ where self.claim_sha_atomic_swap_with_hash(output_hash, pre_image, fee_per_gram) .await }, + OutputManagerRequest::AddUnvalidatedOutput((tx_id, uo)) => self + .add_unvalidated_output(tx_id, *uo) + .await + .map(|_| OutputManagerResponse::OutputAdded), } } @@ -417,7 +421,7 @@ where self.validate_outputs() } - /// Add an unblinded output to the unspent outputs list + /// Add an unblinded output to the outputs table and marks is as `Unspent`. pub async fn add_output(&mut self, tx_id: Option, output: UnblindedOutput) -> Result<(), OutputManagerError> { debug!( target: LOG_TARGET, @@ -431,6 +435,22 @@ where Ok(()) } + /// Add an unblinded output to the outputs table and marks is as `EncumberedToBeReceived`. This is so that it will + /// require a successful validation to confirm that it indeed spendable. + pub async fn add_unvalidated_output( + &mut self, + tx_id: TxId, + output: UnblindedOutput, + ) -> Result<(), OutputManagerError> { + debug!( + target: LOG_TARGET, + "Add unvalidated output of value {} to Output Manager", output.value + ); + let output = DbUnblindedOutput::from_unblinded_output(output, &self.resources.factories)?; + self.resources.db.add_unvalidated_output(tx_id, output).await?; + Ok(()) + } + /// Update an output's metadata signature, akin to 'finalize output' pub async fn update_output_metadata_signature( &mut self, diff --git a/base_layer/wallet/src/output_manager_service/storage/database.rs b/base_layer/wallet/src/output_manager_service/storage/database.rs index 127472d2d9..72caec2822 100644 --- a/base_layer/wallet/src/output_manager_service/storage/database.rs +++ b/base_layer/wallet/src/output_manager_service/storage/database.rs @@ -128,6 +128,8 @@ pub trait OutputManagerBackend: Send + Sync + Clone { &self, current_tip_for_time_lock_calculation: Option, ) -> Result; + /// Import unvalidated output + fn add_unvalidated_output(&self, output: DbUnblindedOutput, tx_id: TxId) -> Result<(), OutputManagerStorageError>; } /// Holds the state of the KeyManager being used by the Output Manager Service @@ -264,6 +266,19 @@ where T: OutputManagerBackend + 'static Ok(()) } + pub async fn add_unvalidated_output( + &self, + tx_id: TxId, + output: DbUnblindedOutput, + ) -> Result<(), OutputManagerStorageError> { + let db_clone = self.db.clone(); + tokio::task::spawn_blocking(move || db_clone.add_unvalidated_output(output, tx_id)) + .await + .map_err(|err| OutputManagerStorageError::BlockingTaskSpawnError(err.to_string()))??; + + Ok(()) + } + pub async fn add_output_to_be_received( &self, tx_id: TxId, diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs index fdd8661e9d..974c4a57fc 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs @@ -1166,6 +1166,30 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase { } Ok(()) } + + fn add_unvalidated_output(&self, output: DbUnblindedOutput, tx_id: TxId) -> Result<(), OutputManagerStorageError> { + let start = Instant::now(); + let conn = self.database_connection.get_pooled_connection()?; + let acquire_lock = start.elapsed(); + + if OutputSql::find_by_commitment_and_cancelled(&output.commitment.to_vec(), false, &conn).is_ok() { + return Err(OutputManagerStorageError::DuplicateOutput); + } + let mut new_output = NewOutputSql::new(output, OutputStatus::EncumberedToBeReceived, Some(tx_id), None)?; + self.encrypt_if_necessary(&mut new_output)?; + new_output.commit(&conn)?; + + if start.elapsed().as_millis() > 0 { + trace!( + target: LOG_TARGET, + "sqlite profile - reinstate_cancelled_inbound_output: lock {} + db_op {} = {} ms", + acquire_lock.as_millis(), + (start.elapsed() - acquire_lock).as_millis(), + start.elapsed().as_millis() + ); + } + Ok(()) + } } impl TryFrom for OutputStatus { diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index 1b71f2744d..1ea209b069 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -373,7 +373,7 @@ where .await?; self.output_manager_service - .add_output_with_tx_id(tx_id, unblinded_output.clone()) + .add_unvalidated_output(tx_id, unblinded_output.clone()) .await?; info!( diff --git a/base_layer/wallet/tests/wallet/mod.rs b/base_layer/wallet/tests/wallet/mod.rs index e2a2df6da2..3dcc79190b 100644 --- a/base_layer/wallet/tests/wallet/mod.rs +++ b/base_layer/wallet/tests/wallet/mod.rs @@ -744,7 +744,7 @@ async fn test_import_utxo() { let balance = alice_wallet.output_manager_service.get_balance().await.unwrap(); - assert_eq!(balance.available_balance, 20000 * uT); + assert_eq!(balance.pending_incoming_balance, 20000 * uT); let completed_tx = alice_wallet .transaction_service @@ -755,8 +755,6 @@ async fn test_import_utxo() { .expect("Tx should be in collection"); assert_eq!(completed_tx.amount, 20000 * uT); - let stored_utxo = alice_wallet.output_manager_service.get_unspent_outputs().await.unwrap()[0].clone(); - assert_eq!(stored_utxo, utxo); } #[test] diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index c783a1147a..fbd9046d76 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -4392,7 +4392,25 @@ pub unsafe extern "C" fn wallet_import_utxo( &(*spending_key).clone(), &Default::default(), )) { - Ok(tx_id) => tx_id, + Ok(tx_id) => { + if let Err(e) = (*wallet) + .runtime + .block_on((*wallet).wallet.output_manager_service.validate_txos()) + { + error = LibWalletError::from(WalletError::OutputManagerError(e)).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + if let Err(e) = (*wallet) + .runtime + .block_on((*wallet).wallet.transaction_service.validate_transactions()) + { + error = LibWalletError::from(WalletError::TransactionServiceError(e)).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + tx_id + }, Err(e) => { error = LibWalletError::from(e).code; ptr::swap(error_out, &mut error as *mut c_int); From 81f8c379d03fec18165d309d8a43d5c3cafa692d Mon Sep 17 00:00:00 2001 From: Mike the Tike Date: Wed, 17 Nov 2021 14:13:06 +0200 Subject: [PATCH 3/6] ci: split cucumber job into two (#3583) Split circle ci job into two smaller jobs --- .circleci/config.yml | 232 ++++-------------- .../features/WalletTransactions.feature | 2 +- 2 files changed, 44 insertions(+), 190 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f502eb02da..bb6fa80f20 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,97 +4,52 @@ defaults: rust_image: &rust_image quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-09-18 commands: - test: - description: Run the tests - parameters: - release: - description: Set this to true to compile in release mode. - type: boolean - default: false + cucumber-js: + description: Run cucumber scenarios steps: - run: - name: Calculate dependencies - command: | - rustc --version >rust-version - test -e Cargo.lock || cargo generate-lockfile + name: node -v + command: node -v - run: - name: Install cargo2junit - command: cargo install cargo2junit - - restore_cache: - keys: - - v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-<>-{{checksum "Cargo.lock"}} + name: npm ci + command: cd integration_tests && npm ci - run: - name: Run tests - command: mkdir -p testresults && cargo test --workspace --all-features -v --jobs=3 <<#parameters.release>>--release<> -- -Z unstable-options --format json --report-time | cargo2junit > testresults/results.xml - - save_cache: - paths: - - /usr/local/cargo/registry - - target - key: v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-<>-{{checksum "Cargo.lock"}} - - store_test_results: - path: testresults - - store_artifacts: - path: testresults - build: - description: Build - parameters: - release: - description: Set this to true to compile in release mode. - type: boolean - default: false - steps: + name: Check formatting + command: cd integration_tests && npm run check-fmt - run: - name: Calculate dependencies - command: | - rustc --version >rust-version - test -e Cargo.lock || cargo generate-lockfile - - restore_cache: - keys: - - v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-<>-{{checksum "Cargo.lock"}} + name: Check eslint + command: cd integration_tests && npm run lint - run: - name: Build - command: cargo build -v --all --all-features --jobs=3 <<#parameters.release>>--release<> + name: Build base node + command: cargo build --release --bin tari_base_node - run: - name: Build Wallet - command: cargo build -p tari_wallet <<#parameters.release>>--release<> - - save_cache: - paths: - - /usr/local/cargo/registry - - target - key: v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-<>-{{checksum "Cargo.lock"}} - clippy: - description: cargo clippy - steps: + name: Build wallet + command: cargo build --release --bin tari_console_wallet - run: - name: Calculate dependencies - command: | - rustc --version >rust-version - test -e Cargo.lock || cargo generate-lockfile - - restore_cache: - keys: - - v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-{{checksum "Cargo.lock"}} + name: Build mmproxy + command: cargo build --release --bin tari_merge_mining_proxy - run: - name: Cargo fmt - command: | - TOOLCHAIN=$(awk '/channel = /{print $NF}' rust-toolchain.toml) - rustup component add --toolchain $TOOLCHAIN rustfmt - cargo fmt --all -- --check + name: Build mining_node + command: cargo build --release --bin tari_mining_node - run: - name: Run clippy (main source) - command: | - TOOLCHAIN=$(awk '/channel = /{print $NF}' rust-toolchain.toml) - rustup component add --toolchain $TOOLCHAIN clippy - cargo clippy -- -D warnings -W clippy::cognitive_complexity + name: Build stratum_transcoder + command: cargo build --release --bin tari_stratum_transcoder - run: - name: Run clippy (all targets) - command: cargo clippy --all-targets -- -D warnings - - save_cache: - paths: - - /usr/local/cargo/registry - - target - key: v6-cargo-cache-{{arch}}-{{checksum "rust-version"}}-{{checksum "Cargo.lock"}} - cucumber-js: - description: Run cucumber scenarios + name: Run cucumber scenarios + no_output_timeout: 20m + command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "@critical and not @long-running and not @broken and not @wallet-ffi" --format json:cucumber_output/tests.cucumber --exit --retry 3 --retry-tag-filter "@flaky and not @broken" + - run: + name: Generate report + command: cd integration_tests && node ./generate_report.js + when: always + - store_test_results: + path: integration_tests/cucumber_output + - store_artifacts: + path: integration_tests/cucumber_output + - store_artifacts: + path: integration_tests/temp/reports + cucumber-js-ffi: + description: Run cucumber scenarios (FFI) steps: - run: name: node -v @@ -102,9 +57,6 @@ commands: - run: name: npm ci command: cd integration_tests && npm ci - - run: - name: Check formatting - command: cd integration_tests && npm run check-fmt - run: name: Check eslint command: cd integration_tests && npm run lint @@ -126,14 +78,6 @@ commands: - run: name: Build stratum_transcoder command: cargo build --release --bin tari_stratum_transcoder - - run: - name: Run cucumber scenarios - no_output_timeout: 20m - command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "@critical and not @long-running and not @broken and not @wallet-ffi" --format json:cucumber_output/tests.cucumber --exit --retry 3 --retry-tag-filter "@flaky and not @broken" - - run: - name: Generate report - command: cd integration_tests && node ./generate_report.js - when: always # Below step requires NodeJS v12 to run correctly, see explanation in WalletFFI.feature - run: name: Run FFI wallet library cucumber scenarios @@ -154,30 +98,6 @@ commands: path: integration_tests/temp/reports jobs: - test-docs: - docker: - - image: *rust_image - steps: - - checkout - - run: - name: RFC documentation - command: | - cargo install mdbook --version ^0.4 - cd RFC && mdbook test && mdbook build - - - persist_to_workspace: - root: . - paths: book - - test-tari-release: - docker: - - image: *rust_image - resource_class: medium - steps: - - checkout - - test: - release: true - run-integration-tests: docker: - image: *rust_image @@ -188,64 +108,16 @@ jobs: - checkout - cucumber-js - build-tari-release: - docker: - - image: *rust_image - resource_class: medium - steps: - - checkout - - build: - release: true - - clippy: + run-ffi-integration-tests: docker: - image: *rust_image resource_class: medium + environment: + CARGO_HTTP_MULTIPLEXING: false steps: - checkout - - clippy + - cucumber-js-ffi - deploy-docs: - docker: - - image: quay.io/tarilabs/git-ssh-client:0.2-alpine - steps: - - checkout - - attach_workspace: - at: . - - add_ssh_keys: - fingerprints: - - "a6:a6:e2:be:a3:94:3e:4c:9d:51:25:f6:98:f9:0c:a4" - - run: - name: Deploy docs to gh-pages branch - command: | - DEST_BRANCH=gh-pages - DEST_PATH=book/ - - if [[ ! -d $DEST_PATH ]]; then - echo "$DEST_PATH directory not found!" - exit 1 - fi - - TMP_DIR=$(mktemp -d /tmp/ghpages_XXXXXX) - - echo "Copying book files to temporary location $TMP_DIR" - cp -R $DEST_PATH/* $DEST_PATH/.nojekyll $TMP_DIR - - REMOTE=$(git remote get-url origin) - - cd $TMP_DIR - - git config --global user.email "ci-build@tari.com" - git config --global user.name "ci-build" - - git init - git checkout -b $DEST_BRANCH - git remote add origin $REMOTE - git add --all . - git commit -m "[skip ci] Update RFC docs" - git push origin $DEST_BRANCH --force - - echo "Published." workflows: version: 2 @@ -255,25 +127,7 @@ workflows: filters: branches: ignore: gh-pages - # - test-docs: - # filters: - # branches: - # ignore: gh-pages - # - deploy-docs: - # requires: - # - test-docs - # filters: - # branches: - # only: development - # - build-tari-release: - # filters: - # branches: - # ignore: gh-pages - # - test-tari-release: - # filters: - # branches: - # ignore: gh-pages - # - clippy: - # filters: - # branches: - # ignore: gh-pages + - run-ffi-integration-tests: + filters: + branches: + ignore: gh-pages \ No newline at end of file diff --git a/integration_tests/features/WalletTransactions.feature b/integration_tests/features/WalletTransactions.feature index 96d7378903..a279582e1b 100644 --- a/integration_tests/features/WalletTransactions.feature +++ b/integration_tests/features/WalletTransactions.feature @@ -1,7 +1,7 @@ @wallet-transact @wallet Feature: Wallet Transactions - @critical + @critical @flaky Scenario: Wallet sending and receiving one-sided transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes From 291380457ba28c6208d2d1ac97757e8cfa8df85c Mon Sep 17 00:00:00 2001 From: Philip Robinson Date: Wed, 17 Nov 2021 14:49:58 +0200 Subject: [PATCH 4/6] feat: add error codes to LibWallet for CipherSeed errors (#3578) Description --- This PR adds explicit error codes to the LibWallet FFI interface to return the errors that can occur when invalid seed words are used during wallet recovery. The new error codes are: - Code 429: KeyManagerError::InvalidData - Code 430: KeyManagerError::VersionMismatch - Code 431: KeyManagerError::DecryptionFailed - Code 432: KeyManagerError::CrcError How Has This Been Tested? --- cargo test --- base_layer/wallet_ffi/src/error.rs | 19 +++++++++++++++++-- base_layer/wallet_ffi/src/lib.rs | 3 ++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/base_layer/wallet_ffi/src/error.rs b/base_layer/wallet_ffi/src/error.rs index 37349dd778..e842530d11 100644 --- a/base_layer/wallet_ffi/src/error.rs +++ b/base_layer/wallet_ffi/src/error.rs @@ -26,14 +26,13 @@ use tari_crypto::{ signatures::SchnorrSignatureError, tari_utilities::{hex::HexError, ByteArrayError}, }; -use tari_key_manager::error::MnemonicError; +use tari_key_manager::error::{KeyManagerError, MnemonicError}; use tari_wallet::{ contacts_service::error::{ContactsServiceError, ContactsServiceStorageError}, error::{WalletError, WalletStorageError}, output_manager_service::error::{OutputManagerError, OutputManagerStorageError}, transaction_service::error::{TransactionServiceError, TransactionStorageError}, }; - use thiserror::Error; const LOG_TARGET: &str = "wallet_ffi::error"; @@ -286,6 +285,22 @@ impl From for LibWalletError { code: 428, message: format!("{:?}", w), }, + WalletError::KeyManagerError(KeyManagerError::InvalidData) => Self { + code: 429, + message: format!("{:?}", w), + }, + WalletError::KeyManagerError(KeyManagerError::VersionMismatch) => Self { + code: 430, + message: format!("{:?}", w), + }, + WalletError::KeyManagerError(KeyManagerError::DecryptionFailed) => Self { + code: 431, + message: format!("{:?}", w), + }, + WalletError::KeyManagerError(KeyManagerError::CrcError) => Self { + code: 432, + message: format!("{:?}", w), + }, // This is the catch all error code. Any error that is not explicitly mapped above will be given this code _ => Self { code: 999, diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index fbd9046d76..43006072de 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -1071,7 +1071,8 @@ pub unsafe extern "C" fn seed_words_push_word( return if let Err(e) = CipherSeed::from_mnemonic(&(*seed_words).0, None) { log::error!( target: LOG_TARGET, - "Problem building valid private seed from seed phrase" + "Problem building valid private seed from seed phrase: {}", + e ); error = LibWalletError::from(WalletError::KeyManagerError(e)).code; ptr::swap(error_out, &mut error as *mut c_int); From 294f45ea8b084a9c55daeea4a778cd5bd3f8be79 Mon Sep 17 00:00:00 2001 From: Mike the Tike Date: Wed, 17 Nov 2021 15:05:04 +0200 Subject: [PATCH 5/6] v0.21.1 --- Cargo.lock | 48 +++++++++---------- applications/tari_app_grpc/Cargo.toml | 2 +- applications/tari_app_utilities/Cargo.toml | 2 +- applications/tari_base_node/Cargo.toml | 2 +- applications/tari_console_wallet/Cargo.toml | 4 +- .../tari_merge_mining_proxy/Cargo.toml | 2 +- applications/tari_mining_node/Cargo.toml | 2 +- applications/test_faucet/Cargo.toml | 2 +- base_layer/common_types/Cargo.toml | 2 +- base_layer/core/Cargo.toml | 2 +- base_layer/key_manager/Cargo.toml | 2 +- base_layer/mmr/Cargo.toml | 2 +- base_layer/p2p/Cargo.toml | 2 +- base_layer/service_framework/Cargo.toml | 2 +- base_layer/tari_stratum_ffi/Cargo.toml | 2 +- base_layer/wallet/Cargo.toml | 2 +- base_layer/wallet_ffi/Cargo.toml | 2 +- changelog.md | 22 +++++++++ common/Cargo.toml | 2 +- comms/Cargo.toml | 2 +- comms/dht/Cargo.toml | 2 +- comms/rpc_macros/Cargo.toml | 2 +- infrastructure/derive/Cargo.toml | 2 +- infrastructure/shutdown/Cargo.toml | 2 +- infrastructure/storage/Cargo.toml | 2 +- infrastructure/test_utils/Cargo.toml | 2 +- package-lock.json | 2 +- 27 files changed, 72 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d674d81979..3e8078ceae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4401,7 +4401,7 @@ dependencies = [ [[package]] name = "tari_app_grpc" -version = "0.21.0" +version = "0.21.1" dependencies = [ "chrono", "prost", @@ -4416,7 +4416,7 @@ dependencies = [ [[package]] name = "tari_app_utilities" -version = "0.21.0" +version = "0.21.1" dependencies = [ "config", "dirs-next 1.0.2", @@ -4441,7 +4441,7 @@ dependencies = [ [[package]] name = "tari_base_node" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "bincode", @@ -4503,7 +4503,7 @@ dependencies = [ [[package]] name = "tari_common" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "config", @@ -4542,7 +4542,7 @@ dependencies = [ [[package]] name = "tari_common_types" -version = "0.21.0" +version = "0.21.1" dependencies = [ "digest", "futures 0.3.17", @@ -4556,7 +4556,7 @@ dependencies = [ [[package]] name = "tari_comms" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "async-trait", @@ -4606,7 +4606,7 @@ dependencies = [ [[package]] name = "tari_comms_dht" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -4654,7 +4654,7 @@ dependencies = [ [[package]] name = "tari_comms_rpc_macros" -version = "0.21.0" +version = "0.21.1" dependencies = [ "futures 0.3.17", "proc-macro2 1.0.32", @@ -4669,7 +4669,7 @@ dependencies = [ [[package]] name = "tari_console_wallet" -version = "0.21.0" +version = "0.21.1" dependencies = [ "bitflags 1.3.2", "chrono", @@ -4712,7 +4712,7 @@ dependencies = [ [[package]] name = "tari_core" -version = "0.21.0" +version = "0.21.1" dependencies = [ "async-trait", "bincode", @@ -4794,7 +4794,7 @@ dependencies = [ [[package]] name = "tari_infra_derive" -version = "0.21.0" +version = "0.21.1" dependencies = [ "blake2", "proc-macro2 0.4.30", @@ -4804,7 +4804,7 @@ dependencies = [ [[package]] name = "tari_key_manager" -version = "0.21.0" +version = "0.21.1" dependencies = [ "argon2", "arrayvec 0.7.1", @@ -4824,7 +4824,7 @@ dependencies = [ [[package]] name = "tari_merge_mining_proxy" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "bincode", @@ -4870,7 +4870,7 @@ dependencies = [ [[package]] name = "tari_mining_node" -version = "0.21.0" +version = "0.21.1" dependencies = [ "bufstream", "chrono", @@ -4900,7 +4900,7 @@ dependencies = [ [[package]] name = "tari_mmr" -version = "0.21.0" +version = "0.21.1" dependencies = [ "bincode", "blake2", @@ -4919,7 +4919,7 @@ dependencies = [ [[package]] name = "tari_p2p" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "bytes 0.5.6", @@ -4963,7 +4963,7 @@ dependencies = [ [[package]] name = "tari_service_framework" -version = "0.21.0" +version = "0.21.1" dependencies = [ "anyhow", "async-trait", @@ -4980,7 +4980,7 @@ dependencies = [ [[package]] name = "tari_shutdown" -version = "0.21.0" +version = "0.21.1" dependencies = [ "futures 0.3.17", "tokio 1.13.0", @@ -4988,7 +4988,7 @@ dependencies = [ [[package]] name = "tari_storage" -version = "0.21.0" +version = "0.21.1" dependencies = [ "bincode", "bytes 0.5.6", @@ -5006,7 +5006,7 @@ dependencies = [ [[package]] name = "tari_stratum_ffi" -version = "0.21.0" +version = "0.21.1" dependencies = [ "hex", "libc", @@ -5060,7 +5060,7 @@ dependencies = [ [[package]] name = "tari_test_utils" -version = "0.21.0" +version = "0.21.1" dependencies = [ "futures 0.3.17", "futures-test", @@ -5091,7 +5091,7 @@ dependencies = [ [[package]] name = "tari_wallet" -version = "0.21.0" +version = "0.21.1" dependencies = [ "aes-gcm 0.8.0", "argon2", @@ -5137,7 +5137,7 @@ dependencies = [ [[package]] name = "tari_wallet_ffi" -version = "0.21.0" +version = "0.21.1" dependencies = [ "chrono", "env_logger 0.7.1", @@ -5190,7 +5190,7 @@ dependencies = [ [[package]] name = "test_faucet" -version = "0.21.0" +version = "0.21.1" dependencies = [ "rand 0.8.4", "serde 1.0.130", diff --git a/applications/tari_app_grpc/Cargo.toml b/applications/tari_app_grpc/Cargo.toml index fff5cfc6b5..f3e7262c06 100644 --- a/applications/tari_app_grpc/Cargo.toml +++ b/applications/tari_app_grpc/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "This crate is to provide a single source for all cross application grpc files and conversions to and from tari::core" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/applications/tari_app_utilities/Cargo.toml b/applications/tari_app_utilities/Cargo.toml index 09f49767a5..48c8f0484f 100644 --- a/applications/tari_app_utilities/Cargo.toml +++ b/applications/tari_app_utilities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_app_utilities" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/tari_base_node/Cargo.toml b/applications/tari_base_node/Cargo.toml index 23c2c4916e..440ee59ea8 100644 --- a/applications/tari_base_node/Cargo.toml +++ b/applications/tari_base_node/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari full base node implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/applications/tari_console_wallet/Cargo.toml b/applications/tari_console_wallet/Cargo.toml index 7378ae8ed2..e7827d6e9d 100644 --- a/applications/tari_console_wallet/Cargo.toml +++ b/applications/tari_console_wallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_console_wallet" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] edition = "2018" @@ -50,7 +50,7 @@ default-features = false features = ["transactions", "mempool_proto", "base_node_proto"] [dependencies.tui] -version = "0.16" +version = "^0.16" default-features = false features = ["crossterm"] diff --git a/applications/tari_merge_mining_proxy/Cargo.toml b/applications/tari_merge_mining_proxy/Cargo.toml index b8649c0133..fc058caee9 100644 --- a/applications/tari_merge_mining_proxy/Cargo.toml +++ b/applications/tari_merge_mining_proxy/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari merge miner proxy for xmrig" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [features] diff --git a/applications/tari_mining_node/Cargo.toml b/applications/tari_mining_node/Cargo.toml index 9b9632f225..8d3dadd3db 100644 --- a/applications/tari_mining_node/Cargo.toml +++ b/applications/tari_mining_node/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari mining node implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/applications/test_faucet/Cargo.toml b/applications/test_faucet/Cargo.toml index 62e13c4707..1e5ee98504 100644 --- a/applications/test_faucet/Cargo.toml +++ b/applications/test_faucet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_faucet" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] edition = "2018" diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index 6e61345a94..a15d105675 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_common_types" authors = ["The Tari Development Community"] description = "Tari cryptocurrency common types" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index 0d8f4f8801..3f9b98c03c 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [features] diff --git a/base_layer/key_manager/Cargo.toml b/base_layer/key_manager/Cargo.toml index 3c3c69ab64..18c64eb6d5 100644 --- a/base_layer/key_manager/Cargo.toml +++ b/base_layer/key_manager/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet key management" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/base_layer/mmr/Cargo.toml b/base_layer/mmr/Cargo.toml index a61138f80b..62663d291f 100644 --- a/base_layer/mmr/Cargo.toml +++ b/base_layer/mmr/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "A Merkle Mountain Range implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [features] diff --git a/base_layer/p2p/Cargo.toml b/base_layer/p2p/Cargo.toml index f8ef9e7c04..e3a7b6f07d 100644 --- a/base_layer/p2p/Cargo.toml +++ b/base_layer/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_p2p" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development community"] description = "Tari base layer-specific peer-to-peer communication features" repository = "https://github.com/tari-project/tari" diff --git a/base_layer/service_framework/Cargo.toml b/base_layer/service_framework/Cargo.toml index b51333a151..bc288cf93e 100644 --- a/base_layer/service_framework/Cargo.toml +++ b/base_layer/service_framework/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_service_framework" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] description = "The Tari communication stack service framework" repository = "https://github.com/tari-project/tari" diff --git a/base_layer/tari_stratum_ffi/Cargo.toml b/base_layer/tari_stratum_ffi/Cargo.toml index b6b5effbd4..805be3e4b9 100644 --- a/base_layer/tari_stratum_ffi/Cargo.toml +++ b/base_layer/tari_stratum_ffi/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_stratum_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency miningcore C FFI bindings" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/base_layer/wallet/Cargo.toml b/base_layer/wallet/Cargo.toml index 33b4d75f2e..13c6e527e3 100644 --- a/base_layer/wallet/Cargo.toml +++ b/base_layer/wallet/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_wallet" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet library" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index 1402cd3e14..49ddf8016e 100644 --- a/base_layer/wallet_ffi/Cargo.toml +++ b/base_layer/wallet_ffi/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_wallet_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet C FFI bindings" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/changelog.md b/changelog.md index 45f5bf0402..d2f69f8cfd 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,28 @@ # Changelog +### [0.21.1](https://github.com/tari-project/tari/compare/v0.21.0...v0.21.1) (2021-11-17) + + +### Features + +* add atomic swap htlc sending and claiming ([#3552](https://github.com/tari-project/tari/issues/3552)) ([a185506](https://github.com/tari-project/tari/commit/a1855065e0f2aaabbb6d7e508f71d6d0eaf6acd5)) +* add error codes to LibWallet for CipherSeed errors ([#3578](https://github.com/tari-project/tari/issues/3578)) ([2913804](https://github.com/tari-project/tari/commit/291380457ba28c6208d2d1ac97757e8cfa8df85c)) +* add support for MultiAddr in RPC config ([#3557](https://github.com/tari-project/tari/issues/3557)) ([9f8e289](https://github.com/tari-project/tari/commit/9f8e2899922c0eec9167ed4f49c5d4c161330221)) +* get fee for transactions for stratum transcoder ([#3571](https://github.com/tari-project/tari/issues/3571)) ([ccf1da0](https://github.com/tari-project/tari/commit/ccf1da02dcbf99fe1872deec73f424b4328c70e0)) +* implement multiple read single write for sqlite ([#3568](https://github.com/tari-project/tari/issues/3568)) ([8d22164](https://github.com/tari-project/tari/commit/8d22164ca10a4493fe73f66d13edf9ddd57cc6d1)) +* implement prometheus metrics for base node ([#3563](https://github.com/tari-project/tari/issues/3563)) ([433bc46](https://github.com/tari-project/tari/commit/433bc46e3d5cd488ec0f29fef6059594cf0cf3e3)) +* one-click installer - cli edition ([#3534](https://github.com/tari-project/tari/issues/3534)) ([ec67798](https://github.com/tari-project/tari/commit/ec677987a712c934168040da07f31fc744f66f71)) +* trigger time lock balance update when block received ([#3567](https://github.com/tari-project/tari/issues/3567)) ([11b8afa](https://github.com/tari-project/tari/commit/11b8afa31abe7e64ff366f8e83e478b017a86da5)) +* **wallet:** import utxo’s as EncumberedToBeReceived rather than Unspent ([#3575](https://github.com/tari-project/tari/issues/3575)) ([c286d40](https://github.com/tari-project/tari/commit/c286d408f5419620a63783c1ae9fe4d9f5cd68d2)) + + +### Bug Fixes + +* avoid implicit using of the time crate ([#3562](https://github.com/tari-project/tari/issues/3562)) ([23e8398](https://github.com/tari-project/tari/commit/23e83988cb8fe99babd0a96686602added75011a)) +* stop leak of value of recovered output ([#3558](https://github.com/tari-project/tari/issues/3558)) ([e0f2187](https://github.com/tari-project/tari/commit/e0f21876278702aa43096b04aa9e701f0942be67)) +* use time crate instead of chrono ([#3527](https://github.com/tari-project/tari/issues/3527)) ([d211031](https://github.com/tari-project/tari/commit/d211031cfa44ad498706db84e8a919b9babaf422)) + ## [0.21.0](https://github.com/tari-project/tari/compare/v0.13.0...v0.21.0) (2021-11-09) diff --git a/common/Cargo.toml b/common/Cargo.toml index 8dd805cedd..4ed687e6da 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [features] diff --git a/comms/Cargo.toml b/comms/Cargo.toml index 380184bb05..091275ca46 100644 --- a/comms/Cargo.toml +++ b/comms/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/comms/dht/Cargo.toml b/comms/dht/Cargo.toml index 80739d331f..a02696fdbb 100644 --- a/comms/dht/Cargo.toml +++ b/comms/dht/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_comms_dht" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] description = "Tari comms DHT module" repository = "https://github.com/tari-project/tari" diff --git a/comms/rpc_macros/Cargo.toml b/comms/rpc_macros/Cargo.toml index 63944e9712..52a73902a4 100644 --- a/comms/rpc_macros/Cargo.toml +++ b/comms/rpc_macros/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [lib] diff --git a/infrastructure/derive/Cargo.toml b/infrastructure/derive/Cargo.toml index 619deeea72..6d7208e964 100644 --- a/infrastructure/derive/Cargo.toml +++ b/infrastructure/derive/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [lib] diff --git a/infrastructure/shutdown/Cargo.toml b/infrastructure/shutdown/Cargo.toml index 60f35c24ff..4a32a93b4b 100644 --- a/infrastructure/shutdown/Cargo.toml +++ b/infrastructure/shutdown/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/infrastructure/storage/Cargo.toml b/infrastructure/storage/Cargo.toml index 29a00c9766..42590b5b0d 100644 --- a/infrastructure/storage/Cargo.toml +++ b/infrastructure/storage/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.21.0" +version = "0.21.1" edition = "2018" [dependencies] diff --git a/infrastructure/test_utils/Cargo.toml b/infrastructure/test_utils/Cargo.toml index 083b0754f3..0fb9b1f8b2 100644 --- a/infrastructure/test_utils/Cargo.toml +++ b/infrastructure/test_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tari_test_utils" description = "Utility functions used in Tari test functions" -version = "0.21.0" +version = "0.21.1" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" diff --git a/package-lock.json b/package-lock.json index 127e50bdb2..fd3ecdaa80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4 +1,4 @@ { "lockfileVersion": 1, - "version": "0.14.0" + "version": "0.21.1" } From e191e27ed79aff5cfe4d76effe77473a03eb31f6 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal <39146854+hansieodendaal@users.noreply.github.com> Date: Wed, 17 Nov 2021 15:46:44 +0200 Subject: [PATCH 6/6] feat: improve wallet connectivity status for console wallet (#3577) Description --- - Improved base node connection status feedback to the console wallet UI. - Added disconnect logic for the wallet connectivity service to enable closing bad base node connections if RPC connections cannot be obtained, which will force the connection cycle to restart from scratch, rather than just waiting for the connection to become alive again. - ~~Disabled obtaining latency information after obtaining tip information in the wallet's base node monitor, as it sometimes introduces huge additional delays.~~ ~~_**Note:** Fixing this behaviour is marked for another PR._~~ _**(Fixed in PR #3579)**_ Motivation and Context --- - Connectivity status was not always current in the console wallet under certain edge cases, observed when switching base nodes. - Retrying to obtain an RPC connection from a bad base node connection is not efficient; this sometimes results in the base node staying offline for extended (> 30 minutes) durations. How Has This Been Tested? --- - System-level testing: - Switching base nodes and observing the connection status while (a) mining and (b) monitoring transactions to be mined. - Stress testing `make-it-rain`. - Stress testing `coin-split`. - Stress testing simaltaneous `make-it-rain` and `coin-split`. See sample profiling measurements below depicting the added delay sometimes introduced by obtaining latency information, _**without the fix mentioned above**_: ``` rust 2021-11-16 14:18:07.490078500 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain RPC client 160 ms 2021-11-16 14:18:08.062610200 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain tip info in 572 ms 2021-11-16 14:18:08.062646600 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain latency info in 0 ms 2021-11-16 14:18:08.062944600 [wallet::base_node_service::chain_metadata_monitor] DEBUG Base node ece4c616a156c1e4fe34d94d8c Tip: 52127 (Synced) Latency: 572 ms 2021-11-16 14:18:37.491546100 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain RPC client 0 ms 2021-11-16 14:20:28.971178900 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain tip info in 111479 ms 2021-11-16 14:25:07.794774200 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain latency info in 278823 ms 2021-11-16 14:25:07.795167000 [wallet::base_node_service::chain_metadata_monitor] DEBUG Base node ece4c616a156c1e4fe34d94d8c Tip: 52127 (Synced) Latency: 11011 ms 2021-11-16 14:25:26.789903600 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain RPC client 0 ms 2021-11-16 14:30:35.914526200 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain tip info in 309124 ms 2021-11-16 14:34:04.569556900 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain latency info in 208654 ms 2021-11-16 14:34:04.569945400 [wallet::base_node_service::chain_metadata_monitor] DEBUG Base node ece4c616a156c1e4fe34d94d8c Tip: 52130 (Synced) Latency: 9699 ms 2021-11-16 14:34:24.885048300 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain RPC client 0 ms 2021-11-16 14:34:44.260586300 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain tip info in 19375 ms 2021-11-16 14:34:44.260734900 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain latency info in 0 ms 2021-11-16 14:34:44.261005000 [wallet::base_node_service::chain_metadata_monitor] DEBUG Base node ece4c616a156c1e4fe34d94d8c Tip: 52133 (Synced) Latency: 10712 ms 2021-11-16 14:35:03.552244200 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain RPC client 0 ms 2021-11-16 14:35:22.417825800 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain tip info in 18865 ms 2021-11-16 14:35:22.417869200 [wallet::base_node_service::chain_metadata_monitor] TRACE Obtain latency info in 0 ms 2021-11-16 14:35:22.418075300 [wallet::base_node_service::chain_metadata_monitor] DEBUG Base node ece4c616a156c1e4fe34d94d8c Tip: 52134 (Synced) Latency: 18865 ms ``` --- .../wallet/src/base_node_service/monitor.rs | 37 +++++++++---------- .../src/connectivity_service/service.rs | 26 ++++++++++++- .../tests/transaction_service/service.rs | 4 +- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/base_layer/wallet/src/base_node_service/monitor.rs b/base_layer/wallet/src/base_node_service/monitor.rs index 11003eff8b..9ef2452086 100644 --- a/base_layer/wallet/src/base_node_service/monitor.rs +++ b/base_layer/wallet/src/base_node_service/monitor.rs @@ -119,7 +119,7 @@ where .obtain_base_node_wallet_rpc_client() .await .ok_or(BaseNodeMonitorError::NodeShuttingDown)?; - debug!( + trace!( target: LOG_TARGET, "Obtain RPC client {} ms", timer.elapsed().as_millis() @@ -144,36 +144,27 @@ where .and_then(|metadata| { ChainMetadata::try_from(metadata).map_err(BaseNodeMonitorError::InvalidBaseNodeResponse) })?; - debug!( + trace!( target: LOG_TARGET, - "get_tip_info took {} ms", + "Obtain tip info in {} ms", timer.elapsed().as_millis() ); + let timer = Instant::now(); let latency = match client.get_last_request_latency().await? { Some(latency) => latency, None => continue, }; - - let is_synced = tip_info.is_synced; - debug!( - target: LOG_TARGET, - "Base node {} Tip: {} ({}) Latency: {} ms", - base_node_id, - chain_metadata.height_of_longest_chain(), - if is_synced { "Synced" } else { "Syncing..." }, - latency.as_millis() - ); - - let timer = Instant::now(); - self.db.set_chain_metadata(chain_metadata.clone()).await?; trace!( target: LOG_TARGET, - "Update metadata in db {} ms", + "Obtain latency info in {} ms", timer.elapsed().as_millis() ); - let timer = Instant::now(); + self.db.set_chain_metadata(chain_metadata.clone()).await?; + + let is_synced = tip_info.is_synced; + let height_of_longest_chain = chain_metadata.height_of_longest_chain(); self.map_state(move |_| BaseNodeState { chain_metadata: Some(chain_metadata), is_synced: Some(is_synced), @@ -181,7 +172,15 @@ where latency: Some(latency), }) .await; - trace!(target: LOG_TARGET, "Publish event {} ms", timer.elapsed().as_millis()); + + debug!( + target: LOG_TARGET, + "Base node {} Tip: {} ({}) Latency: {} ms", + base_node_id, + height_of_longest_chain, + if is_synced { "Synced" } else { "Syncing..." }, + latency.as_millis() + ); let delay = time::sleep(self.interval.saturating_sub(latency)); if interrupt(base_node_watch.changed(), delay).await.is_none() { diff --git a/base_layer/wallet/src/connectivity_service/service.rs b/base_layer/wallet/src/connectivity_service/service.rs index a3df1874b4..d558389747 100644 --- a/base_layer/wallet/src/connectivity_service/service.rs +++ b/base_layer/wallet/src/connectivity_service/service.rs @@ -88,6 +88,7 @@ impl WalletConnectivityService { debug!(target: LOG_TARGET, "Wallet connectivity service has started."); let mut check_connection = time::interval_at(time::Instant::now() + Duration::from_secs(5), Duration::from_secs(5)); + self.set_online_status(OnlineStatus::Offline); check_connection.set_missed_tick_behavior(MissedTickBehavior::Delay); loop { tokio::select! { @@ -116,6 +117,7 @@ impl WalletConnectivityService { if let Some(pool) = self.pools.as_ref() { if !pool.base_node_wallet_rpc_client.is_connected().await { debug!(target: LOG_TARGET, "Peer connection lost. Attempting to reconnect..."); + self.set_online_status(OnlineStatus::Offline); self.setup_base_node_connection().await; } } @@ -155,6 +157,9 @@ impl WalletConnectivityService { target: LOG_TARGET, "Base node connection failed: {}. Reconnecting...", e ); + if let Some(node_id) = self.current_base_node() { + self.disconnect_base_node(node_id).await; + }; self.pending_requests.push(reply.into()); }, }, @@ -185,6 +190,9 @@ impl WalletConnectivityService { target: LOG_TARGET, "Base node connection failed: {}. Reconnecting...", e ); + if let Some(node_id) = self.current_base_node() { + self.disconnect_base_node(node_id).await; + }; self.pending_requests.push(reply.into()); }, }, @@ -205,6 +213,14 @@ impl WalletConnectivityService { self.base_node_watch.borrow().as_ref().map(|p| p.node_id.clone()) } + async fn disconnect_base_node(&mut self, node_id: NodeId) { + if let Ok(Some(connection)) = self.connectivity.get_connection(node_id.clone()).await { + if connection.clone().disconnect().await.is_ok() { + debug!(target: LOG_TARGET, "Disconnected base node peer {}", node_id); + } + }; + } + async fn setup_base_node_connection(&mut self) { self.pools = None; loop { @@ -231,15 +247,18 @@ impl WalletConnectivityService { }, Ok(false) => { // Retry with updated peer + self.disconnect_base_node(node_id).await; + time::sleep(self.config.base_node_monitor_refresh_interval).await; continue; }, Err(e) => { - if self.current_base_node() != Some(node_id) { + if self.current_base_node() != Some(node_id.clone()) { self.set_online_status(OnlineStatus::Connecting); } else { self.set_online_status(OnlineStatus::Offline); } warn!(target: LOG_TARGET, "{}", e); + self.disconnect_base_node(node_id).await; time::sleep(self.config.base_node_monitor_refresh_interval).await; continue; }, @@ -254,7 +273,10 @@ impl WalletConnectivityService { async fn try_setup_rpc_pool(&mut self, peer: NodeId) -> Result { let conn = match self.try_dial_peer(peer.clone()).await? { Some(c) => c, - None => return Ok(false), + None => { + warn!(target: LOG_TARGET, "Could not dial base node peer {}", peer); + return Ok(false); + }, }; debug!( target: LOG_TARGET, diff --git a/base_layer/wallet/tests/transaction_service/service.rs b/base_layer/wallet/tests/transaction_service/service.rs index d9b058ad49..acebd6425a 100644 --- a/base_layer/wallet/tests/transaction_service/service.rs +++ b/base_layer/wallet/tests/transaction_service/service.rs @@ -998,8 +998,8 @@ fn test_htlc_send_and_claim() { .expect("Alice sending HTLC transaction") }); - let mut alice_ts_clone2 = alice_ts.clone(); - let mut alice_oms_clone = alice_oms.clone(); + let mut alice_ts_clone2 = alice_ts; + let mut alice_oms_clone = alice_oms; runtime.block_on(async move { let completed_tx = alice_ts_clone2 .get_completed_transaction(tx_id)