diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index 377795ea8..76fcd045f 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -80,7 +80,7 @@ fn mine_empty_chain() { for n in 1..4 { let prev = chain.head_header().unwrap(); let pk = keychain.derive_pubkey(n as u32).unwrap(); - let mut b = core::core::Block::new(&prev, vec![], &keychain, pk).unwrap(); + let mut b = core::core::Block::new(&prev, vec![], &keychain, &pk).unwrap(); b.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -251,7 +251,7 @@ fn prepare_block_nosum(prev: &BlockHeader, diff: u64) -> Block { let keychain = Keychain::from_random_seed().unwrap(); let pubkey = keychain.derive_pubkey(1).unwrap(); - let mut b = core::core::Block::new(prev, vec![], &keychain, pubkey).unwrap(); + let mut b = core::core::Block::new(prev, vec![], &keychain, &pubkey).unwrap(); b.header.timestamp = prev.timestamp + time::Duration::seconds(60); b.header.total_difficulty = Difficulty::from_num(diff); b diff --git a/chain/tests/store_indices.rs b/chain/tests/store_indices.rs index c8ddc60d0..9457a4777 100644 --- a/chain/tests/store_indices.rs +++ b/chain/tests/store_indices.rs @@ -39,7 +39,7 @@ fn test_various_store_indices() { let chain_store = &chain::store::ChainKVStore::new(".grin".to_string()).unwrap() as &ChainStore; - let block = Block::new(&BlockHeader::default(), vec![], &keychain, pubkey).unwrap(); + let block = Block::new(&BlockHeader::default(), vec![], &keychain, &pubkey).unwrap(); let commit = block.outputs[0].commitment(); let block_hash = block.hash(); diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index fd70a95cb..3f3b7cf61 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -76,7 +76,7 @@ fn test_coinbase_maturity() { let pk3 = keychain.derive_pubkey(3).unwrap(); let pk4 = keychain.derive_pubkey(4).unwrap(); - let mut block = core::core::Block::new(&prev, vec![], &keychain, pk1.clone()).unwrap(); + let mut block = core::core::Block::new(&prev, vec![], &keychain, &pk1).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -109,8 +109,7 @@ fn test_coinbase_maturity() { &keychain, ).unwrap(); - let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk3.clone()) - .unwrap(); + let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &pk3).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -138,7 +137,7 @@ fn test_coinbase_maturity() { let keychain = Keychain::from_random_seed().unwrap(); let pk = keychain.derive_pubkey(1).unwrap(); - let mut block = core::core::Block::new(&prev, vec![], &keychain, pk).unwrap(); + let mut block = core::core::Block::new(&prev, vec![], &keychain, &pk).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -157,7 +156,7 @@ fn test_coinbase_maturity() { let prev = chain.head_header().unwrap(); - let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk4).unwrap(); + let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &pk4).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 769c03cc7..c14c7643b 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -266,7 +266,7 @@ impl Block { prev: &BlockHeader, txs: Vec<&Transaction>, keychain: &keychain::Keychain, - pubkey: keychain::Identifier, + pubkey: &keychain::Identifier, ) -> Result { let fees = txs.iter().map(|tx| tx.fee).sum(); @@ -469,11 +469,18 @@ impl Block { // * That the sum of blinding factors for all coinbase-marked outputs match // the coinbase-marked kernels. fn verify_coinbase(&self, secp: &Secp256k1) -> Result<(), Error> { - let cb_outs = filter_map_vec!(self.outputs, |out| { - if out.features.contains(COINBASE_OUTPUT) { Some(out.commitment()) } else { None } + let cb_outs = filter_map_vec!(self.outputs, |out| if out.features.contains( + COINBASE_OUTPUT, + ) + { + Some(out.commitment()) + } else { + None }); - let cb_kerns = filter_map_vec!(self.kernels, |k| { - if k.features.contains(COINBASE_KERNEL) { Some(k.excess) } else { None } + let cb_kerns = filter_map_vec!(self.kernels, |k| if k.features.contains(COINBASE_KERNEL) { + Some(k.excess) + } else { + None }); let over_commit = secp.commit_value(reward(self.total_fees()))?; @@ -490,16 +497,15 @@ impl Block { /// reward. pub fn reward_output( keychain: &keychain::Keychain, - pubkey: keychain::Identifier, + pubkey: &keychain::Identifier, fees: u64, ) -> Result<(Output, TxKernel), keychain::Error> { - let secp = keychain.secp(); - let commit = keychain.commit(reward(fees), &pubkey)?; + let commit = keychain.commit(reward(fees), pubkey)?; // let switch_commit = keychain.switch_commit(pubkey)?; let msg = secp::pedersen::ProofMessage::empty(); - let rproof = keychain.range_proof(reward(fees), &pubkey, commit, msg)?; + let rproof = keychain.range_proof(reward(fees), pubkey, commit, msg)?; let output = Output { features: COINBASE_OUTPUT, @@ -540,7 +546,7 @@ mod test { // header fn new_block(txs: Vec<&Transaction>, keychain: &Keychain) -> Block { let pubkey = keychain.derive_pubkey(1).unwrap(); - Block::new(&BlockHeader::default(), txs, keychain, pubkey).unwrap() + Block::new(&BlockHeader::default(), txs, keychain, &pubkey).unwrap() } // utility producing a transaction that spends an output with the provided diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 877b2b4a6..618996d47 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -329,7 +329,7 @@ mod test { let keychain = new_keychain(); let pubkey = keychain.derive_pubkey(1).unwrap(); - let b = Block::new(&BlockHeader::default(), vec![], &keychain, pubkey).unwrap(); + let b = Block::new(&BlockHeader::default(), vec![], &keychain, &pubkey).unwrap(); b.compact().validate(&keychain.secp()).unwrap(); } @@ -345,7 +345,7 @@ mod test { let mut tx1 = tx2i1o(); tx1.verify_sig(keychain.secp()).unwrap(); - let b = Block::new(&BlockHeader::default(), vec![&mut tx1], &keychain, pubkey).unwrap(); + let b = Block::new(&BlockHeader::default(), vec![&mut tx1], &keychain, &pubkey).unwrap(); b.compact().validate(keychain.secp()).unwrap(); } @@ -360,7 +360,7 @@ mod test { let mut tx2 = tx1i1o(); tx2.verify_sig(keychain.secp()).unwrap(); - let b = Block::new(&BlockHeader::default(), vec![&mut tx1, &mut tx2], &keychain, pubkey).unwrap(); + let b = Block::new(&BlockHeader::default(), vec![&mut tx1, &mut tx2], &keychain, &pubkey).unwrap(); b.validate(keychain.secp()).unwrap(); } diff --git a/core/src/ser.rs b/core/src/ser.rs index dbcd53a19..525208e94 100644 --- a/core/src/ser.rs +++ b/core/src/ser.rs @@ -22,6 +22,7 @@ use std::{error, fmt, cmp}; use std::io::{self, Write, Read}; use byteorder::{ByteOrder, ReadBytesExt, BigEndian}; +use keychain::Identifier; use secp::pedersen::Commitment; use secp::pedersen::RangeProof; use secp::constants::PEDERSEN_COMMITMENT_SIZE; @@ -285,6 +286,19 @@ impl Writeable for Commitment { } } +impl Writeable for Identifier { + fn write(&self, writer: &mut W) -> Result<(), Error> { + writer.write_fixed_bytes(self) + } +} + +impl Readable for Identifier { + fn read(reader: &mut Reader) -> Result { + let bytes = reader.read_fixed_bytes(20)?; + Ok(Identifier::from_bytes(&bytes)) + } +} + impl Writeable for RangeProof { fn write(&self, writer: &mut W) -> Result<(), Error> { writer.write_fixed_bytes(self) @@ -511,3 +525,8 @@ impl AsFixedBytes for ::secp::pedersen::Commitment { return PEDERSEN_COMMITMENT_SIZE; } } +impl AsFixedBytes for ::keychain::Identifier { + fn len(&self) -> usize { + return 20; + } +} diff --git a/grin/src/miner.rs b/grin/src/miner.rs index a14166dd4..f3b20d152 100644 --- a/grin/src/miner.rs +++ b/grin/src/miner.rs @@ -42,7 +42,7 @@ use chain; use secp; use pool; use util; -use keychain::Keychain; +use keychain::{Identifier, Keychain}; use wallet::{BlockFees, WalletReceiveRequest, CbData}; use pow::plugin::PluginMiner; @@ -431,13 +431,15 @@ impl Miner { // to prevent the wallet from generating a new HD key derivation for each // iteration, we keep the returned derivation to provide it back when // nothing has changed - let mut derivation = 0; + let mut pubkey = None; loop { + debug!("in miner loop..."); + // get the latest chain state and build a block on top of it let head = self.chain.head_header().unwrap(); let mut latest_hash = self.chain.head().unwrap().last_block_h; - let (mut b, deriv) = self.build_block(&head, derivation); + let (mut b, block_fees) = self.build_block(&head, pubkey); let mut sol = None; let mut use_async = false; @@ -500,16 +502,22 @@ impl Miner { e ); } - derivation = 0; + debug!("resetting pubkey in miner to None"); + pubkey = None; } else { - derivation = deriv; + debug!("setting pubkey in miner to pubkey from block_fees - {:?}", block_fees); + pubkey = block_fees.pubkey(); } } } /// Builds a new block with the chain head as previous and eligible /// transactions from the pool. - fn build_block(&self, head: &core::BlockHeader, deriv: u32) -> (core::Block, u32) { + fn build_block( + &self, + head: &core::BlockHeader, + pubkey: Option, + ) -> (core::Block, BlockFees) { // prepare the block header timestamp let mut now_sec = time::get_time().sec; let head_sec = head.timestamp.to_timespec().sec; @@ -529,7 +537,12 @@ impl Miner { // build the coinbase and the block itself let fees = txs.iter().map(|tx| tx.fee).sum(); - let (output, kernel, deriv) = self.get_coinbase(fees, deriv); + let block_fees = BlockFees { + fees: fees, + pubkey: pubkey, + }; + + let (output, kernel, block_fees) = self.get_coinbase(block_fees); let mut b = core::Block::with_reward(head, txs, output, kernel).unwrap(); debug!( "(Server ID: {}) Built new block with {} inputs and {} outputs, difficulty: {}", @@ -550,21 +563,28 @@ impl Miner { self.chain.set_sumtree_roots(&mut b).expect( "Error setting sum tree roots", ); - (b, deriv) + (b, block_fees) } - fn get_coinbase(&self, fees: u64, derivation: u32) -> (core::Output, core::TxKernel, u32) { + fn get_coinbase( + &self, + block_fees: BlockFees, + ) -> (core::Output, core::TxKernel, BlockFees) { if self.config.burn_reward { let keychain = Keychain::from_random_seed().unwrap(); let pubkey = keychain.derive_pubkey(1).unwrap(); - let (out, kern) = core::Block::reward_output(&keychain, pubkey, fees).unwrap(); - (out, kern, 0) + let (out, kern) = core::Block::reward_output( + &keychain, + &pubkey, + block_fees.fees + ).unwrap(); + (out, kern, block_fees) } else { let url = format!( "{}/v1/receive/coinbase", self.config.wallet_receiver_url.as_str() ); - let request = WalletReceiveRequest::Coinbase(BlockFees { fees: fees, derivation: derivation }); + let request = WalletReceiveRequest::Coinbase(block_fees.clone()); let res: CbData = api::client::post(url.as_str(), &request).expect( format!( "(Server ID: {}) Wallet receiver unreachable, could not claim reward. Is it running?", @@ -574,10 +594,18 @@ impl Miner { ); let out_bin = util::from_hex(res.output).unwrap(); let kern_bin = util::from_hex(res.kernel).unwrap(); + let pubkey_bin = util::from_hex(res.pubkey).unwrap(); let output = ser::deserialize(&mut &out_bin[..]).unwrap(); let kernel = ser::deserialize(&mut &kern_bin[..]).unwrap(); + let pubkey = ser::deserialize(&mut &pubkey_bin[..]).unwrap(); + let block_fees = BlockFees { + pubkey: Some(pubkey), + .. block_fees + }; - (output, kernel, res.derivation) + debug!("block_fees here: {:?}", block_fees); + + (output, kernel, block_fees) } } } diff --git a/keychain/Cargo.toml b/keychain/Cargo.toml index 4f5f40da5..67e898bf8 100644 --- a/keychain/Cargo.toml +++ b/keychain/Cargo.toml @@ -4,10 +4,11 @@ version = "0.1.0" authors = ["Antioch Peverell"] [dependencies] -byteorder = "1" +byteorder = "~1" blake2-rfc = "~0.2.17" rand = "~0.3" serde = "~1.0.8" serde_derive = "~1.0.8" +serde_json = "~1.0.3" grin_util = { path = "../util" } secp256k1zkp = { git = "https://github.com/mimblewimble/rust-secp256k1-zkp" } diff --git a/keychain/src/extkey.rs b/keychain/src/extkey.rs index 8d13b4f06..5f1a0f63d 100644 --- a/keychain/src/extkey.rs +++ b/keychain/src/extkey.rs @@ -15,6 +15,8 @@ use std::{error, fmt}; use std::cmp::min; +use serde::{de, ser}; + use byteorder::{ByteOrder, BigEndian}; use blake2::blake2b::blake2b; use secp::Secp256k1; @@ -75,25 +77,83 @@ impl fmt::Display for Fingerprint { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -pub struct Identifier(String); +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Identifier([u8; 20]); + +impl ser::Serialize for Identifier { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_str(&self.to_hex()) + } +} + +impl<'de> de::Deserialize<'de> for Identifier { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_u64(IdentifierVisitor) + } +} + +struct IdentifierVisitor; + +impl<'de> de::Visitor<'de> for IdentifierVisitor { + type Value = Identifier; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an identifier") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + // TODO - error handling here + let identifier = Identifier::from_hex(s).unwrap(); + Ok(identifier) + } +} impl Identifier { - fn from_bytes(bytes: &[u8]) -> Identifier { + pub fn from_bytes(bytes: &[u8]) -> Identifier { let mut identifier = [0; 20]; for i in 0..min(20, bytes.len()) { identifier[i] = bytes[i]; } - Identifier(util::to_hex(identifier.to_vec())) + Identifier(identifier) + } + + fn from_hex(hex: &str) -> Result { + // TODO - error handling, don't unwrap here + let bytes = util::from_hex(hex.to_string()).unwrap(); + Ok(Identifier::from_bytes(&bytes)) } pub fn to_hex(&self) -> String { - self.0.clone() + util::to_hex(self.0.to_vec()) } pub fn fingerprint(&self) -> Fingerprint { - let hex = &self.0[0..8]; - Fingerprint(String::from(hex)) + Fingerprint::from_bytes(&self.0) + } +} + +impl AsRef<[u8]> for Identifier { + fn as_ref(&self) -> &[u8] { + &self.0.as_ref() + } +} + +impl ::std::fmt::Debug for Identifier { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + try!(write!(f, "{}(", stringify!(Identifier))); + for i in self.0.iter().cloned() { + try!(write!(f, "{:02x}", i)); + } + write!(f, ")") } } @@ -208,6 +268,8 @@ impl ExtendedKey { #[cfg(test)] mod test { + use serde_json; + use secp::Secp256k1; use secp::key::SecretKey; use super::{ExtendedKey, Fingerprint, Identifier}; @@ -217,6 +279,29 @@ mod test { util::from_hex(hex_str.to_string()).unwrap() } + #[test] + fn test_identifier_json_ser_deser() { + let hex = "942b6c0bd43bdcb24f3edfe7fadbc77054ecc4f2"; + let identifier = Identifier::from_hex(hex).unwrap(); + + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct HasAnIdentifier { + identifier: Identifier, + } + + let has_an_identifier = HasAnIdentifier { identifier }; + + let json = serde_json::to_string(&has_an_identifier).unwrap(); + + assert_eq!( + json, + "{\"identifier\":\"942b6c0bd43bdcb24f3edfe7fadbc77054ecc4f2\"}" + ); + + let deserialized: HasAnIdentifier = serde_json::from_str(&json).unwrap(); + assert_eq!(deserialized, has_an_identifier); + } + #[test] fn extkey_from_seed() { // TODO More test vectors diff --git a/keychain/src/keychain.rs b/keychain/src/keychain.rs index daa855b0c..e9ae347cb 100644 --- a/keychain/src/keychain.rs +++ b/keychain/src/keychain.rs @@ -51,7 +51,7 @@ pub struct Keychain { } impl Keychain { - pub fn fingerprint(self) -> Fingerprint { + pub fn fingerprint(&self) -> Fingerprint { self.extkey.fingerprint.clone() } @@ -87,7 +87,19 @@ impl Keychain { return Ok(extkey.key); } } - Err(Error::KeyDerivation("cannot find one...".to_string())) + Err(Error::KeyDerivation(format!("cannot find extkey for {}", pubkey.fingerprint()))) + } + + // TODO - clean this and derived_key up, rename them? + // TODO - maybe wallet deals exclusively with pubkeys and not derivations - this leaks? + pub fn derivation_from_pubkey(&self, pubkey: &Identifier) -> Result { + for i in 1..10000 { + let extkey = self.extkey.derive(&self.secp, i)?; + if extkey.identifier() == *pubkey { + return Ok(extkey.n_child); + } + } + Err(Error::KeyDerivation(format!("cannot find extkey for {}", pubkey.fingerprint()))) } pub fn commit(&self, amount: u64, pubkey: &Identifier) -> Result { diff --git a/keychain/src/lib.rs b/keychain/src/lib.rs index aee79894f..af5b694b9 100644 --- a/keychain/src/lib.rs +++ b/keychain/src/lib.rs @@ -22,6 +22,7 @@ extern crate grin_util as util; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate serde_json; mod blind; mod extkey; diff --git a/pool/src/pool.rs b/pool/src/pool.rs index 7798e1d36..f2b98b8f2 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -908,7 +908,7 @@ mod tests { &block::BlockHeader::default(), block_transactions, &keychain, - pubkey, + &pubkey, ).unwrap(); chain_ref.apply_block(&block); @@ -1007,7 +1007,7 @@ mod tests { let keychain = Keychain::from_random_seed().unwrap(); let pubkey = keychain.derive_pubkey(1).unwrap(); - block = block::Block::new(&block::BlockHeader::default(), tx_refs, &keychain, pubkey) + block = block::Block::new(&block::BlockHeader::default(), tx_refs, &keychain, &pubkey) .unwrap(); } diff --git a/wallet/src/receiver.rs b/wallet/src/receiver.rs index 100a1f836..1c7894291 100644 --- a/wallet/src/receiver.rs +++ b/wallet/src/receiver.rs @@ -108,27 +108,35 @@ impl ApiEndpoint for WalletReceiver { match input { WalletReceiveRequest::Coinbase(cb_fees) => { debug!("Operation {} with fees {:?}", op, cb_fees); - let (out, kern, derivation) = + let (out, kern, block_fees) = receive_coinbase( &self.config, &self.keychain, - cb_fees.fees, - cb_fees.derivation, + &cb_fees, ).map_err(|e| { api::Error::Internal(format!("Error building coinbase: {:?}", e)) })?; let out_bin = ser::ser_vec(&out).map_err(|e| { - api::Error::Internal(format!("Error serializing output: {:?}", e)) - })?; + api::Error::Internal(format!("Error serializing output: {:?}", e)) + })?; let kern_bin = ser::ser_vec(&kern).map_err(|e| { + api::Error::Internal(format!("Error serializing kernel: {:?}", e)) + })?; + let pubkey_bin = match block_fees.pubkey { + Some(pubkey) => { + ser::ser_vec(&pubkey).map_err(|e| { api::Error::Internal(format!("Error serializing kernel: {:?}", e)) - })?; + })? + }, + None => vec![], + }; + Ok(CbData { output: util::to_hex(out_bin), kernel: util::to_hex(kern_bin), - derivation: derivation, + pubkey: util::to_hex(pubkey_bin), }) } _ => Err(api::Error::Argument( @@ -148,7 +156,7 @@ impl ApiEndpoint for WalletReceiver { Ok(CbData { output: String::from(""), kernel: String::from(""), - derivation: 0, + pubkey: String::from(""), }) } _ => Err(api::Error::Argument( @@ -165,33 +173,48 @@ impl ApiEndpoint for WalletReceiver { fn receive_coinbase( config: &WalletConfig, keychain: &Keychain, - fees: u64, - mut derivation: u32, -) -> Result<(Output, TxKernel, u32), Error> { - let fingerprint = keychain.clone().fingerprint(); + block_fees: &BlockFees, +) -> Result<(Output, TxKernel, BlockFees), Error> { + let fingerprint = keychain.fingerprint(); // operate within a lock on wallet data WalletData::with_wallet(&config.data_file_dir, |wallet_data| { - if derivation == 0 { - derivation = wallet_data.next_child(fingerprint.clone()); - } - let pubkey = keychain.derive_pubkey(derivation)?; + let pubkey = block_fees.pubkey(); + let (pubkey, derivation) = match pubkey { + Some(pubkey) => { + let derivation = keychain.derivation_from_pubkey(&pubkey)?; + (pubkey.clone(), derivation) + }, + None => { + let derivation = wallet_data.next_child(fingerprint.clone()); + let pubkey = keychain.derive_pubkey(derivation)?; + (pubkey, derivation) + } + }; // track the new output and return the stuff needed for reward wallet_data.add_output(OutputData { fingerprint: fingerprint.clone(), identifier: pubkey.clone(), n_child: derivation, - value: reward(fees), + value: reward(block_fees.fees), status: OutputStatus::Unconfirmed, height: 0, lock_height: 0, }); - debug!("Received coinbase and built output - {}, {}, {}", + + debug!("Received coinbase and built candidate output - {}, {}, {}", fingerprint.clone(), pubkey.fingerprint(), derivation); - let (out, kern) = Block::reward_output(&keychain, pubkey, fees)?; - Ok((out, kern, derivation)) + debug!("block_fees - {:?}", block_fees); + + let mut block_fees = block_fees.clone(); + block_fees.pubkey = Some(pubkey.clone()); + + debug!("block_fees updated - {:?}", block_fees); + + let (out, kern) = Block::reward_output(&keychain, &pubkey, block_fees.fees)?; + Ok((out, kern, block_fees)) })? } diff --git a/wallet/src/types.rs b/wallet/src/types.rs index 5dec0fd62..f93aca06c 100644 --- a/wallet/src/types.rs +++ b/wallet/src/types.rs @@ -264,7 +264,7 @@ impl WalletData { Error::WalletData(format!("Could not create {}: {}", data_file_path, e)) })?; let res_json = serde_json::to_vec_pretty(self).map_err(|e| { - Error::WalletData(format!("Error serializing wallet data.")) + Error::WalletData(format!("Error serializing wallet data: {}", e)) })?; data_file.write_all(res_json.as_slice()).map_err(|e| { Error::WalletData(format!("Error writing {}: {}", data_file_path, e)) @@ -385,7 +385,13 @@ pub enum WalletReceiveRequest { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct BlockFees { pub fees: u64, - pub derivation: u32, + pub pubkey: Option, +} + +impl BlockFees { + pub fn pubkey(&self) -> Option { + self.pubkey.clone() + } } /// Response to build a coinbase output. @@ -393,5 +399,5 @@ pub struct BlockFees { pub struct CbData { pub output: String, pub kernel: String, - pub derivation: u32, + pub pubkey: String, }