Skip to content
Permalink
Browse files

hook multisig in the ledger

  • Loading branch information...
vincenthz committed May 11, 2019
1 parent 09998a9 commit 0b8149e4efcdf26334768261fcf771fde33c3d41
@@ -9,7 +9,7 @@ use crate::message::Message;
use crate::stake::{CertificateApplyOutput, DelegationError, DelegationState, StakeDistribution};
use crate::transaction::*;
use crate::value::*;
use crate::{account, certificate, legacy, setting, stake, update, utxo};
use crate::{account, certificate, legacy, multisig, setting, stake, update, utxo};
use chain_addr::{Address, Discrimination, Kind};
use chain_core::property::{self, ChainLength as _, Message as _};
use chain_time::{Epoch, SlotDuration, TimeEra, TimeFrame, Timeline};
@@ -45,6 +45,7 @@ pub struct Ledger {
pub(crate) accounts: account::Ledger,
pub(crate) settings: setting::Settings,
pub(crate) updates: update::UpdateState,
pub(crate) multisig: multisig::Ledger,
pub(crate) delegation: DelegationState,
pub(crate) static_params: Arc<LedgerStaticParameters>,
pub(crate) date: BlockDate,
@@ -86,16 +87,19 @@ pub enum Error {
OldUtxoInvalidSignature(UtxoPointer, Output<legacy::OldAddress>, Witness),
OldUtxoInvalidPublicKey(UtxoPointer, Output<legacy::OldAddress>, Witness),
AccountInvalidSignature(account::Identifier, Witness),
MultisigInvalidSignature(multisig::Identifier, Witness),
TransactionHasNoInput,
FeeCalculationError(ValueError),
PraosActiveSlotsCoeffInvalid(ActiveSlotsCoeffError),
UtxoInputsTotal(ValueError),
UtxoOutputsTotal(ValueError),
Block0(Block0Error),
Account(account::LedgerError),
Multisig(multisig::LedgerError),
NotBalanced(Value, Value),
ZeroOutput(Output<Address>),
Delegation(DelegationError),
AccountIdentifierInvalid,
InvalidDiscrimination,
ExpectingAccountWitness,
ExpectingUtxoWitness,
@@ -130,6 +134,12 @@ impl From<account::LedgerError> for Error {
}
}

impl From<multisig::LedgerError> for Error {
fn from(e: multisig::LedgerError) -> Self {
Error::Multisig(e)
}
}

impl From<DelegationError> for Error {
fn from(e: DelegationError) -> Self {
Error::Delegation(e)
@@ -156,6 +166,7 @@ impl Ledger {
accounts: account::Ledger::new(),
settings,
updates: update::UpdateState::new(),
multisig: multisig::Ledger::new(),
delegation: DelegationState::new(),
static_params: Arc::new(static_params),
date: BlockDate::first(),
@@ -245,16 +256,19 @@ impl Ledger {
return Err(Error::Block0(Block0Error::TransactionHasWitnesses));
}
let transaction_id = authenticated_tx.transaction.hash();
let (new_utxos, new_accounts) = internal_apply_transaction_output(
ledger.utxos,
ledger.accounts,
&ledger.static_params,
&ledger_params,
&transaction_id,
&authenticated_tx.transaction.outputs,
)?;
let (new_utxos, new_accounts, new_multisig) =
internal_apply_transaction_output(
ledger.utxos,
ledger.accounts,
ledger.multisig,
&ledger.static_params,
&ledger_params,
&transaction_id,
&authenticated_tx.transaction.outputs,
)?;
ledger.utxos = new_utxos;
ledger.accounts = new_accounts;;
ledger.accounts = new_accounts;
ledger.multisig = new_multisig;
}
Message::UpdateProposal(_) => {
return Err(Error::Block0(Block0Error::HasUpdateProposal));
@@ -533,14 +547,17 @@ fn internal_apply_transaction(
ledger = input_utxo_verify(ledger, transaction_id, &utxo, witness)?
}
InputEnum::AccountInput(account_id, value) => {
ledger.accounts = input_account_verify(
let (single, multi) = input_account_verify(
ledger.accounts,
ledger.multisig,
&ledger.static_params.block0_initial_hash,
transaction_id,
&account_id,
value,
witness,
)?
)?;
ledger.accounts = single;
ledger.multisig = multi;
}
}
}
@@ -555,28 +572,31 @@ fn internal_apply_transaction(
}

// 4. add the new outputs
let (new_utxos, new_accounts) = internal_apply_transaction_output(
let (new_utxos, new_accounts, new_multisig) = internal_apply_transaction_output(
ledger.utxos,
ledger.accounts,
ledger.multisig,
&ledger.static_params,
dyn_params,
transaction_id,
outputs,
)?;
ledger.utxos = new_utxos;
ledger.accounts = new_accounts;
ledger.multisig = new_multisig;

Ok(ledger)
}

fn internal_apply_transaction_output(
mut utxos: utxo::Ledger<Address>,
mut accounts: account::Ledger,
mut multisig: multisig::Ledger,
static_params: &LedgerStaticParameters,
dyn_params: &LedgerParameters,
transaction_id: &TransactionId,
outputs: &[Output<Address>],
) -> Result<(utxo::Ledger<Address>, account::Ledger), Error> {
) -> Result<(utxo::Ledger<Address>, account::Ledger, multisig::Ledger), Error> {
let mut new_utxos = Vec::new();
for (index, output) in outputs.iter().enumerate() {
// Reject zero-valued outputs.
@@ -604,11 +624,15 @@ fn internal_apply_transaction_output(
Err(error) => return Err(error.into()),
};
}
Kind::Multisig(identifier) => {
let identifier = multisig::Identifier::from(identifier.clone());
multisig = multisig.add_value(&identifier, output.value)?;
}
}
}

utxos = utxos.add(transaction_id, &new_utxos)?;
Ok((utxos, accounts))
Ok((utxos, accounts, multisig))
}

