Using the Bitcoin Crate to Sign a Segwit Transaction - rust

I'm trying to create a transaction programmatically (in Rust) that spends an output associated with a P2WPKH address. This is the relevant code snippet:
fn sign_transaction<SignFun>(
own_public_key: &[u8],
own_address: &Address,
own_utxos: &[Utxo],
mut transaction: Transaction,
key_name: String,
derivation_path: Vec<Vec<u8>>,
signer: SignFun,
) -> Transaction
where
SignFun: Fn(String, Vec<Vec<u8>>, Vec<u8>) -> Fut,
{
let txclone = transaction.clone();
let mut hash_cache = sighash::SighashCache::new(&txclone);
for (index, input) in transaction.input.iter_mut().enumerate() {
let value = get_value(input, own_utxos); // Look up the value by finding the corresponding UTXO
let sighash = hash_cache
.segwit_signature_hash(index, &own_address.script_pubkey(), value, SIG_HASH_TYPE)
.expect("Creating the segwit signature hash failed.");
let signature = signer(key_name.clone(), derivation_path.clone(), sighash.to_vec()).await;
// Convert signature to DER.
let der_signature = sec1_to_der(signature);
let mut sig_with_hashtype = der_signature;
sig_with_hashtype.push(SIG_HASH_TYPE.to_u32() as u8);
let witness_bytes = vec![sig_with_hashtype, own_public_key.to_vec()];
input.witness = Witness::from_vec(witness_bytes);
}
transaction
}
The code uses the standard bitcoin crate.
When sending a signed transaction to my local Bitcoin node in RegTest mode, I get the following error:
error code: -26
error message:
non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)
I logged the following information:
Public key:
0377f5de845ac601f24e7cbf2e4abcc9e1040cd4ae971ecaa00837b1c74684e15b
Address: bcrt1qh3zle7xs34azdyycg8cpf9wx5nxjpcqyqv4eyc
Input spent with value: 625000000
Transaction to sign: 0100000001ceac446d9350730c2a886220bed7ae154ca3f717897819091d5e72dcd0f0895e00000
00000ffffffff0200e1f505000000001600148be949ae15ee4b5da9af0ce2bf8d3f3c43c582da26
dc4a1f00000000160014bc45fcf8d08d7a26909841f01495c6a4cd20e00400000000
Sighash: d7e5696f18363b58c84b8d57014d291c9f7ebbac562d219f7e7014b9a5685bbf
SEC1 signature: c10c09b210914e49f295c07c9f96352e085df9d2c4272292239445d6f89483bc64c9903bebaba4b
bf998d217c80375c36b60b212a824b63435e30205b2ed5a6a
DER signature: 3045022100c10c09b210914e49f295c07c9f96352e085df9d2c4272292239445d6f89483bc02206
4c9903bebaba4bbf998d217c80375c36b60b212a824b63435e30205b2ed5a6a
DER signature with Sighash type: 3045022100c10c09b210914e49f295c07c9f96352e085df9d2c4272292239445d6f89483bc02206
4c9903bebaba4bbf998d217c80375c36b60b212a824b63435e30205b2ed5a6a01
Signed transaction: 01000000000101ceac446d9350730c2a886220bed7ae154ca3f717897819091d5e72dcd0f0895e0
000000000ffffffff0200e1f505000000001600148be949ae15ee4b5da9af0ce2bf8d3f3c43c582
da26dc4a1f00000000160014bc45fcf8d08d7a26909841f01495c6a4cd20e00402483045022100c
10c09b210914e49f295c07c9f96352e085df9d2c4272292239445d6f89483bc022064c9903bebab
a4bbf998d217c80375c36b60b212a824b63435e30205b2ed5a6a01210377f5de845ac601f24e7cb
f2e4abcc9e1040cd4ae971ecaa00837b1c74684e15b00000000
Note that a similar piece of code for legacy (P2PKH) transactions using the same ECDSA signer works perfectly, so I'm assuming the signer is okay.
Any help to figure out where the problem lies would be greatly appreciated!

Even when the rawtransaction is right, if you give the wrong script_pubkey, it will generate wrong sighash. Just try to make sure that you are giving the right one. Try giving p2pkh script_pubkey of your pubkey.
let public_key = PublicKey::from_slice(own_public_key).unwrap();
let script_code = bitcoin::Address::p2pkh(&public_key, bitcoin::network::constants::Network::Testnet).script_pubkey();
let sighash = hash_cache
.segwit_signature_hash(index, &script_code, value, SIG_HASH_TYPE)
.expect("Creating the segwit signature hash failed.");

Related

How to use mail filter context data?

