mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
merge staging
This commit is contained in:
@@ -1239,7 +1239,7 @@ pub trait OwnerRpc {
|
|||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"sigs": [],
|
"sigs": [],
|
||||||
"sta": "S3",
|
"sta": "S3",
|
||||||
"ver": "4:3"
|
"ver": "4:5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3140,7 +3140,7 @@ macro_rules! doctest_helper_json_rpc_owner_assert_response {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::libwallet::{SlatepackArmor, VersionedBinSlate};
|
use crate::libwallet::{SlatepackArmor, VersionedBinSlate, GRIN_BLOCK_HEADER_VERSION};
|
||||||
use grin_wallet_util::byte_ser;
|
use grin_wallet_util::byte_ser;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
@@ -3186,7 +3186,10 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(response["result"]["Ok"]["ver"], "5:3");
|
assert_eq!(
|
||||||
|
response["result"]["Ok"]["ver"],
|
||||||
|
format!("5:{}", GRIN_BLOCK_HEADER_VERSION)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -842,6 +842,25 @@ where
|
|||||||
args.input_file,
|
args.input_file,
|
||||||
args.input_slatepack_message,
|
args.input_slatepack_message,
|
||||||
)?;
|
)?;
|
||||||
|
match slate.state {
|
||||||
|
SlateState::Invoice1 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'pay' command to process this invoice transaction".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SlateState::Standard2 | SlateState::Invoice2 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'finalize' command to complete this transaction".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SlateState::Standard3 | SlateState::Invoice3 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'post' command to post this finalized transaction to the chain"
|
||||||
|
.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
let km = match keychain_mask.as_ref() {
|
let km = match keychain_mask.as_ref() {
|
||||||
None => None,
|
None => None,
|
||||||
@@ -1005,6 +1024,25 @@ where
|
|||||||
args.input_file.clone(),
|
args.input_file.clone(),
|
||||||
args.input_slatepack_message.clone(),
|
args.input_slatepack_message.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
match slate.state {
|
||||||
|
SlateState::Standard1 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'receive' command on the recipient's wallet first".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SlateState::Invoice1 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'pay' command on the payer's wallet first".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SlateState::Standard3 | SlateState::Invoice3 => {
|
||||||
|
return Err(Error::GenericError(
|
||||||
|
"Use the 'post' command to post this finalized transaction to the chain"
|
||||||
|
.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Rather than duplicating the entire command, we'll just
|
// Rather than duplicating the entire command, we'll just
|
||||||
// try to determine what kind of finalization this is
|
// try to determine what kind of finalization this is
|
||||||
|
|||||||
@@ -66,22 +66,18 @@ lazy_static! {
|
|||||||
|
|
||||||
fn check_middleware(
|
fn check_middleware(
|
||||||
name: ForeignCheckMiddlewareFn,
|
name: ForeignCheckMiddlewareFn,
|
||||||
node_version_info: Option<NodeVersionInfo>,
|
_node_version_info: Option<NodeVersionInfo>,
|
||||||
slate: Option<&Slate>,
|
slate: Option<&Slate>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match name {
|
match name {
|
||||||
// allow coinbases to be built regardless
|
// allow coinbases to be built regardless
|
||||||
ForeignCheckMiddlewareFn::BuildCoinbase => Ok(()),
|
ForeignCheckMiddlewareFn::BuildCoinbase => Ok(()),
|
||||||
_ => {
|
_ => {
|
||||||
let mut bhv = 3;
|
|
||||||
if let Some(n) = node_version_info {
|
|
||||||
bhv = n.block_header_version;
|
|
||||||
}
|
|
||||||
if let Some(s) = slate {
|
if let Some(s) = slate {
|
||||||
if bhv > 4 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION {
|
if s.version_info.block_header_version > GRIN_BLOCK_HEADER_VERSION {
|
||||||
Err(Error::Compatibility(
|
Err(Error::Compatibility(
|
||||||
"Incoming Slate is not compatible with this wallet. \
|
"Incoming Slate is not compatible with this wallet. \
|
||||||
Please upgrade the node or use a different one."
|
Please upgrade the wallet."
|
||||||
.into(),
|
.into(),
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,11 @@ use crate::core::core::{self, amount_to_hr_string, Inputs, OutputFeatures};
|
|||||||
use crate::core::global;
|
use crate::core::global;
|
||||||
use crate::libwallet::contract::types::{ContractView, OwnCommitmentStatus};
|
use crate::libwallet::contract::types::{ContractView, OwnCommitmentStatus};
|
||||||
use crate::libwallet::{
|
use crate::libwallet::{
|
||||||
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, Slate, TxLogEntry, ViewWallet,
|
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, Slate, SlatepackAddress, TxLogEntry,
|
||||||
WalletInfo,
|
ViewWallet, WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::util::secp::pedersen::Commitment;
|
use crate::util::secp::pedersen::Commitment;
|
||||||
use crate::util::ToHex;
|
use crate::util::ToHex;
|
||||||
use grin_wallet_util::OnionV3Address;
|
|
||||||
use prettytable;
|
use prettytable;
|
||||||
use std::io::prelude::Write;
|
use std::io::prelude::Write;
|
||||||
use term;
|
use term;
|
||||||
@@ -615,7 +614,7 @@ pub fn payment_proof(tx: &TxLogEntry) -> Result<(), Error> {
|
|||||||
writeln!(
|
writeln!(
|
||||||
t,
|
t,
|
||||||
"Receiver Address: {}",
|
"Receiver Address: {}",
|
||||||
OnionV3Address::from_bytes(pp.receiver_address.to_bytes())
|
SlatepackAddress::new(&pp.receiver_address)
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(t, "Receiver Signature: {}", receiver_signature).unwrap();
|
writeln!(t, "Receiver Signature: {}", receiver_signature).unwrap();
|
||||||
@@ -624,7 +623,7 @@ pub fn payment_proof(tx: &TxLogEntry) -> Result<(), Error> {
|
|||||||
writeln!(
|
writeln!(
|
||||||
t,
|
t,
|
||||||
"Sender Address: {}",
|
"Sender Address: {}",
|
||||||
OnionV3Address::from_bytes(pp.sender_address.to_bytes())
|
SlatepackAddress::new(&pp.sender_address)
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(t, "Sender Signature: {}", sender_signature).unwrap();
|
writeln!(t, "Sender Signature: {}", sender_signature).unwrap();
|
||||||
|
|||||||
@@ -124,6 +124,44 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||||||
)?;
|
)?;
|
||||||
assert_eq!(slate.state, SlateState::Invoice1);
|
assert_eq!(slate.state, SlateState::Invoice1);
|
||||||
|
|
||||||
|
let receive_result = wallet::controller::foreign_single_use(
|
||||||
|
wallet1.clone(),
|
||||||
|
PathBuf::from(test_dir),
|
||||||
|
mask1_i.clone(),
|
||||||
|
|api| api.receive_tx(&slate, None, None).map(|_| ()),
|
||||||
|
);
|
||||||
|
assert_eq!(receive_result, Err(libwallet::Error::SlateState));
|
||||||
|
wallet::controller::owner_single_use(
|
||||||
|
wallet1.clone(),
|
||||||
|
mask1,
|
||||||
|
PathBuf::from(test_dir),
|
||||||
|
|api, m| {
|
||||||
|
let (_, txs) = api.retrieve_txs(m, false, None, Some(slate.id), None)?;
|
||||||
|
assert!(txs.is_empty());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// receive must reject every slate state except S1
|
||||||
|
for state in [
|
||||||
|
SlateState::Unknown,
|
||||||
|
SlateState::Standard2,
|
||||||
|
SlateState::Standard3,
|
||||||
|
SlateState::Invoice1,
|
||||||
|
SlateState::Invoice2,
|
||||||
|
SlateState::Invoice3,
|
||||||
|
] {
|
||||||
|
let mut bad_slate = slate.clone();
|
||||||
|
bad_slate.state = state.clone();
|
||||||
|
let res = wallet::controller::foreign_single_use(
|
||||||
|
wallet1.clone(),
|
||||||
|
PathBuf::from(test_dir),
|
||||||
|
mask1_i.clone(),
|
||||||
|
|api| api.receive_tx(&bad_slate, None, None).map(|_| ()),
|
||||||
|
);
|
||||||
|
assert_eq!(res, Err(libwallet::Error::SlateState), "state {}", state);
|
||||||
|
}
|
||||||
|
|
||||||
wallet::controller::owner_single_use(
|
wallet::controller::owner_single_use(
|
||||||
wallet1.clone(),
|
wallet1.clone(),
|
||||||
mask1,
|
mask1,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use grin_core as core;
|
|||||||
use self::core::core::transaction;
|
use self::core::core::transaction;
|
||||||
use self::core::core::Transaction;
|
use self::core::core::Transaction;
|
||||||
use self::core::global;
|
use self::core::global;
|
||||||
use self::libwallet::{InitTxArgs, OutputStatus, Slate, SlateState};
|
use self::libwallet::{InitTxArgs, OutputStatus, Slate, SlateState, GRIN_BLOCK_HEADER_VERSION};
|
||||||
use impls::test_framework::{self, LocalWalletClient};
|
use impls::test_framework::{self, LocalWalletClient};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -105,6 +105,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||||||
// assert wallet contents
|
// assert wallet contents
|
||||||
// and a single use api for a send command
|
// and a single use api for a send command
|
||||||
let amount = 60_000_000_000;
|
let amount = 60_000_000_000;
|
||||||
|
let header_version = core::consensus::header_version(chain.head().unwrap().height).0;
|
||||||
let mut slate = Slate::blank(1, false);
|
let mut slate = Slate::blank(1, false);
|
||||||
wallet::controller::owner_single_use(
|
wallet::controller::owner_single_use(
|
||||||
wallet1.clone(),
|
wallet1.clone(),
|
||||||
@@ -124,6 +125,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||||
|
|
||||||
assert_eq!(slate_i.state, SlateState::Standard1);
|
assert_eq!(slate_i.state, SlateState::Standard1);
|
||||||
|
assert_eq!(slate_i.version_info.block_header_version, header_version);
|
||||||
|
|
||||||
// Check we are creating a tx with the expected lock_height of 0.
|
// Check we are creating a tx with the expected lock_height of 0.
|
||||||
// We will check this produces a Plain kernel later.
|
// We will check this produces a Plain kernel later.
|
||||||
@@ -131,6 +133,26 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||||||
|
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
assert_eq!(slate.state, SlateState::Standard2);
|
assert_eq!(slate.state, SlateState::Standard2);
|
||||||
|
|
||||||
|
// wallet2 already has this slate, so accepted versions fail on the duplicate check
|
||||||
|
for bhv in 1..=GRIN_BLOCK_HEADER_VERSION + 1 {
|
||||||
|
let mut s = slate_i.clone();
|
||||||
|
s.version_info.block_header_version = bhv;
|
||||||
|
let res = wallet::controller::foreign_single_use(
|
||||||
|
wallet2.clone(),
|
||||||
|
PathBuf::from(test_dir),
|
||||||
|
mask2_i.clone(),
|
||||||
|
|api| api.receive_tx(&s, None, None).map(|_| ()),
|
||||||
|
);
|
||||||
|
if bhv <= GRIN_BLOCK_HEADER_VERSION {
|
||||||
|
assert!(matches!(
|
||||||
|
res,
|
||||||
|
Err(libwallet::Error::TransactionAlreadyReceived(_))
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
assert!(matches!(res, Err(libwallet::Error::Compatibility(_))));
|
||||||
|
}
|
||||||
|
}
|
||||||
sender_api.tx_lock_outputs(m, &slate)?;
|
sender_api.tx_lock_outputs(m, &slate)?;
|
||||||
slate = sender_api.finalize_tx(m, &slate)?;
|
slate = sender_api.finalize_tx(m, &slate)?;
|
||||||
assert_eq!(slate.state, SlateState::Standard3);
|
assert_eq!(slate.state, SlateState::Standard3);
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ where
|
|||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut ret_slate = slate.clone();
|
let mut ret_slate = slate.clone();
|
||||||
|
if ret_slate.state != SlateState::Standard1 {
|
||||||
|
return Err(Error::SlateState);
|
||||||
|
}
|
||||||
check_ttl(w, &ret_slate)?;
|
check_ttl(w, &ret_slate)?;
|
||||||
let parent_key_id = match dest_acct_name {
|
let parent_key_id = match dest_acct_name {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use crate::contract::types::ContractSetupArgsAPI;
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::grin_keychain::Keychain;
|
use crate::grin_keychain::Keychain;
|
||||||
use crate::grin_util::secp::key::SecretKey;
|
use crate::grin_util::secp::key::SecretKey;
|
||||||
|
use crate::internal::tx;
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
use crate::types::{Context, NodeClient};
|
use crate::types::{Context, NodeClient};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -65,11 +66,15 @@ where
|
|||||||
let net_change = setup_args.required_net_change()?;
|
let net_change = setup_args.required_net_change()?;
|
||||||
debug!("contract::new => net_change passed: {}", net_change);
|
debug!("contract::new => net_change passed: {}", net_change);
|
||||||
|
|
||||||
// Initialize a new contract (if net_change is positive, I'm the receiver meaning this is invoice flow)
|
// invoice flow if net_change is positive
|
||||||
let num_participants = setup_args.num_participants;
|
let mut slate = tx::new_tx_slate(
|
||||||
let mut slate = Slate::blank(num_participants, net_change > 0);
|
w,
|
||||||
// Contracts start with V4 and move to V5 when their proof data requires it
|
net_change.unsigned_abs(),
|
||||||
slate.version_info.version = 4;
|
net_change > 0,
|
||||||
|
setup_args.num_participants,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
// Use a caller-supplied id when given, so a retried creation reuses the same context.
|
// Use a caller-supplied id when given, so a retried creation reuses the same context.
|
||||||
let mut existing_context = None;
|
let mut existing_context = None;
|
||||||
if let Some(id) = slate_id {
|
if let Some(id) = slate_id {
|
||||||
@@ -96,9 +101,6 @@ where
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We set slate.amount to contain the _positive_ net_change for the other party so they can derive expectations.
|
|
||||||
// unsigned_abs avoids the i64::MIN overflow panic of abs().
|
|
||||||
slate.amount = net_change.unsigned_abs();
|
|
||||||
debug!("contract::new => slate amount: {}", slate.amount);
|
debug!("contract::new => slate amount: {}", slate.amount);
|
||||||
|
|
||||||
// Perform setup for the slate
|
// Perform setup for the slate
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::grin_core::consensus::valid_header_version;
|
use crate::grin_core::consensus::header_version;
|
||||||
use crate::grin_core::core::HeaderVersion;
|
|
||||||
use crate::grin_keychain::{Identifier, Keychain};
|
use crate::grin_keychain::{Identifier, Keychain};
|
||||||
use crate::grin_util::secp::key::SecretKey;
|
use crate::grin_util::secp::key::SecretKey;
|
||||||
use crate::grin_util::secp::pedersen;
|
use crate::grin_util::secp::pedersen;
|
||||||
@@ -72,17 +71,7 @@ where
|
|||||||
}
|
}
|
||||||
slate.amount = amount;
|
slate.amount = amount;
|
||||||
|
|
||||||
if valid_header_version(current_height, HeaderVersion(1)) {
|
slate.version_info.block_header_version = header_version(current_height).0;
|
||||||
slate.version_info.block_header_version = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if valid_header_version(current_height, HeaderVersion(2)) {
|
|
||||||
slate.version_info.block_header_version = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if valid_header_version(current_height, HeaderVersion(3)) {
|
|
||||||
slate.version_info.block_header_version = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the features explicitly to 0 here.
|
// Set the features explicitly to 0 here.
|
||||||
// This will generate a Plain kernel (rather than a HeightLocked kernel).
|
// This will generate a Plain kernel (rather than a HeightLocked kernel).
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ pub mod v5_bin;
|
|||||||
/// The most recent version of the slate
|
/// The most recent version of the slate
|
||||||
pub const CURRENT_SLATE_VERSION: u16 = 5;
|
pub const CURRENT_SLATE_VERSION: u16 = 5;
|
||||||
|
|
||||||
/// The grin block header this slate is intended to be compatible with
|
/// The latest grin block header version this wallet supports
|
||||||
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 3;
|
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 5;
|
||||||
|
|
||||||
const HEIGHT_LOCKED_FEATURE: u8 = 2;
|
const HEIGHT_LOCKED_FEATURE: u8 = 2;
|
||||||
const NRD_FEATURE: u8 = 3;
|
const NRD_FEATURE: u8 = 3;
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ use semver::Version;
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
const MIN_COMPAT_NODE_VERSION: &str = "4.0.0-alpha.1";
|
const MIN_COMPAT_NODE_VERSION: &str = "5.0.0-beta.1";
|
||||||
|
|
||||||
pub fn wallet_command<C>(
|
pub fn wallet_command<C>(
|
||||||
wallet_args: &ArgMatches<'_>,
|
wallet_args: &ArgMatches<'_>,
|
||||||
|
|||||||
@@ -567,6 +567,22 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller::
|
|||||||
test_dir
|
test_dir
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// receive and finalize should point to pay
|
||||||
|
for cmd in ["receive", "finalize"] {
|
||||||
|
let arg_vec = vec![
|
||||||
|
"grin-wallet",
|
||||||
|
"-a",
|
||||||
|
"mining",
|
||||||
|
"-p",
|
||||||
|
"password1",
|
||||||
|
cmd,
|
||||||
|
"-i",
|
||||||
|
&file_name,
|
||||||
|
];
|
||||||
|
let e = execute_command(&app, test_dir, "wallet1", &client1, arg_vec).unwrap_err();
|
||||||
|
assert!(e.to_string().contains("'pay'"), "{}", e);
|
||||||
|
}
|
||||||
|
|
||||||
// now pay the invoice tx, wallet 1
|
// now pay the invoice tx, wallet 1
|
||||||
let arg_vec = vec![
|
let arg_vec = vec![
|
||||||
"grin-wallet",
|
"grin-wallet",
|
||||||
|
|||||||
Reference in New Issue
Block a user