fn input_utxo_verify(
@@ -618,7 +642,8 @@ fn input_utxo_verify(
witness: &Witness,
) -> Result<Ledger, Error> {
match witness {
Witness::Account(_) => return Err(Error::ExpectingUtxoWitness),
Witness::Account(_) => Err(Error::ExpectingUtxoWitness),
Witness::Multisig(_) => Err(Error::ExpectingUtxoWitness),
Witness::OldUtxo(xpub, signature) => {
let (old_utxos, associated_output) = ledger
.oldutxos
@@ -685,20 +710,27 @@ fn input_utxo_verify(

fn input_account_verify(
mut ledger: account::Ledger,
mut mledger: multisig::Ledger,
block0_hash: &HeaderHash,
transaction_id: &TransactionId,
account: &account::Identifier,
account: &AccountIdentifier,
value: Value,
witness: &Witness,
) -> Result<account::Ledger, Error> {
) -> Result<(account::Ledger, multisig::Ledger), Error> {
// .remove_value() check if there's enough value and if not, returns a Err.
let (new_ledger, spending_counter) = ledger.remove_value(account, value)?;
ledger = new_ledger;

match witness {
Witness::OldUtxo(_, _) => return Err(Error::ExpectingAccountWitness),
Witness::Utxo(_) => return Err(Error::ExpectingAccountWitness),
Witness::Account(sig) => {
// refine account to a single account identifier
let account = account
.to_single_account()
.ok_or(Error::AccountIdentifierInvalid)?;

let (new_ledger, spending_counter) = ledger.remove_value(&account, value)?;
ledger = new_ledger;

let tidsc = WitnessAccountData::new(block0_hash, transaction_id, &spending_counter);
let verified = sig.verify(&account.clone().into(), &tidsc);
if verified == chain_crypto::Verification::Failed {
@@ -707,7 +739,23 @@ fn input_account_verify(
witness.clone(),
));
};
Ok(ledger)
Ok((ledger, mledger))
}
Witness::Multisig(msignature) => {
// refine account to a multisig account identifier
let account = account.to_multi_account();

let (new_ledger, declaration, spending_counter) =
mledger.remove_value(&account, value)?;

let data_to_verify =
WitnessMultisigData::new(&block0_hash, &transaction_id, &spending_counter);
if msignature.verify(declaration, &data_to_verify) != true {
return Err(Error::MultisigInvalidSignature(account, witness.clone()));
}
mledger = new_ledger;

Ok((ledger, mledger))
}
}
}
@@ -1,7 +1,7 @@
use super::transaction::TransactionId;
use super::utxo::UtxoPointer;
use crate::account;
use crate::value::*;
use crate::{account, multisig};
use chain_core::mempack::{ReadBuf, ReadError, Readable};
use chain_core::property;
use chain_crypto::PublicKey;
@@ -24,8 +24,33 @@ pub enum InputType {
Account,
}

/// This is either an single account or a multisig account depending on the witness type
pub struct AccountIdentifier([u8; INPUT_PTR_SIZE]);

impl AccountIdentifier {
pub fn to_single_account(&self) -> Option<account::Identifier> {
PublicKey::from_binary(&self.0).map(|x| x.into()).ok()
}
pub fn to_multi_account(&self) -> multisig::Identifier {
multisig::Identifier::from(self.0.clone())
}

pub fn from_single_account(identifier: account::Identifier) -> Self {
let mut buf = [0u8; INPUT_PTR_SIZE];
let pk: PublicKey<account::AccountAlg> = identifier.into();
buf.copy_from_slice(pk.as_ref());
AccountIdentifier(buf)
}

pub fn from_multi_account(identifier: multisig::Identifier) -> Self {
let mut buf = [0u8; INPUT_PTR_SIZE];
buf.copy_from_slice(identifier.as_ref());
AccountIdentifier(buf)
}
}

pub enum InputEnum {
AccountInput(account::Identifier, Value),
AccountInput(AccountIdentifier, Value),
UtxoInput(UtxoPointer),
}

@@ -48,23 +73,32 @@ impl Input {
}
}

pub fn from_account(id: account::Identifier, value: Value) -> Self {
let pk: PublicKey<account::AccountAlg> = id.into();
pub fn from_account(id: AccountIdentifier, value: Value) -> Self {
let mut input_ptr = [0u8; INPUT_PTR_SIZE];
input_ptr.clone_from_slice(pk.as_ref());
input_ptr.copy_from_slice(&id.0);
Input {
index_or_account: 0xff,
value: value,
input_ptr: input_ptr,
}
}

pub fn from_account_single(id: account::Identifier, value: Value) -> Self {
let id = AccountIdentifier::from_single_account(id);
Input::from_account(id, value)
}

pub fn from_multisig_account(id: multisig::Identifier, value: Value) -> Self {
let id = AccountIdentifier::from_multi_account(id);
Input::from_account(id, value)
}

pub fn to_enum(&self) -> InputEnum {
match self.get_type() {
InputType::Account => {
let pk = PublicKey::from_binary(&self.input_ptr)
.expect("internal error in publickey type");
InputEnum::AccountInput(pk.into(), self.value)
let account_identifier = self.input_ptr.clone();
let id = AccountIdentifier(account_identifier);
InputEnum::AccountInput(id, self.value)
}
InputType::Utxo => InputEnum::UtxoInput(UtxoPointer::new(
TransactionId::from_bytes(self.input_ptr.clone()),
@@ -5,6 +5,7 @@ use crate::key::{
deserialize_public_key, deserialize_signature, serialize_public_key, serialize_signature,
AccountSecretKey, AccountSignature, SpendingPublicKey, SpendingSecretKey, SpendingSignature,
};
use crate::multisig;
use chain_core::mempack::{ReadBuf, ReadError, Readable};
use chain_core::property;
use chain_crypto::{Ed25519Bip32, PublicKey, Signature, Verification};
@@ -23,6 +24,7 @@ pub enum Witness {
PublicKey<Ed25519Bip32>,
Signature<WitnessUtxoData, Ed25519Bip32>,
),
Multisig(multisig::Witness),
}

impl PartialEq for Witness {
@@ -140,6 +142,7 @@ impl Witness {
signature.verify(public_key, &WitnessUtxoData::new(block0, transaction_id))
}
Witness::Account(_) => Verification::Failed,
Witness::Multisig(_) => Verification::Failed,
}
}
}
@@ -154,7 +157,6 @@ impl property::Serialize for Witness {

fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), Self::Error> {
use chain_core::packer::*;
//use chain_core::property::Serialize;

let mut codec = Codec::new(writer);
match self {
@@ -171,6 +173,10 @@ impl property::Serialize for Witness {
codec.put_u8(WITNESS_TAG_ACCOUNT)?;
serialize_signature(sig, codec.into_inner())
}
Witness::Multisig(msig) => {
codec.put_u8(WITNESS_TAG_MULTISIG)?;
msig.serialize(codec.into_inner())
}
}
}
}
@@ -185,6 +191,10 @@ impl Readable for Witness {
}
WITNESS_TAG_UTXO => deserialize_signature(buf).map(Witness::Utxo),
WITNESS_TAG_ACCOUNT => deserialize_signature(buf).map(Witness::Account),
WITNESS_TAG_MULTISIG => {
let msig = multisig::Witness::read(buf)?;
Ok(Witness::Multisig(msig))
}
i => Err(ReadError::UnknownTag(i as u32)),
}
}

0 comments on commit 0b8149e

Please sign in to comment.
You can’t perform that action at this time.