mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31:08 +03:00
82ed280625
* rename wallet libs * rename transaction.rs to slate.rs * rename transaction.rs to slate.rs * move some types into libwallet/types * rustfmt * rename libtransaction libtx * rename libtransaction libtx * change types.rs to file_wallet * rustfmt * rename WalletData to FileWallet * refactoring WalletBackend types out * rustfmt * All compiling, at least * rustfmt * fix FileWallet paths to persist * rustfmt * re-ignore wallet integration test
206 lines
6.3 KiB
Rust
206 lines
6.3 KiB
Rust
// Copyright 2018 The Grin Developers
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! tests for transactions building within libtx
|
|
extern crate grin_chain as chain;
|
|
extern crate grin_core as core;
|
|
extern crate grin_keychain as keychain;
|
|
extern crate grin_util as util;
|
|
extern crate grin_wallet as wallet;
|
|
extern crate rand;
|
|
#[macro_use]
|
|
extern crate slog;
|
|
extern crate serde;
|
|
extern crate time;
|
|
extern crate uuid;
|
|
|
|
mod common;
|
|
|
|
use std::fs;
|
|
use std::sync::Arc;
|
|
|
|
use chain::Chain;
|
|
use chain::types::*;
|
|
use core::global::ChainTypes;
|
|
use core::{global, pow};
|
|
use util::LOGGER;
|
|
use wallet::libwallet::selection;
|
|
|
|
fn clean_output_dir(test_dir: &str) {
|
|
let _ = fs::remove_dir_all(test_dir);
|
|
}
|
|
|
|
fn setup(test_dir: &str, chain_dir: &str) -> Chain {
|
|
util::init_test_logger();
|
|
clean_output_dir(test_dir);
|
|
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
|
let genesis_block = pow::mine_genesis_block().unwrap();
|
|
let dir_name = format!("{}/{}", test_dir, chain_dir);
|
|
chain::Chain::init(
|
|
dir_name.to_string(),
|
|
Arc::new(NoopAdapter {}),
|
|
genesis_block,
|
|
pow::verify_size,
|
|
).unwrap()
|
|
}
|
|
|
|
/// Build and test new version of sending API
|
|
#[test]
|
|
fn build_transaction() {
|
|
let chain = setup("test_output", "build_transaction_2/.grin");
|
|
let mut wallet1 = common::create_wallet("test_output/build_transaction_2/wallet1");
|
|
let mut wallet2 = common::create_wallet("test_output/build_transaction_2/wallet2");
|
|
common::award_blocks_to_wallet(&chain, &mut wallet1, 10);
|
|
// Wallet 1 has 600 Grins, wallet 2 has 0. Create a transaction that sends
|
|
// 300 Grins from wallet 1 to wallet 2, using libtx
|
|
|
|
// Get lock height
|
|
let chain_tip = chain.head().unwrap();
|
|
let amount = 300_000_000_000;
|
|
let min_confirmations = 3;
|
|
|
|
// ensure outputs we're selecting are up to date
|
|
let res = common::refresh_output_state_local(&mut wallet1, &chain);
|
|
|
|
if let Err(e) = res {
|
|
panic!("Unable to refresh sender wallet outputs: {}", e);
|
|
}
|
|
|
|
// TRANSACTION WORKFLOW STARTS HERE
|
|
// Sender selects outputs into a new slate and save our corresponding IDs in
|
|
// a transaction context. The secret key in our transaction context will be
|
|
// randomly selected. This returns the public slate, and a closure that locks
|
|
// our inputs and outputs once we're convinced the transaction exchange went
|
|
// according to plan
|
|
// This function is just a big helper to do all of that, in theory
|
|
// this process can be split up in any way
|
|
let (mut slate, mut sender_context, sender_lock_fn) = selection::build_send_tx_slate(
|
|
&mut wallet1,
|
|
2,
|
|
amount,
|
|
chain_tip.height,
|
|
min_confirmations,
|
|
chain_tip.height,
|
|
1000,
|
|
true,
|
|
).unwrap();
|
|
|
|
// Generate a kernel offset and subtract from our context's secret key. Store
|
|
// the offset in the slate's transaction kernel, and adds our public key
|
|
// information to the slate
|
|
let _ = slate
|
|
.fill_round_1(
|
|
&wallet1.keychain,
|
|
&mut sender_context.sec_key,
|
|
&sender_context.sec_nonce,
|
|
0,
|
|
)
|
|
.unwrap();
|
|
|
|
debug!(LOGGER, "Transaction Slate after step 1: sender initiation");
|
|
debug!(LOGGER, "-----------------------------------------");
|
|
debug!(LOGGER, "{:?}", slate);
|
|
|
|
// Now, just like the sender did, recipient is going to select a target output,
|
|
// add it to the transaction, and keep track of the corresponding wallet
|
|
// Identifier Again, this is a helper to do that, which returns a closure that
|
|
// creates the output when we're satisified the process was successful
|
|
let (_, mut recp_context, receiver_create_fn) =
|
|
selection::build_recipient_output_with_slate(&mut wallet2, &mut slate).unwrap();
|
|
|
|
let _ = slate
|
|
.fill_round_1(
|
|
&wallet2.keychain,
|
|
&mut recp_context.sec_key,
|
|
&recp_context.sec_nonce,
|
|
1,
|
|
)
|
|
.unwrap();
|
|
|
|
// recipient can proceed to round 2 now
|
|
let _ = receiver_create_fn(&mut wallet2);
|
|
|
|
let _ = slate
|
|
.fill_round_2(
|
|
&wallet1.keychain,
|
|
&recp_context.sec_key,
|
|
&recp_context.sec_nonce,
|
|
1,
|
|
)
|
|
.unwrap();
|
|
|
|
debug!(
|
|
LOGGER,
|
|
"Transaction Slate after step 2: receiver initiation"
|
|
);
|
|
debug!(LOGGER, "-----------------------------------------");
|
|
debug!(LOGGER, "{:?}", slate);
|
|
|
|
// SENDER Part 3: Sender confirmation
|
|
let _ = slate
|
|
.fill_round_2(
|
|
&wallet1.keychain,
|
|
&sender_context.sec_key,
|
|
&sender_context.sec_nonce,
|
|
0,
|
|
)
|
|
.unwrap();
|
|
|
|
debug!(LOGGER, "PartialTx after step 3: sender confirmation");
|
|
debug!(LOGGER, "--------------------------------------------");
|
|
debug!(LOGGER, "{:?}", slate);
|
|
|
|
// Final transaction can be built by anyone at this stage
|
|
let res = slate.finalize(&wallet1.keychain);
|
|
|
|
if let Err(e) = res {
|
|
panic!("Error creating final tx: {:?}", e);
|
|
}
|
|
|
|
debug!(LOGGER, "Final transaction is:");
|
|
debug!(LOGGER, "--------------------------------------------");
|
|
debug!(LOGGER, "{:?}", slate.tx);
|
|
|
|
// All okay, lock sender's outputs
|
|
let _ = sender_lock_fn(&mut wallet1);
|
|
|
|
// Insert this transaction into a new block, then mine till confirmation
|
|
common::award_block_to_wallet(&chain, vec![&slate.tx], &mut wallet1);
|
|
common::award_blocks_to_wallet(&chain, &mut wallet1, 5);
|
|
|
|
// Refresh wallets
|
|
let res = common::refresh_output_state_local(&mut wallet2, &chain);
|
|
if let Err(e) = res {
|
|
panic!("Error refreshing output state for wallet: {:?}", e);
|
|
}
|
|
|
|
// check recipient wallet
|
|
let chain_tip = chain.head().unwrap();
|
|
let balances = common::get_wallet_balances(&mut wallet2, chain_tip.height).unwrap();
|
|
|
|
assert_eq!(balances.3, 300_000_000_000);
|
|
|
|
// check sender wallet
|
|
let res = common::refresh_output_state_local(&mut wallet1, &chain);
|
|
if let Err(e) = res {
|
|
panic!("Error refreshing output state for wallet: {:?}", e);
|
|
}
|
|
let balances = common::get_wallet_balances(&mut wallet1, chain_tip.height).unwrap();
|
|
println!("tip height: {:?}", chain_tip.height);
|
|
println!("Sender balances: {:?}", balances);
|
|
// num blocks * grins per block, and wallet1 mined the fee
|
|
assert_eq!(
|
|
balances.3,
|
|
(chain_tip.height - min_confirmations) * 60_000_000_000 - amount
|
|
);
|
|
}
|