I am trying to write a mail filter in Rust using the milter crate. I built the example on a Linux VM and it all works fine. However, the example is using u32 as the type of context injected into their handlers, a quite simple example. I instead need to store a string from the handle_header callback through to the handle_eom handler so I can use an incoming header to set the envelope from.
If I log the value of the header in handle_header to console, it writes correctly but by the time it arrives in handle_eom, it has been corrupted/overwritten whatever. I thought that context was supposed to be specifically for this scenario but it seems weird that it uses type inference rather than e.g. a pointer to an object that you can just assign whatever you want to it.
Is my understanding of context wrong or is the code incorrect?
I tried using value and &value in handle_header and it behaves the same way.
use milter::*;
fn main() {
Milter::new("inet:3000#localhost")
.name("BounceRewriteFilter")
.on_header(header_callback)
.on_eom(eom_callback)
.on_abort(abort_callback)
.actions(Actions::ADD_HEADER | Actions::REPLACE_SENDER)
.run()
.expect("milter execution failed");
}
#[on_header(header_callback)]
fn handle_header<'a>(mut context: Context<&'a str>, header: &str, value: &'a str) -> milter::Result<Status> {
if header == "Set-Return-Path" {
match context.data.borrow_mut() {
Some(retpath) => *retpath = &value,
None => {
context.data.replace(value)?;
}
}
}
Ok(Status::Continue)
}
#[on_eom(eom_callback)]
fn handle_eom(mut context: Context<&str>) -> milter::Result<Status> {
match context.data.take() {
Ok(result) => {
println!("Set-return-path header is {}", result.unwrap());
context.api.replace_sender(result.unwrap(), None::<&str>)?;
}
Err(_error) => {}
}
Ok(Status::Continue)
}
Thanks to glts on Github, the author of the crate, the problem was that the string slices passed into the handle_header method were not borrowed by the external code that stores the data pointer so by the time that handle_eom is called, the memory has been reused for something else.
All I had to do was change Context<&str> to Context<String> and convert the strings using mystr.to_owned() and in the reverse direction val = &*mystring

Changing a PDA owned token account authority fails because of privilege escalation

I am getting a privilege escalation error (Hw5dRzdcUNHahscRYr1AtsS3t6KXoxyHiGaeShjF7Wq3's signer privilege escalated) when I try to change the authority of an SPL.
Hw5dRzdcUNHahscRYr1AtsS3t6KXoxyHiGaeShjF7Wq3 is the address of the escrow_signer in the code below.
I can confirm the SPL token account is owned by the PDA, as I changed its authority in another transaction.
token::set_authority(
ctx.accounts.into(),
AuthorityType::AccountOwner,
Some(ctx.accounts.escrow_signer.key()),
)?;
pub fn terminate_escrow (ctx: Context<Terminate>) -> ProgramResult {
let seeds = &[
ctx.accounts.escrow_signer.key.as_ref(),
&[ctx.accounts.escrow_account.nonce],
];
let cpi_accounts = SetAuthority {
account_or_mint: ctx.accounts
.initializer_lp_token_account
.to_account_info()
.clone(),
current_authority: ctx.accounts.escrow_signer.clone(),
};
let cpi_program = ctx.accounts.token_program.clone();
token::set_authority(
CpiContext::new(cpi_program, cpi_accounts)
.with_signer(&[&seeds[..]]),
AuthorityType::AccountOwner,
Some(ctx.accounts.initializer.key()),
)?;
}
#[derive(Accounts)]
pub struct Terminate<'info> {
...
#[account(
seeds = [escrow_account.to_account_info().key.as_ref()],
bump = escrow_account.nonce,
)]
pub escrow_signer: AccountInfo<'info>,
}
Here is how I am creating the PDA address:
const [_escrowSigner, _nonce] = await anchor.web3.PublicKey.findProgramAddress(
[escrowAccount.publicKey.toBuffer()],
program.programId
);
Thanks for helping.
Should your seeds actually be:
let seeds = &[
ctx.accounts.escrow_account.key.as_ref(),
&[ctx.accounts.escrow_account.nonce],
];
Instead of the signer?
I wonder if they were passed the wrong way around, so that escrow_signer is actually escrow_account, which is not signing this instruction, which would explain the error.
Ensure seeds is correct
Ensure relevant account is marked as mutable (THIS is often overlooked)

How to handle errors for Not found key in Rust

