From 1a6b8aff3b8f54d8a4ba846dbf3b2821efa7d427 Mon Sep 17 00:00:00 2001 From: antiochp <30642645+antiochp@users.noreply.github.com> Date: Tue, 20 Aug 2019 10:05:21 +0100 Subject: [PATCH] introduce VersionedCoinbase to add api stability around build_coinbase --- api/src/foreign_rpc.rs | 14 +++++++++----- impls/src/test_framework/mod.rs | 18 +++++++++++------- libwallet/src/api_impl/types.rs | 12 ------------ libwallet/src/lib.rs | 7 ++++--- libwallet/src/slate.rs | 16 ++++++++++++++-- libwallet/src/slate_versions/mod.rs | 21 ++++++++++++++++++++- libwallet/src/slate_versions/v2.rs | 13 ++++++++++++- libwallet/src/types.rs | 15 ++++++++++++++- 8 files changed, 84 insertions(+), 32 deletions(-) diff --git a/api/src/foreign_rpc.rs b/api/src/foreign_rpc.rs index fef2d2dce..a360b29c6 100644 --- a/api/src/foreign_rpc.rs +++ b/api/src/foreign_rpc.rs @@ -17,7 +17,8 @@ use crate::keychain::Keychain; use crate::libwallet::{ self, BlockFees, CbData, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient, - NodeVersionInfo, Slate, VersionInfo, VersionedSlate, WalletLCProvider, + NodeVersionInfo, Slate, SlateVersion, VersionInfo, VersionedCoinbase, VersionedSlate, + WalletLCProvider, }; use crate::{Foreign, ForeignCheckMiddlewareFn}; use easy_jsonrpc_mw; @@ -94,7 +95,9 @@ pub trait ForeignRpc { "kernel": { "excess": "08dfe86d732f2dd24bac36aa7502685221369514197c26d33fac03041d47e4b490", "excess_sig": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841be02fa098c54c9bf638e0ee1ad5eb896caa11565f632be7b9cd65643ba371044f", - "features": "Coinbase" + "features": "Coinbase", + "fee": "0", + "lock_height": "0" }, "key_id": "0300000000000000000000000400000000", "output": { @@ -110,7 +113,7 @@ pub trait ForeignRpc { ``` */ - fn build_coinbase(&self, block_fees: &BlockFees) -> Result; + fn build_coinbase(&self, block_fees: &BlockFees) -> Result; /** Networked version of [Foreign::verify_slate_messages](struct.Foreign.html#method.verify_slate_messages). @@ -524,8 +527,9 @@ where Foreign::check_version(self).map_err(|e| e.kind()) } - fn build_coinbase(&self, block_fees: &BlockFees) -> Result { - Foreign::build_coinbase(self, block_fees).map_err(|e| e.kind()) + fn build_coinbase(&self, block_fees: &BlockFees) -> Result { + let cb: CbData = Foreign::build_coinbase(self, block_fees).map_err(|e| e.kind())?; + Ok(VersionedCoinbase::into_version(cb, SlateVersion::V2)) } fn verify_slate_messages(&self, slate: VersionedSlate) -> Result<(), ErrorKind> { diff --git a/impls/src/test_framework/mod.rs b/impls/src/test_framework/mod.rs index 3e8a8b593..baa9df14f 100644 --- a/impls/src/test_framework/mod.rs +++ b/impls/src/test_framework/mod.rs @@ -16,13 +16,13 @@ use crate::api; use crate::chain; use crate::chain::Chain; use crate::core; -use crate::core::core::{OutputFeatures, OutputIdentifier, Transaction}; +use crate::core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel}; use crate::core::{consensus, global, pow}; use crate::keychain; use crate::libwallet; use crate::libwallet::api_impl::{foreign, owner}; use crate::libwallet::{ - BlockFees, CbData, InitTxArgs, NodeClient, WalletInfo, WalletInst, WalletLCProvider, + BlockFees, InitTxArgs, NodeClient, WalletInfo, WalletInst, WalletLCProvider, }; use crate::util::secp::key::SecretKey; use crate::util::secp::pedersen; @@ -75,14 +75,19 @@ fn get_outputs_by_pmmr_index_local( } /// Adds a block with a given reward to the chain and mines it -pub fn add_block_with_reward(chain: &Chain, txs: Vec<&Transaction>, reward: CbData) { +pub fn add_block_with_reward( + chain: &Chain, + txs: Vec<&Transaction>, + reward_output: Output, + reward_kernel: TxKernel, +) { let prev = chain.head_header().unwrap(); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let mut b = core::core::Block::new( &prev, txs.into_iter().cloned().collect(), next_header_info.clone().difficulty, - (reward.output, reward.kernel), + (reward_output, reward_kernel), ) .unwrap(); b.header.timestamp = prev.timestamp + Duration::seconds(60); @@ -125,10 +130,9 @@ where let coinbase_tx = { let mut w_lock = wallet.lock(); let w = w_lock.lc_provider()?.wallet_inst()?; - let res = foreign::build_coinbase(&mut **w, keychain_mask, &block_fees, false)?; - res + foreign::build_coinbase(&mut **w, keychain_mask, &block_fees, false)? }; - add_block_with_reward(chain, txs, coinbase_tx.clone()); + add_block_with_reward(chain, txs, coinbase_tx.output, coinbase_tx.kernel); Ok(()) } diff --git a/libwallet/src/api_impl/types.rs b/libwallet/src/api_impl/types.rs index 07e7f0afe..9b498e617 100644 --- a/libwallet/src/api_impl/types.rs +++ b/libwallet/src/api_impl/types.rs @@ -14,7 +14,6 @@ //! Types specific to the wallet api, mostly argument serialization -use crate::grin_core::core::{Output, TxKernel}; use crate::grin_core::libtx::secp_ser; use crate::grin_keychain::Identifier; use crate::grin_util::secp::pedersen; @@ -179,17 +178,6 @@ impl BlockFees { } } -/// Response to build a coinbase output. -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CbData { - /// Output - pub output: Output, - /// Kernel - pub kernel: TxKernel, - /// Key Id - pub key_id: Option, -} - /// Map Outputdata to commits #[derive(Serialize, Deserialize, Debug, Clone)] pub struct OutputCommitMapping { diff --git a/libwallet/src/lib.rs b/libwallet/src/lib.rs index d605ab071..9e6fb7958 100644 --- a/libwallet/src/lib.rs +++ b/libwallet/src/lib.rs @@ -53,15 +53,16 @@ mod types; pub use crate::error::{Error, ErrorKind}; pub use crate::slate::{ParticipantData, ParticipantMessageData, Slate}; pub use crate::slate_versions::{ - SlateVersion, VersionedSlate, CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION, + SlateVersion, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION, + GRIN_BLOCK_HEADER_VERSION, }; pub use api_impl::types::{ - BlockFees, CbData, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, NodeHeightResult, + BlockFees, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, NodeHeightResult, OutputCommitMapping, SendTXArgs, VersionInfo, }; pub use internal::restore::{check_repair, restore}; pub use types::{ - AcctPathMapping, BlockIdentifier, Context, NodeClient, NodeVersionInfo, OutputData, + AcctPathMapping, BlockIdentifier, CbData, Context, NodeClient, NodeVersionInfo, OutputData, OutputStatus, TxLogEntry, TxLogEntryType, TxWrapper, WalletBackend, WalletInfo, WalletInst, WalletLCProvider, WalletOutputBatch, }; diff --git a/libwallet/src/slate.rs b/libwallet/src/slate.rs index a3ddd92bc..b12d7a36e 100644 --- a/libwallet/src/slate.rs +++ b/libwallet/src/slate.rs @@ -39,10 +39,11 @@ use std::sync::Arc; use uuid::Uuid; use crate::slate_versions::v2::{ - InputV2, OutputV2, ParticipantDataV2, SlateV2, TransactionBodyV2, TransactionV2, TxKernelV2, - VersionCompatInfoV2, + CoinbaseV2, InputV2, OutputV2, ParticipantDataV2, SlateV2, TransactionBodyV2, TransactionV2, + TxKernelV2, VersionCompatInfoV2, }; use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION}; +use crate::types::CbData; /// Public data for each participant in the slate #[derive(Serialize, Deserialize, Debug, Clone)] @@ -711,6 +712,17 @@ impl SlateVersionProbe { } } +// Coinbase data to versioned. +impl From for CoinbaseV2 { + fn from(cb: CbData) -> CoinbaseV2 { + CoinbaseV2 { + output: OutputV2::from(&cb.output), + kernel: TxKernelV2::from(&cb.kernel), + key_id: cb.key_id, + } + } +} + // Current slate version to versioned conversions // Slate to versioned diff --git a/libwallet/src/slate_versions/mod.rs b/libwallet/src/slate_versions/mod.rs index 76484cf99..c6c33dfc4 100644 --- a/libwallet/src/slate_versions/mod.rs +++ b/libwallet/src/slate_versions/mod.rs @@ -18,7 +18,8 @@ //! remains for future needs use crate::slate::Slate; -use crate::slate_versions::v2::SlateV2; +use crate::slate_versions::v2::{CoinbaseV2, SlateV2}; +use crate::types::CbData; #[allow(missing_docs)] pub mod v2; @@ -85,3 +86,21 @@ impl From for Slate { } } } + +#[derive(Deserialize, Serialize)] +#[serde(untagged)] +/// Versions are ordered newest to oldest so serde attempts to +/// deserialize newer versions first, then falls back to older versions. +pub enum VersionedCoinbase { + /// Current supported coinbase version. + V2(CoinbaseV2), +} + +impl VersionedCoinbase { + /// convert this coinbase data to a specific versioned representation for the json api. + pub fn into_version(cb: CbData, version: SlateVersion) -> VersionedCoinbase { + match version { + SlateVersion::V2 => VersionedCoinbase::V2(cb.into()), + } + } +} diff --git a/libwallet/src/slate_versions/v2.rs b/libwallet/src/slate_versions/v2.rs index 2c5832f8e..f62536da4 100644 --- a/libwallet/src/slate_versions/v2.rs +++ b/libwallet/src/slate_versions/v2.rs @@ -37,7 +37,7 @@ use crate::grin_core::core::transaction::OutputFeatures; use crate::grin_core::libtx::secp_ser; -use crate::grin_keychain::BlindingFactor; +use crate::grin_keychain::{BlindingFactor, Identifier}; use crate::grin_util::secp; use crate::grin_util::secp::key::PublicKey; use crate::grin_util::secp::pedersen::{Commitment, RangeProof}; @@ -184,3 +184,14 @@ pub struct TxKernelV2 { #[serde(with = "secp_ser::sig_serde")] pub excess_sig: secp::Signature, } + +/// A mining node requests new coinbase via the foreign api every time a new candidate block is built. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct CoinbaseV2 { + /// Output + pub output: OutputV2, + /// Kernel + pub kernel: TxKernelV2, + /// Key Id + pub key_id: Option, +} diff --git a/libwallet/src/types.rs b/libwallet/src/types.rs index 5102713c0..d05e7150c 100644 --- a/libwallet/src/types.rs +++ b/libwallet/src/types.rs @@ -17,7 +17,7 @@ use crate::error::{Error, ErrorKind}; use crate::grin_core::core::hash::Hash; -use crate::grin_core::core::Transaction; +use crate::grin_core::core::{Output, Transaction, TxKernel}; use crate::grin_core::libtx::{aggsig, secp_ser}; use crate::grin_core::{global, ser}; use crate::grin_keychain::{Identifier, Keychain}; @@ -809,3 +809,16 @@ pub struct TxWrapper { /// hex representation of transaction pub tx_hex: String, } + +/// Wrapper for reward output and kernel used when building a coinbase for a mining node. +/// Note: Not serializable, must be converted to necesssary "versioned" representation +/// before serializing to json to ensure compatibility with mining node. +#[derive(Debug, Clone)] +pub struct CbData { + /// Output + pub output: Output, + /// Kernel + pub kernel: TxKernel, + /// Key Id + pub key_id: Option, +}