I'm trying to capture errors on Rust, but I don't want the program to exit if I found it. I'm very new to Rust. Basically, I want to find a key from the Windows registry and if it doesn't exist, then create it.
Im using a crate called winreg for that.
This would be a section of my program:
fn main() -> io::Result<()> {
...
...
...
key.set_value("TestSZ", &"written by Rust")?;
// here I'm getting a value that exists
let sz_val: String = key.get_value("TestSZ")?;
// but this key doesn't exist
let other: String = key.get_value("NOT_EXISTING_KEY")?;
println!("TestSZ = {}", sz_val);
println!("TestSZ = {}", other);
Ok(())
}
If I compile that I receive this in the console:
And now lets write something...
An existing key has been opened
TestSZ = written by Rust
Error: Os { code: 2, kind: NotFound, message: "Couldn't find the pecified file." }
error: process didn't exit successfully: `target\debug\playground.exe` (exit code: 1)
In a pseudocode way, I would like something like:
if other == null {
println!("Nothing found!");
create_key();
}
If I analize get_value it looks like this:
pub fn get_value<T: FromRegValue, N: AsRef<OsStr>>(&self, name: N) -> io::Result<T>
I don't know what that means. I've been reading about errors and everything I do fails.
If I do let other: String = key.get_value("NOT_EXISTING_KEY").expect("Failed to read product name"); then the program exits, showing the error.
But I don't want the program to fail, I want to capture the error and do a different flow if I don't find the key (for example, create it).
Does anyone know how can I deal with this?
In Rust, a function that can fail usually returns a Result<OkType, ErrorType> data type. This type is a structured enum, which means, that it can tell you not only if error has occured, but also what kind of error, so you could act accordingly.
You can process enums with match statements. Or alternatively, Result type has shortcuts like Result::unwrap or Result::expect that basically say: "If there is an error, just tell me what kind and crash the program."
I'm not very familiar with Windows Registry, so I'm not sure how bulletproof the following code snippet is, but it should give you an idea on how you can process errors with a match statement.
fn main() {
// ...
let anykey_value = match key.get_value("AnyKey") {
// If the key is present, initialize `anykey_value` variable
// with the returned value
Ok(value) => value,
// If the key is not found, do the following steps:
Err(error) => {
println!("Nothing found!");
// Try to set an empty string as the value for "AnyKey".
// If fails: panic with the following message.
key.set_value("AnyKey", &"").expect("Failed to create key \"AnyKey\"");
// Initialize `anykey_value` variable with an empty string.
""
}
}
// Will print the value stored in "AnyKey"
// or an empty string, if the key was just created.
println!("AnyKey = {}", anykey_value);
// ...
}
Also you can checkout Error handling chapter from The Rust Programming Language book. It might be helpful.
I got it this way:
match key.get_value("NOT_EXISTING_KEY") {
Ok(value) => {
println!("found: {}", value);
value
},
Err(err) => {
println!("not found: {}", err);
String::from("")},
};
It was expecting a String

How to combine AccounId and the time stamp to create a new key for Storage map in Substrate

I am trying to create a new Key to store data in to a StorageMap by combining the account ID and the time stamp
Im not sure how to get a string representation of the account and concatenate the timestamp
let origin_account = ensure_signed(origin);
let time = <pallet_timestamp::Module<T>>::get();
Sounds like you want to use one of two things:
Use a tuple to represent both pieces of information as a single key:
/// Any signal messages waiting to be sent.
#[pallet::storage]
pub(super) type MyMap<T: Config> = StorageMap<
_,
Blake2_128Concat,
(T::AccountId, T::Moment), // <--- key will be a tuple of the two data
ValueType,
>;
and
let origin_account = ensure_signed(origin)?;
let time = <pallet_timestamp::Module<T>>::get();
let value = 99;
MyMap::<T>::insert((origin_account, time), value);
Or you want to use a double map, which explicitly supports two keys.
#[pallet::storage]
pub(super) type MyDoubleMap<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
T::AccountId, // <-- key 1
Blake2_128Concat,
T::Moment, // <-- key 2
ValueType,
>;
and
let origin_account = ensure_signed(origin)?;
let time = <pallet_timestamp::Module<T>>::get();
let value = 99;
MyDoubleMap::<T>::insert(origin_account, time, value);

How can I pull data out of an Option for independent use?

Is there a way to 'pull' data out of an Option? I have an API call that returns Some(HashMap). I want to use the HashMap as if it weren't inside Some and play with the data.
Based on what I've read, it looks like Some(...) is only good for match comparisons and some built-in functions.
Simple API call pulled from crate docs:
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::blocking::get("https://httpbin.org/ip")?
.json::<HashMap<String, String>>()?;
println!("{:#?}", resp.get("origin"));
Ok(())
}
Result:
Some("75.69.138.107")
if let Some(origin) = resp.get("origin") {
// use origin
}
If you can guarantee that it's impossible for the value to be None, then you can use:
let origin = resp.get("origin").unwrap();
Or:
let origin = resp.get("origin").expect("This shouldn't be possible!");
And, since your function returns a Result:
let origin = resp.get("origin").ok_or("This shouldn't be possible!")?;
Or with a custom error type:
let origin = resp.get("origin").ok_or(MyError::DoesntExist)?;
The most common way is with if let:
if let Some(origin) = resp.get("origin") {
origin.do_stuff()
}
For more fine grained control, you can use pattern matching:
match resp.get("origin") {
Some(origin) => origin.do_stuff(),
None => panic!("origin not found!")
}
You could also use unwrap, which will give you the underlying value of the option, or panic if it is None:
let origin = resp.get("origin").unwrap();
You can customize the panic message with expect:
let origin = resp.get("origin").expect("Oops!");
Or compute a default value with unwrap_or:
let origin = resp.get("origin").unwrap_or(&String::from("192.168.0.1"));
You can also return an error instead of panicking:
let origin = resp.get("origin").ok_or(Error::UnknownOrigin)?;
Your options are a plenty.
if let Some(origin) = resp.get("origin") {
// do stuff using origin
}
origin = resp.get("origin").unwrap()
// will panic if None
resp.get("origin").map(|origin| {
// do stuff using inner value, returning another option
})
resp.get("origin").and_then(|origin| {
// same as map but short-circuits if there is no inner value
})

Resources