mirror of
https://github.com/logos-co/nomos-node.git
synced 2026-08-31 03:21:15 +00:00
refactor(ledger): execute typed signed operations
- initialize ledger state from typed genesis operations - consume SignedOps during transaction verification - execute only operations in the Verified state - propagate signed operations through Mantle and SDP state transitions - expose the new transaction types through the Mantle API
This commit is contained in:
+53
-26
@@ -9,12 +9,17 @@ use crate::{
|
||||
mantle::{
|
||||
NoteId,
|
||||
channel_notes::{self, ChannelNotes},
|
||||
ledger::{self, ExecutableOperation as _},
|
||||
ops::channel::{
|
||||
ChannelId, ChannelKeyIndex, MsgId,
|
||||
config::Keys,
|
||||
inscribe::{InscriptionExecutionContext, InscriptionOp},
|
||||
ledger,
|
||||
ledger::verification_mode::GenesisMode,
|
||||
ops::{
|
||||
SignedOperation,
|
||||
channel::{
|
||||
ChannelId, ChannelKeyIndex, MsgId,
|
||||
config::Keys,
|
||||
inscribe::{InscriptionExecutionContext, InscriptionOp},
|
||||
},
|
||||
},
|
||||
transactions::states::Verified,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -133,11 +138,15 @@ impl Default for Channels {
|
||||
}
|
||||
|
||||
impl Channels {
|
||||
pub fn from_genesis(op: &InscriptionOp) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (context, events) = op.execute(InscriptionExecutionContext {
|
||||
channels: Self::default(),
|
||||
block_slot: Slot::default(),
|
||||
})?;
|
||||
pub fn from_genesis(
|
||||
signed_operation: SignedOperation<InscriptionOp, Verified, GenesisMode>,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (context, events) = signed_operation
|
||||
.execute(InscriptionExecutionContext {
|
||||
channels: Self::default(),
|
||||
block_slot: Slot::default(),
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
Ok((context.channels, events))
|
||||
}
|
||||
|
||||
@@ -233,8 +242,8 @@ impl ChannelState {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ark_ff::AdditiveGroup as _;
|
||||
use lb_groth16::Fr;
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, ZkKey};
|
||||
use lb_groth16::{CompressedGroth16Proof, Fr};
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, ZkKey, ZkSignature};
|
||||
use lb_utils::blake_rng::RngCore as _;
|
||||
use rand::thread_rng;
|
||||
|
||||
@@ -243,7 +252,7 @@ mod tests {
|
||||
events::{DepositNote, TxEventPayload},
|
||||
mantle::{
|
||||
Note, Utxo, Value,
|
||||
ledger::Utxos,
|
||||
ledger::{Utxos, verification_mode::StandardMode},
|
||||
ops::{
|
||||
OpId as _,
|
||||
channel::{
|
||||
@@ -252,8 +261,9 @@ mod tests {
|
||||
withdraw::{ChannelWithdrawOp, WithdrawExecutionContext},
|
||||
},
|
||||
},
|
||||
transactions::{GasPrices, mantle_tx::MantleTxGasContext},
|
||||
transactions::{GasPrices, tx_list::ops::OpsGasContext},
|
||||
},
|
||||
proofs::channel_multi_sig_proof::{ChannelMultiSigProof, IndexedSignatures},
|
||||
};
|
||||
|
||||
fn test_public_key(seed: u8) -> PublicKey {
|
||||
@@ -356,7 +366,7 @@ mod tests {
|
||||
channel_notes: ChannelNotes::new(),
|
||||
};
|
||||
|
||||
let gas_context = MantleTxGasContext::from_channels(&channels, GasPrices::new(0, 0));
|
||||
let gas_context = OpsGasContext::from_channels(&channels, GasPrices::new(0, 0));
|
||||
|
||||
assert_eq!(gas_context.transfer_threshold(&first_id), Some(1));
|
||||
assert_eq!(gas_context.transfer_threshold(&second_id), Some(2));
|
||||
@@ -376,10 +386,14 @@ mod tests {
|
||||
inputs: [note_id].into(),
|
||||
metadata: Metadata::empty(),
|
||||
};
|
||||
let empty_proof = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_deposit: SignedOperation<_, _, StandardMode> =
|
||||
SignedOperation::new(deposit_op, empty_proof).into_state_trusted();
|
||||
let operation = signed_deposit.operation().clone();
|
||||
|
||||
let utxo_tree = utxo_tree(vec![utxo]);
|
||||
|
||||
let (updated, events) = deposit_op
|
||||
let (updated, events) = signed_deposit
|
||||
.execute(DepositExecutionContext {
|
||||
channels,
|
||||
utxos: utxo_tree,
|
||||
@@ -389,7 +403,7 @@ mod tests {
|
||||
|
||||
// The deposited note is consumed and re-created as a channel note
|
||||
// under a new NoteId.
|
||||
let deposited = Utxo::new(deposit_op.op_id(), 0, utxo.note).id();
|
||||
let deposited = Utxo::new(operation.op_id(), 0, utxo.note).id();
|
||||
assert!(!updated.utxos.contains(¬e_id));
|
||||
assert!(!updated.channels.is_channel_note(¬e_id));
|
||||
assert!(updated.utxos.contains(&deposited));
|
||||
@@ -419,10 +433,10 @@ mod tests {
|
||||
panic!("events should include deposit event")
|
||||
};
|
||||
assert_eq!(*tx_hash, [0; 32].into());
|
||||
assert_eq!(*op_id, deposit_op.op_id());
|
||||
assert_eq!(*event_channel_id, deposit_op.channel_id);
|
||||
assert_eq!(*op_id, operation.op_id());
|
||||
assert_eq!(*event_channel_id, operation.channel_id);
|
||||
assert_eq!(*amount, utxo.note.value);
|
||||
assert_eq!(*metadata, deposit_op.metadata);
|
||||
assert_eq!(*metadata, operation.metadata);
|
||||
assert_eq!(
|
||||
notes.clone().into_inner(),
|
||||
vec![DepositNote {
|
||||
@@ -445,8 +459,12 @@ mod tests {
|
||||
inputs: [first.id(), second.id()].into(),
|
||||
metadata: Metadata::empty(),
|
||||
};
|
||||
let empty_proof = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_deposit: SignedOperation<_, _, StandardMode> =
|
||||
SignedOperation::new(deposit_op, empty_proof).into_state_trusted();
|
||||
let op_id = signed_deposit.operation().op_id();
|
||||
|
||||
let (updated, _) = deposit_op
|
||||
let (updated, _) = signed_deposit
|
||||
.execute(DepositExecutionContext {
|
||||
channels: Channels::new(),
|
||||
utxos: utxo_tree(vec![first, second]),
|
||||
@@ -456,8 +474,8 @@ mod tests {
|
||||
|
||||
// Each input is re-created at its own output index, so the two notes
|
||||
// get distinct identifiers even though they share an OpId.
|
||||
let first_deposited = Utxo::new(deposit_op.op_id(), 0, first.note).id();
|
||||
let second_deposited = Utxo::new(deposit_op.op_id(), 1, second.note).id();
|
||||
let first_deposited = Utxo::new(op_id, 0, first.note).id();
|
||||
let second_deposited = Utxo::new(op_id, 1, second.note).id();
|
||||
assert_ne!(first_deposited, second_deposited);
|
||||
|
||||
assert!(!updated.utxos.contains(&first.id()));
|
||||
@@ -485,8 +503,11 @@ mod tests {
|
||||
channel_id,
|
||||
inputs: [note_id].into(),
|
||||
};
|
||||
let empty_proof = ChannelMultiSigProof::new(IndexedSignatures::try_from(vec![]).unwrap());
|
||||
let signed_withdraw: SignedOperation<_, _, StandardMode> =
|
||||
SignedOperation::new(withdraw_op, empty_proof).into_state_trusted();
|
||||
|
||||
let (updated, events) = withdraw_op
|
||||
let (updated, events) = signed_withdraw
|
||||
.execute(WithdrawExecutionContext {
|
||||
channels,
|
||||
tx_hash: [1; 32].into(),
|
||||
@@ -508,15 +529,21 @@ mod tests {
|
||||
channel_id,
|
||||
inputs: [note_id].into(),
|
||||
};
|
||||
let empty_proof = ChannelMultiSigProof::new(IndexedSignatures::try_from(vec![]).unwrap());
|
||||
let signed_withdraw: SignedOperation<_, _, StandardMode> =
|
||||
SignedOperation::new(withdraw_op, empty_proof).into_state_trusted();
|
||||
|
||||
let result = withdraw_op.execute(WithdrawExecutionContext {
|
||||
let result = signed_withdraw.execute(WithdrawExecutionContext {
|
||||
channels,
|
||||
tx_hash: [0; 32].into(),
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(Error::ChannelNotes(channel_notes::Error::NotInChannel(_)))
|
||||
Err((
|
||||
_,
|
||||
Error::ChannelNotes(channel_notes::Error::NotInChannel(_))
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod channel;
|
||||
mod channel_notes;
|
||||
mod fixtures;
|
||||
pub mod gas;
|
||||
pub mod ledger;
|
||||
pub mod mock;
|
||||
@@ -6,14 +8,9 @@ pub mod ops;
|
||||
pub mod traits;
|
||||
pub mod transactions;
|
||||
|
||||
mod channel_notes;
|
||||
mod fixtures;
|
||||
|
||||
pub use gas::{GasProfile, TxGasCalculator};
|
||||
pub use ledger::{Note, NoteId, Utxo, Value};
|
||||
pub use ops::{Op, OpProof};
|
||||
pub use transactions::{
|
||||
CryptarchiaParameter, GenesisTime, MantleTransaction, hash::TxHash, mantle_tx::RawMantleTx,
|
||||
};
|
||||
pub use ops::{Op, OpProof, OpProofRef, OpRef};
|
||||
pub use transactions::{CryptarchiaParameter, GenesisTime, SignedOps, hash::TxHash};
|
||||
|
||||
pub use crate::mantle::transactions::VerificationError;
|
||||
|
||||
@@ -12,10 +12,9 @@ use lb_core::{
|
||||
mantle::{
|
||||
NoteId, Utxo, Value,
|
||||
gas::{Gas, GasCost, GasOverflow, GasPrice, GasProfile},
|
||||
ledger::ExecutableOperation as _,
|
||||
ops::{pow::PowTarget, transfer::TransferOp},
|
||||
traits::GenesisTx,
|
||||
transactions::{GENESIS_EXECUTION_GAS_PRICE, GENESIS_STORAGE_GAS_PRICE},
|
||||
ledger::verification_mode::{GenesisMode, StandardMode},
|
||||
ops::{SignedOperation, pow::PowTarget, transfer::TransferOp},
|
||||
transactions::{GENESIS_EXECUTION_GAS_PRICE, GENESIS_STORAGE_GAS_PRICE, states::Verified},
|
||||
},
|
||||
proofs::leader_proof::{self, LeaderPublic},
|
||||
sdp::Declarations,
|
||||
@@ -556,17 +555,18 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_transfer<Id, Profile: GasProfile>(
|
||||
mut self,
|
||||
transfer_op: &TransferOp,
|
||||
signed_operation: SignedOperation<TransferOp, Verified, StandardMode>,
|
||||
) -> Result<(Self, Balance, Vec<TxEvent>), LedgerError<Id>> {
|
||||
let operation = signed_operation.operation();
|
||||
// Compute the balance
|
||||
let balance = transfer_op
|
||||
let balance = operation
|
||||
.balance(&self.utxos)
|
||||
.map_err(mantle::Error::Transfer)?;
|
||||
|
||||
//execute the transfer
|
||||
let (result, events) = transfer_op
|
||||
let (result, events) = signed_operation
|
||||
.execute(self.utxos)
|
||||
.map_err(mantle::Error::Transfer)?;
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::Transfer(error))?;
|
||||
self.utxos = result;
|
||||
Ok((self, balance, events))
|
||||
}
|
||||
@@ -697,13 +697,16 @@ impl LedgerState {
|
||||
}
|
||||
|
||||
pub fn from_genesis_tx<Id>(
|
||||
tx: impl GenesisTx,
|
||||
transfer: &SignedOperation<TransferOp, Verified, GenesisMode>,
|
||||
config: &Config,
|
||||
epoch_nonce: Fr,
|
||||
) -> Result<Self, LedgerError<Id>> {
|
||||
let transfer_op = tx.genesis_transfer();
|
||||
if !transfer_op.inputs.is_empty() {
|
||||
let first_input = transfer_op
|
||||
let operation = transfer.operation();
|
||||
|
||||
// This transfer has not yet been verified despite the state saying so.
|
||||
// This is its verification.
|
||||
if !operation.inputs.is_empty() {
|
||||
let first_input = operation
|
||||
.inputs
|
||||
.iter()
|
||||
.next()
|
||||
@@ -712,7 +715,7 @@ impl LedgerState {
|
||||
return Err(LedgerError::InputInGenesis(first_input));
|
||||
}
|
||||
|
||||
Ok(Self::from_utxos(transfer_op.utxos(), config, epoch_nonce))
|
||||
Ok(Self::from_utxos(operation.utxos(), config, epoch_nonce))
|
||||
}
|
||||
|
||||
pub fn from_utxos(utxos: impl IntoIterator<Item = Utxo>, config: &Config, nonce: Fr) -> Self {
|
||||
@@ -832,23 +835,25 @@ pub mod tests {
|
||||
use lb_core::{
|
||||
crypto::{Digest as _, Hasher},
|
||||
mantle::{
|
||||
MantleTransaction, Note, Op,
|
||||
Note, Op,
|
||||
OpProof::ZkSig,
|
||||
RawMantleTx, TxGasCalculator as _,
|
||||
SignedOps, TxGasCalculator as _,
|
||||
gas::MainnetGasProfile,
|
||||
ledger::{Inputs, Outputs},
|
||||
ops::{leader_claim::VoucherCm, sdp::SDPDeclareOp},
|
||||
ops::{ZkAndEd25519Proof, leader_claim::VoucherCm, sdp::SDPDeclareOp},
|
||||
traits::Hashable as _,
|
||||
transactions::{
|
||||
GasPrices,
|
||||
GasPrices, OpProofs, Ops,
|
||||
states::{Preverified, Unverified},
|
||||
},
|
||||
},
|
||||
sdp::{Declaration, DeclarationId, Locator, ServiceParameters, ServiceType},
|
||||
};
|
||||
use lb_cryptarchia_engine::EpochConfig;
|
||||
use lb_groth16::{AdditiveGroup as _, ModulusShift};
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, Ed25519PublicKey, ZkKey, ZkSignature};
|
||||
use lb_groth16::{AdditiveGroup as _, CompressedGroth16Proof, ModulusShift};
|
||||
use lb_key_management_system_keys::keys::{
|
||||
Ed25519Key, Ed25519PublicKey, Ed25519Signature, ZkKey, ZkSignature,
|
||||
};
|
||||
use lb_utils::math::{NonNegativeF64, NonNegativeRatio};
|
||||
use num_bigint::BigUint;
|
||||
use rand::{RngCore as _, thread_rng};
|
||||
@@ -983,7 +988,7 @@ pub mod tests {
|
||||
slot,
|
||||
&proof,
|
||||
&UncleSlots::default(),
|
||||
std::iter::empty::<&MantleTransaction<Preverified>>(),
|
||||
std::iter::empty::<SignedOps<Preverified, StandardMode>>(),
|
||||
)?;
|
||||
ledger.commit_update(id, state);
|
||||
Ok(id)
|
||||
@@ -1205,6 +1210,14 @@ pub mod tests {
|
||||
zk_id: zk_key.to_public_key(),
|
||||
locked_note_id: sdp_utxo.id(),
|
||||
};
|
||||
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation =
|
||||
SignedOperation::<_, _, StandardMode>::new(declare_op.clone(), proof)
|
||||
.into_state_trusted();
|
||||
let config = ledger.config().clone();
|
||||
|
||||
let block_ledger = ledger.states.get_mut(&id).unwrap();
|
||||
@@ -1212,7 +1225,7 @@ pub mod tests {
|
||||
.mantle_ledger
|
||||
.clone()
|
||||
.try_apply_sdp_declaration(
|
||||
&declare_op,
|
||||
signed_operation,
|
||||
block_ledger.cryptarchia_ledger.latest_utxos(),
|
||||
&config,
|
||||
)
|
||||
@@ -1883,7 +1896,7 @@ pub mod tests {
|
||||
fn create_tx_with_transfer(
|
||||
inputs: &[(&ZkKey, &Utxo)],
|
||||
outputs: Vec<Note>,
|
||||
) -> (MantleTransaction<Unverified>, TransferOp, ZkSignature) {
|
||||
) -> (SignedOps<Unverified, StandardMode>, TransferOp, ZkSignature) {
|
||||
let sks = inputs
|
||||
.iter()
|
||||
.map(|(sk, _)| (*sk).clone())
|
||||
@@ -1893,9 +1906,10 @@ pub mod tests {
|
||||
Inputs::try_new(inputs).expect("Invalid inputs size"),
|
||||
Outputs::try_new(outputs).expect("Invalid outputs size"),
|
||||
);
|
||||
let mantle_tx = RawMantleTx([Op::Transfer(transfer_op.clone())].into());
|
||||
let mantle_tx = Ops::from([Op::Transfer(transfer_op.clone())]);
|
||||
let transfer_sig = ZkKey::multi_sign(&sks, &mantle_tx.hash().to_fr()).unwrap();
|
||||
let tx = MantleTransaction::new(mantle_tx, [ZkSig(transfer_sig.clone())].into());
|
||||
let op_proofs = OpProofs::from([ZkSig(transfer_sig.clone())]);
|
||||
let tx = SignedOps::from_parts(mantle_tx, op_proofs).unwrap();
|
||||
(tx, transfer_op, transfer_sig)
|
||||
}
|
||||
|
||||
@@ -1913,13 +1927,15 @@ pub mod tests {
|
||||
let output_note = Note::new(200, output_note_sk.to_public_key());
|
||||
|
||||
let ledger_state = LedgerState::from_utxos([input_utxo], &config(), Fr::ZERO);
|
||||
let (tx, transfer_op, _transfer_sig) = create_tx_with_transfer(
|
||||
let (tx, transfer_op, transfer_proof) = create_tx_with_transfer(
|
||||
&[(¬e_sk, &input_utxo), (¬e_sk, &input_utxo)],
|
||||
vec![output_note],
|
||||
);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let _fees = tx.total_gas_cost::<MainnetGasProfile>(&GasPrices::new(0, 0));
|
||||
let result = ledger_state.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op);
|
||||
|
||||
let result = ledger_state.try_apply_transfer::<(), MainnetGasProfile>(signed_operation);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
@@ -1940,12 +1956,14 @@ pub mod tests {
|
||||
let output_note2 = Note::new(3000, output_note2_sk.to_public_key());
|
||||
|
||||
let ledger_state = LedgerState::from_utxos([input_utxo], &config(), Fr::ZERO);
|
||||
let (tx, transfer_op, _transfer_sig) =
|
||||
let (tx, transfer_op, transfer_proof) =
|
||||
create_tx_with_transfer(&[(¬e_sk, &input_utxo)], vec![output_note1, output_note2]);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let _fees = tx.total_gas_cost::<MainnetGasProfile>(&GasPrices::new(0, 0));
|
||||
let (new_state, balance, events) = ledger_state
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op)
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(signed_operation)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -1967,7 +1985,7 @@ pub mod tests {
|
||||
assert!(new_state.utxos.contains(&output_utxo2.id()));
|
||||
|
||||
// The new outputs can be spent in future transactions
|
||||
let (tx, transfer_op, _transfer_sig) = create_tx_with_transfer(
|
||||
let (tx, transfer_op, transfer_proof) = create_tx_with_transfer(
|
||||
&[
|
||||
(&output_note1_sk, &output_utxo1),
|
||||
(&output_note2_sk, &output_utxo2),
|
||||
@@ -1975,9 +1993,11 @@ pub mod tests {
|
||||
vec![],
|
||||
);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let _fees = tx.total_gas_cost::<MainnetGasProfile>(&GasPrices::new(0, 0));
|
||||
let (final_state, final_balance, events) = new_state
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op)
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(signed_operation)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -2026,11 +2046,14 @@ pub mod tests {
|
||||
];
|
||||
|
||||
for non_existent_utxo in invalid_utxos {
|
||||
let (_tx, transfer_op, _transfer_sig) =
|
||||
let (_tx, transfer_op, transfer_proof) =
|
||||
create_tx_with_transfer(&[(&ZkKey::zero(), &non_existent_utxo)], vec![]);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let result = ledger_state
|
||||
.clone()
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op);
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(signed_operation);
|
||||
assert!(matches!(result, Err(LedgerError::Mantle(_))));
|
||||
}
|
||||
}
|
||||
@@ -2048,21 +2071,25 @@ pub mod tests {
|
||||
let output_note = Note::new(1, Fr::from(BigUint::from(2u8)).into());
|
||||
|
||||
let ledger_state = LedgerState::from_utxos([input_utxo], &config(), Fr::ZERO);
|
||||
let (_tx, transfer_op, _transfer_sig) =
|
||||
let (_tx, transfer_op, transfer_proof) =
|
||||
create_tx_with_transfer(&[(&input_sk, &input_utxo)], vec![output_note, output_note]);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let (_, balance, events) = ledger_state
|
||||
.clone()
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op)
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(signed_operation)
|
||||
.unwrap();
|
||||
assert_eq!(balance, -1);
|
||||
assert!(events.is_empty());
|
||||
|
||||
let (_tx, transfer_op, _transfer_sig) =
|
||||
let (_tx, transfer_op, transfer_proof) =
|
||||
create_tx_with_transfer(&[(&input_sk, &input_utxo)], vec![output_note]);
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
assert_eq!(
|
||||
ledger_state
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op,)
|
||||
.try_apply_transfer::<(), MainnetGasProfile>(signed_operation)
|
||||
.unwrap()
|
||||
.1,
|
||||
0
|
||||
@@ -2080,11 +2107,13 @@ pub mod tests {
|
||||
};
|
||||
|
||||
let ledger_state = LedgerState::from_utxos([input_utxo], &config(), Fr::ZERO);
|
||||
let (tx, transfer_op, _transfer_sig) =
|
||||
let (tx, transfer_op, transfer_proof) =
|
||||
create_tx_with_transfer(&[(&input_sk, &input_utxo)], vec![]);
|
||||
|
||||
let signed_operation =
|
||||
SignedOperation::new(transfer_op, transfer_proof).into_state_trusted();
|
||||
let _fees = tx.total_gas_cost::<MainnetGasProfile>(&GasPrices::new(0, 0));
|
||||
let result = ledger_state.try_apply_transfer::<(), MainnetGasProfile>(&transfer_op);
|
||||
let result = ledger_state.try_apply_transfer::<(), MainnetGasProfile>(signed_operation);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let (new_state, balance, events) = result.unwrap();
|
||||
|
||||
@@ -26,8 +26,9 @@ use std::{num::NonZero, sync::Arc};
|
||||
use lb_core::{
|
||||
crypto::{Digest as _, Hasher},
|
||||
mantle::{
|
||||
MantleTransaction, Note, Utxo, Value,
|
||||
Note, SignedOps, Utxo, Value,
|
||||
gas::MainnetGasProfile,
|
||||
ledger::verification_mode::StandardMode,
|
||||
transactions::{
|
||||
GENESIS_EXECUTION_GAS_PRICE, GENESIS_STORAGE_GAS_PRICE, states::Preverified,
|
||||
},
|
||||
@@ -384,7 +385,7 @@ fn apply_block_to_ledger(
|
||||
slot,
|
||||
&proof,
|
||||
uncle_slots,
|
||||
std::iter::empty::<&MantleTransaction<Preverified>>(),
|
||||
std::iter::empty::<SignedOps<Preverified, StandardMode>>(),
|
||||
)
|
||||
.expect("ledger update");
|
||||
ledger.commit_update(id, state);
|
||||
|
||||
+206
-143
@@ -16,10 +16,11 @@ use lb_core::{
|
||||
crypto::Hash as BlockHash,
|
||||
events::{Events, HeaderEvent, TxEvent, TxEventPayload},
|
||||
mantle::{
|
||||
NoteId, Op, Utxo, Value, VerificationError,
|
||||
NoteId, TxGasCalculator, Utxo, Value, VerificationError,
|
||||
gas::{Gas, GasCost, GasOverflow, GasProfile},
|
||||
ledger::ExecutableOperation as _,
|
||||
ledger::verification_mode::StandardMode,
|
||||
ops::{
|
||||
SignedOp,
|
||||
channel::{
|
||||
channel_transfer::ChannelTransferExecutionContext,
|
||||
deposit::DepositExecutionContext, withdraw::WithdrawExecutionContext,
|
||||
@@ -27,8 +28,13 @@ use lb_core::{
|
||||
leader_claim::LeaderClaimExecutionContext,
|
||||
pow::{ClaimPoWRewardExecutionContext, PowReward},
|
||||
},
|
||||
traits::{GenesisTx, MantleTxWithProofs, PreverifiedMantleTx},
|
||||
transactions::{GasPrices, MantleTxGasContext, hash::TxHash, mantle_tx::MantleTxContext},
|
||||
traits::{GenesisTx, PreverifiedMantleTransaction, genesis::GenesisOps},
|
||||
transactions::{
|
||||
GasPrices,
|
||||
hash::TxHash,
|
||||
states::Verified,
|
||||
tx_list::ops::{OpsContext, OpsGasContext},
|
||||
},
|
||||
},
|
||||
proofs::leader_proof,
|
||||
};
|
||||
@@ -152,17 +158,17 @@ where
|
||||
///
|
||||
/// On success, a new [`LedgerState`] is returned, which can then be
|
||||
/// committed by calling [`Self::commit_update`].
|
||||
pub fn prepare_update<'tx, Tx, LeaderProof, Profile>(
|
||||
pub fn prepare_update<Tx, LeaderProof, Profile>(
|
||||
&self,
|
||||
id: Id,
|
||||
parent_id: Id,
|
||||
slot: Slot,
|
||||
proof: &LeaderProof,
|
||||
uncle_slots: &UncleSlots,
|
||||
txs: impl Iterator<Item = &'tx Tx>,
|
||||
txs: impl Iterator<Item = Tx>,
|
||||
) -> Result<(Id, LedgerState, Events), LedgerError<Id>>
|
||||
where
|
||||
Tx: PreverifiedMantleTx<Context = GasPrices> + 'tx,
|
||||
Tx: PreverifiedMantleTransaction + TxGasCalculator<Context = GasPrices> + Clone,
|
||||
LeaderProof: leader_proof::LeaderProof,
|
||||
Profile: GasProfile,
|
||||
Id: Into<BlockHash>,
|
||||
@@ -227,17 +233,17 @@ pub struct LedgerState {
|
||||
}
|
||||
|
||||
impl LedgerState {
|
||||
fn try_update<'tx, Tx, LeaderProof, Id, Profile>(
|
||||
fn try_update<Tx, LeaderProof, Id, Profile>(
|
||||
self,
|
||||
block_id: Id,
|
||||
slot: Slot,
|
||||
proof: &LeaderProof,
|
||||
uncle_slots: &UncleSlots,
|
||||
txs: impl Iterator<Item = &'tx Tx>,
|
||||
txs: impl Iterator<Item = Tx>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Events), LedgerError<Id>>
|
||||
where
|
||||
Tx: PreverifiedMantleTx<Context = GasPrices> + 'tx,
|
||||
Tx: PreverifiedMantleTransaction + TxGasCalculator<Context = GasPrices> + Clone,
|
||||
LeaderProof: leader_proof::LeaderProof,
|
||||
Profile: GasProfile,
|
||||
Id: Into<BlockHash>,
|
||||
@@ -447,13 +453,13 @@ impl LedgerState {
|
||||
}
|
||||
|
||||
/// Apply the contents of an update to the ledger state.
|
||||
pub fn try_apply_contents<'tx, Tx, Id, Profile: GasProfile>(
|
||||
pub fn try_apply_contents<Tx, Id, Profile: GasProfile>(
|
||||
mut self,
|
||||
config: &Config,
|
||||
txs: impl Iterator<Item = &'tx Tx>,
|
||||
txs: impl Iterator<Item = Tx>,
|
||||
) -> Result<(Self, Vec<TxEvent>), LedgerError<Id>>
|
||||
where
|
||||
Tx: PreverifiedMantleTx<Context = GasPrices> + 'tx,
|
||||
Tx: PreverifiedMantleTransaction + TxGasCalculator<Context = GasPrices> + Clone,
|
||||
{
|
||||
let mut total_block_execution_gas: Gas = 0.into();
|
||||
let mut total_block_storage_gas: Gas = 0.into();
|
||||
@@ -464,7 +470,8 @@ impl LedgerState {
|
||||
for tx in txs {
|
||||
let balance;
|
||||
let events;
|
||||
(self, balance, events) = self.try_apply_tx::<_, _, Profile>(config, tx)?;
|
||||
|
||||
(self, balance, events) = self.try_apply_tx::<_, _, Profile>(config, tx.clone())?;
|
||||
tx_events.extend(events);
|
||||
|
||||
let gas_prices = GasPrices {
|
||||
@@ -538,9 +545,16 @@ impl LedgerState {
|
||||
config: &Config,
|
||||
epoch_nonce: Fr,
|
||||
) -> Result<(Self, Vec<TxEvent>), LedgerError<Id>> {
|
||||
let cryptarchia_ledger = CryptarchiaLedger::from_genesis_tx(&tx, config, epoch_nonce)?;
|
||||
let GenesisOps {
|
||||
transfer,
|
||||
inscription,
|
||||
declarations,
|
||||
} = tx.into_genesis_ops();
|
||||
let cryptarchia_ledger =
|
||||
CryptarchiaLedger::from_genesis_tx(&transfer, config, epoch_nonce)?;
|
||||
let (mantle_ledger, events) = MantleLedger::from_genesis_tx(
|
||||
tx,
|
||||
inscription,
|
||||
declarations,
|
||||
config,
|
||||
cryptarchia_ledger.latest_utxos(),
|
||||
cryptarchia_ledger.epoch_state(),
|
||||
@@ -609,9 +623,9 @@ impl LedgerState {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn tx_context(&self) -> MantleTxContext {
|
||||
MantleTxContext {
|
||||
gas_context: MantleTxGasContext::from_channels(
|
||||
pub fn tx_context(&self) -> OpsContext {
|
||||
OpsContext {
|
||||
gas_context: OpsGasContext::from_channels(
|
||||
self.mantle_ledger().channels(),
|
||||
self.get_gas_prices(),
|
||||
),
|
||||
@@ -625,56 +639,57 @@ impl LedgerState {
|
||||
)]
|
||||
fn try_apply_op<Id, Profile: GasProfile>(
|
||||
mut self,
|
||||
op: &Op,
|
||||
signed_op: SignedOp<Verified, StandardMode>,
|
||||
config: &Config,
|
||||
tx_hash: &TxHash,
|
||||
mut balance: Balance,
|
||||
mut tx_events: Vec<TxEvent>,
|
||||
) -> Result<(Self, Balance, Vec<TxEvent>), LedgerError<Id>> {
|
||||
match op {
|
||||
Op::ChannelInscribe(op) => {
|
||||
let (result, events) = self
|
||||
.mantle_ledger
|
||||
.try_apply_channel_inscription(op, self.cryptarchia_ledger.slot)?;
|
||||
match signed_op {
|
||||
SignedOp::ChannelInscribe(signed_operation) => {
|
||||
let (result, events) = self.mantle_ledger.try_apply_channel_inscription(
|
||||
signed_operation,
|
||||
self.cryptarchia_ledger.slot,
|
||||
)?;
|
||||
self.mantle_ledger = result;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::ChannelConfig(op) => {
|
||||
SignedOp::ChannelConfig(signed_operation) => {
|
||||
let (result, events) = self
|
||||
.mantle_ledger
|
||||
.try_apply_channel_config(op, self.cryptarchia_ledger.slot)?;
|
||||
.try_apply_channel_config(signed_operation, self.cryptarchia_ledger.slot)?;
|
||||
self.mantle_ledger = result;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::ChannelDeposit(op) => {
|
||||
SignedOp::ChannelDeposit(signed_operation) => {
|
||||
let channels = self.mantle_ledger.channels();
|
||||
let utxos = self.cryptarchia_ledger.latest_utxos();
|
||||
|
||||
// Execute the Deposit
|
||||
let (result, events) = op
|
||||
let (result, events) = signed_operation
|
||||
.execute(DepositExecutionContext {
|
||||
channels: channels.clone(),
|
||||
utxos: utxos.clone(),
|
||||
tx_hash: *tx_hash,
|
||||
})
|
||||
.map_err(mantle::Error::Channel)?;
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::Channel(error))?;
|
||||
self.mantle_ledger = self.mantle_ledger.update_channels(result.channels);
|
||||
self.cryptarchia_ledger = self.cryptarchia_ledger.update_utxos(result.utxos);
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::ChannelWithdraw(op) => {
|
||||
SignedOp::ChannelWithdraw(signed_operation) => {
|
||||
let channels = self.mantle_ledger.channels();
|
||||
|
||||
let (result, events) = op
|
||||
let (result, events) = signed_operation
|
||||
.execute(WithdrawExecutionContext {
|
||||
channels: channels.clone(),
|
||||
tx_hash: *tx_hash,
|
||||
})
|
||||
.map_err(mantle::Error::Channel)?;
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::Channel(error))?;
|
||||
self.mantle_ledger = self.mantle_ledger.update_channels(result.channels);
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::ChannelTransfer(op) => {
|
||||
SignedOp::ChannelTransfer(signed_operation) => {
|
||||
let channels = self.mantle_ledger.channels();
|
||||
let utxos = self.cryptarchia_ledger.latest_utxos();
|
||||
|
||||
@@ -683,32 +698,38 @@ impl LedgerState {
|
||||
utxos: utxos.clone(),
|
||||
tx_hash: *tx_hash,
|
||||
};
|
||||
let (result, events) = op.execute(context).map_err(mantle::Error::Channel)?;
|
||||
let (result, events) = signed_operation
|
||||
.execute(context)
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::Channel(error))?;
|
||||
self.mantle_ledger = self.mantle_ledger.update_channels(result.channels);
|
||||
self.cryptarchia_ledger = self.cryptarchia_ledger.update_utxos(result.utxos);
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::SDPDeclare(op) => {
|
||||
SignedOp::SDPDeclare(signed_operation) => {
|
||||
let (result, events) = self.mantle_ledger.try_apply_sdp_declaration(
|
||||
op,
|
||||
signed_operation,
|
||||
self.cryptarchia_ledger.latest_utxos(),
|
||||
config,
|
||||
)?;
|
||||
self.mantle_ledger = result;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::SDPActive(op) => {
|
||||
let (result, events) = self.mantle_ledger.try_apply_sdp_active(op, config)?;
|
||||
SignedOp::SDPActive(signed_operation) => {
|
||||
let (result, events) = self
|
||||
.mantle_ledger
|
||||
.try_apply_sdp_active(signed_operation, config)?;
|
||||
self.mantle_ledger = result;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::SDPWithdraw(op) => {
|
||||
let (result, events) = self.mantle_ledger.try_apply_sdp_withdraw(op, config)?;
|
||||
SignedOp::SDPWithdraw(signed_operation) => {
|
||||
let (result, events) = self
|
||||
.mantle_ledger
|
||||
.try_apply_sdp_withdraw(signed_operation, config)?;
|
||||
self.mantle_ledger = result;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::LeaderClaim(op) => {
|
||||
let (result, events) = op
|
||||
SignedOp::LeaderClaim(signed_operation) => {
|
||||
let (result, events) = signed_operation
|
||||
.execute(LeaderClaimExecutionContext {
|
||||
nullifiers: self.mantle_ledger.leaders.nullifiers_cloned(),
|
||||
reward_amount: self.mantle_ledger.leaders.reward_amount(),
|
||||
@@ -716,7 +737,7 @@ impl LedgerState {
|
||||
utxos: self.cryptarchia_ledger.latest_utxos().clone(),
|
||||
tx_hash: *tx_hash,
|
||||
})
|
||||
.map_err(mantle::Error::LeaderClaim)?;
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::LeaderClaim(error))?;
|
||||
self.mantle_ledger
|
||||
.leaders
|
||||
.update_nullifiers(result.nullifiers);
|
||||
@@ -727,19 +748,19 @@ impl LedgerState {
|
||||
.update_rewards(result.claimable_rewards);
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::Transfer(op) => {
|
||||
SignedOp::Transfer(signed_operation) => {
|
||||
let transfer_balance;
|
||||
let events;
|
||||
(self.cryptarchia_ledger, transfer_balance, events) =
|
||||
self.cryptarchia_ledger
|
||||
.try_apply_transfer::<_, Profile>(op)?;
|
||||
.try_apply_transfer::<_, Profile>(signed_operation)?;
|
||||
balance = balance
|
||||
.checked_add(transfer_balance)
|
||||
.ok_or(LedgerError::BalanceOverflow)?;
|
||||
tx_events.extend(events);
|
||||
}
|
||||
Op::ClaimPowReward(claim_pow_reward) => {
|
||||
let (result, events) = claim_pow_reward
|
||||
SignedOp::ClaimPowReward(signed_operation) => {
|
||||
let (result, events) = signed_operation
|
||||
.execute(ClaimPoWRewardExecutionContext {
|
||||
reward_pool: self.mantle_ledger.pow.reward_pool(),
|
||||
// TODO: check correctness of epoch reward, as it should be from the op
|
||||
@@ -750,7 +771,7 @@ impl LedgerState {
|
||||
utxos: self.cryptarchia_ledger.latest_utxos().clone(),
|
||||
block_slots: self.mantle_ledger.pow.block_slots().clone(),
|
||||
})
|
||||
.map_err(mantle::Error::ClaimPow)?;
|
||||
.map_err(|(_signed_operation, error)| mantle::Error::ClaimPow(error))?;
|
||||
self.mantle_ledger
|
||||
.pow
|
||||
.update_from_claim_execution_result(&result);
|
||||
@@ -768,7 +789,7 @@ impl LedgerState {
|
||||
///
|
||||
/// Verification is interleaved with execution: each operation is verified
|
||||
/// against the current ledger state (via
|
||||
/// [`MantleTransaction::verified_ops`]) immediately before it is executed,
|
||||
/// [`SignedOps::verified_ops`]) immediately before it is executed,
|
||||
/// so an operation may depend on state produced by earlier operations
|
||||
/// in the same transaction.
|
||||
///
|
||||
@@ -779,15 +800,15 @@ impl LedgerState {
|
||||
///
|
||||
/// If any operation fails verification or execution, returns a
|
||||
/// [`LedgerError`] describing the failure.
|
||||
fn try_apply_tx<'tx, Tx, Id, Profile: GasProfile>(
|
||||
fn try_apply_tx<Tx, Id, Profile: GasProfile>(
|
||||
mut self,
|
||||
config: &Config,
|
||||
tx: &'tx Tx,
|
||||
tx: Tx,
|
||||
) -> Result<(Self, Balance, Vec<TxEvent>), LedgerError<Id>>
|
||||
where
|
||||
Tx: PreverifiedMantleTx + 'tx + MantleTxWithProofs<Context = GasPrices>,
|
||||
Tx: PreverifiedMantleTransaction,
|
||||
{
|
||||
let mut verified_ops = tx.verified_ops();
|
||||
let mut verified_ops = tx.into_verified_operations();
|
||||
|
||||
let mut balance: Balance = 0;
|
||||
let mut tx_events = Vec::new();
|
||||
@@ -798,9 +819,14 @@ impl LedgerState {
|
||||
&self.cryptarchia_ledger,
|
||||
config,
|
||||
);
|
||||
|
||||
// On Error (failed verification), the transaction is considered invalid and
|
||||
// rejected.
|
||||
let Some(op) = verified_ops.next(&helper).transpose()? else {
|
||||
// All operations have been processed, exit the loop.
|
||||
break;
|
||||
};
|
||||
|
||||
(self, balance, tx_events) = self.try_apply_op::<_, Profile>(
|
||||
op,
|
||||
config,
|
||||
@@ -824,11 +850,11 @@ mod tests {
|
||||
use lb_core::{
|
||||
events::DepositNote,
|
||||
mantle::{
|
||||
MantleTransaction, Note, OpProof, RawMantleTx, TxGasCalculator as _,
|
||||
Note, Op, OpProof, SignedOps,
|
||||
gas::MainnetGasProfile,
|
||||
ledger::{Inputs, Outputs, Utxos, VerifiableOperation as _},
|
||||
ops::{
|
||||
OpId as _,
|
||||
OpId as _, OpRef, SignedOperation,
|
||||
channel::{
|
||||
ChannelId, MsgId,
|
||||
config::ChannelConfigOp,
|
||||
@@ -844,7 +870,6 @@ mod tests {
|
||||
transactions::{
|
||||
OpProofs, Ops,
|
||||
hash::TxHashView,
|
||||
mantle_tx::MantleTx as _,
|
||||
states::{Preverified, Unverified},
|
||||
},
|
||||
},
|
||||
@@ -856,7 +881,9 @@ mod tests {
|
||||
};
|
||||
use lb_cryptarchia_engine::Epoch;
|
||||
use lb_groth16::{CompressedGroth16Proof, Field as _};
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, Ed25519PublicKey, ZkKey, ZkPublicKey};
|
||||
use lb_key_management_system_keys::keys::{
|
||||
Ed25519Key, Ed25519PublicKey, ZkKey, ZkPublicKey, ZkSignature,
|
||||
};
|
||||
use num_bigint::BigUint;
|
||||
|
||||
use super::*;
|
||||
@@ -878,17 +905,16 @@ mod tests {
|
||||
inputs: Vec<NoteId>,
|
||||
outputs: Vec<Note>,
|
||||
sks: &[ZkKey],
|
||||
) -> MantleTransaction<Unverified> {
|
||||
) -> SignedOps<Unverified, StandardMode> {
|
||||
let transfer_op = TransferOp::new(
|
||||
Inputs::try_new(inputs).expect("Invalid inputs size"),
|
||||
Outputs::try_new(outputs).expect("Invalid outputs size"),
|
||||
);
|
||||
let mantle_tx = RawMantleTx([Op::Transfer(transfer_op)].into());
|
||||
let ops_proofs = [OpProof::ZkSig(
|
||||
let mantle_tx = Ops::from([Op::Transfer(transfer_op)]);
|
||||
let ops_proofs = OpProofs::from([OpProof::ZkSig(
|
||||
ZkKey::multi_sign(sks, &mantle_tx.hash().to_fr()).unwrap(),
|
||||
)]
|
||||
.into();
|
||||
MantleTransaction::new(mantle_tx, ops_proofs)
|
||||
)]);
|
||||
SignedOps::from_parts(mantle_tx, ops_proofs).unwrap()
|
||||
}
|
||||
|
||||
pub fn create_test_ledger() -> (Ledger<HeaderId>, HeaderId, Utxo) {
|
||||
@@ -950,20 +976,20 @@ mod tests {
|
||||
MultiSequencer(ChannelMultiSigProof),
|
||||
}
|
||||
|
||||
fn create_signed_tx(op: Op, signing_key: &Key) -> MantleTransaction<Preverified> {
|
||||
fn create_signed_tx(op: Op, signing_key: &Key) -> SignedOps<Preverified, StandardMode> {
|
||||
create_multi_signed_tx(vec![op], vec![signing_key])
|
||||
}
|
||||
|
||||
fn create_multi_signed_tx(
|
||||
ops: Vec<Op>,
|
||||
ops_vec: Vec<Op>,
|
||||
signing_keys: Vec<&Key>,
|
||||
) -> MantleTransaction<Preverified> {
|
||||
let mantle_tx = RawMantleTx(Ops::new_unchecked(ops.clone()));
|
||||
) -> SignedOps<Preverified, StandardMode> {
|
||||
let ops = Ops::new_unchecked(ops_vec);
|
||||
|
||||
let tx_hash = mantle_tx.hash();
|
||||
let tx_hash = ops.hash();
|
||||
let ops_proofs = signing_keys
|
||||
.into_iter()
|
||||
.zip(ops)
|
||||
.zip(ops.iter())
|
||||
.map(|(key, _)| match key {
|
||||
Key::Ed25519(key) => {
|
||||
OpProof::Ed25519Sig(key.sign_payload(tx_hash.as_signing_bytes().as_ref()))
|
||||
@@ -975,9 +1001,9 @@ mod tests {
|
||||
Key::MultiSequencer(proof) => OpProof::ChannelMultiSigProof(proof.clone()),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let ops_proofs = OpProofs::try_from(ops_proofs).expect("operation proofs are bounded");
|
||||
|
||||
MantleTransaction::new(mantle_tx, ops_proofs)
|
||||
let ops_proofs = OpProofs::new_unchecked(ops_proofs);
|
||||
SignedOps::from_parts(ops, ops_proofs)
|
||||
.unwrap()
|
||||
.preverify()
|
||||
.expect("Test transaction should have valid signatures")
|
||||
}
|
||||
@@ -999,7 +1025,7 @@ mod tests {
|
||||
&Key::Ed25519(signing_key.clone()),
|
||||
);
|
||||
ledger_state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(config, &tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(config, tx)
|
||||
.unwrap()
|
||||
.0
|
||||
}
|
||||
@@ -1036,11 +1062,17 @@ mod tests {
|
||||
&config.sdp_config.service_rewards_params.blend,
|
||||
))),
|
||||
};
|
||||
let signed_operation = SignedOperation::new(
|
||||
active_op,
|
||||
ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
)
|
||||
.into_state_trusted();
|
||||
|
||||
let block_ledger = ledger.states.get_mut(&id).unwrap();
|
||||
block_ledger.mantle_ledger = block_ledger
|
||||
.mantle_ledger
|
||||
.clone()
|
||||
.try_apply_sdp_active(&active_op, &config)
|
||||
.try_apply_sdp_active(signed_operation, &config)
|
||||
.unwrap()
|
||||
.0;
|
||||
id
|
||||
@@ -1076,7 +1108,11 @@ mod tests {
|
||||
let tx = create_tx(vec![utxo.id()], vec![output_note], &[sk])
|
||||
.preverify()
|
||||
.unwrap();
|
||||
let mantle_tx = tx.mantle_tx().clone();
|
||||
let output_utxo = if let OpRef::Transfer(transfer_op) = tx.op_refs().get(0).unwrap() {
|
||||
transfer_op.outputs.utxo_by_index(0, transfer_op).unwrap()
|
||||
} else {
|
||||
panic!("first op must be a transfer")
|
||||
};
|
||||
|
||||
// Create a dummy proof (using same structure as in cryptarchia tests)
|
||||
|
||||
@@ -1094,7 +1130,7 @@ mod tests {
|
||||
Slot::from(1u64),
|
||||
&proof,
|
||||
&UncleSlots::default(),
|
||||
std::iter::once(&tx),
|
||||
std::iter::once(tx),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(events.is_empty());
|
||||
@@ -1105,12 +1141,7 @@ mod tests {
|
||||
assert!(!new_state.latest_utxos().contains(&utxo.id()));
|
||||
|
||||
// Verify output was created
|
||||
if let Op::Transfer(transfer_op) = &mantle_tx.ops()[0] {
|
||||
let output_utxo = transfer_op.outputs.utxo_by_index(0, transfer_op).unwrap();
|
||||
assert!(new_state.latest_utxos().contains(&output_utxo.id()));
|
||||
} else {
|
||||
panic!("first op must be a transfer")
|
||||
}
|
||||
assert!(new_state.latest_utxos().contains(&output_utxo.id()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1128,7 +1159,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let tx = create_signed_tx(Op::ChannelInscribe(inscribe_op), &Key::Ed25519(signing_key));
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx);
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let (new_state, _, events) = result.unwrap();
|
||||
@@ -1158,7 +1189,7 @@ mod tests {
|
||||
transfer_threshold: 1,
|
||||
};
|
||||
|
||||
let config_tx = RawMantleTx([Op::ChannelConfig(config_op.clone())].into());
|
||||
let config_tx = Ops::from([Op::ChannelConfig(config_op.clone())]);
|
||||
let config_tx_hash = config_tx.hash();
|
||||
let config_proof = ChannelMultiSigProof::try_new(
|
||||
[IndexedSignature::new(
|
||||
@@ -1173,7 +1204,7 @@ mod tests {
|
||||
Op::ChannelConfig(config_op),
|
||||
&Key::MultiSequencer(config_proof),
|
||||
);
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx);
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let (new_state, _, events) = result.unwrap();
|
||||
@@ -1229,7 +1260,8 @@ mod tests {
|
||||
};
|
||||
let ops = vec![Op::ChannelDeposit(deposit.clone())];
|
||||
let tx = create_multi_signed_tx(ops, vec![&Key::Zk(sk)]);
|
||||
let result = ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx);
|
||||
let tx_hash = tx.hash();
|
||||
let result = ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx);
|
||||
let (new_state, balance, events) = result.unwrap();
|
||||
// The deposited note is consumed and re-created as a channel note under
|
||||
// a new NoteId.
|
||||
@@ -1273,7 +1305,7 @@ mod tests {
|
||||
else {
|
||||
panic!("events should include deposit event")
|
||||
};
|
||||
assert_eq!(*event_tx_hash, tx.hash());
|
||||
assert_eq!(*event_tx_hash, tx_hash);
|
||||
assert_eq!(*op_id, deposit.op_id());
|
||||
assert_eq!(*event_channel_id, deposit.channel_id);
|
||||
assert_eq!(*amount, utxo.note.value);
|
||||
@@ -1314,7 +1346,7 @@ mod tests {
|
||||
let deposit_ops = vec![Op::ChannelDeposit(deposit)];
|
||||
let tx = create_multi_signed_tx(deposit_ops, vec![&Key::Zk(sk)]);
|
||||
ledger_state = ledger_state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
@@ -1331,7 +1363,7 @@ mod tests {
|
||||
channel_id,
|
||||
inputs: Inputs::new([deposited]),
|
||||
};
|
||||
let withdraw_tx = RawMantleTx([Op::ChannelWithdraw(withdraw)].into());
|
||||
let withdraw_tx = Ops::from([Op::ChannelWithdraw(withdraw)]);
|
||||
let withdraw_tx_hash = withdraw_tx.hash();
|
||||
let withdraw_proof = ChannelMultiSigProof::try_new(
|
||||
[IndexedSignature::new(
|
||||
@@ -1343,12 +1375,12 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let signed_tx = create_multi_signed_tx(
|
||||
withdraw_tx.0.to_vec(),
|
||||
withdraw_tx.to_vec(),
|
||||
vec![&Key::MultiSequencer(withdraw_proof)],
|
||||
);
|
||||
|
||||
let result =
|
||||
ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &signed_tx);
|
||||
ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, signed_tx);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let (new_state, tx_balance, events) = result.unwrap();
|
||||
@@ -1389,19 +1421,16 @@ mod tests {
|
||||
let deposit_tx =
|
||||
create_multi_signed_tx(vec![Op::ChannelDeposit(deposit)], vec![&Key::Zk(sk)]);
|
||||
ledger_state = ledger_state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &deposit_tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, deposit_tx.clone())
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
// Withdraw releases the channel note under the NoteId the deposit gave
|
||||
// it, so the original input never comes back to the ledger.
|
||||
let withdraw_tx = RawMantleTx(
|
||||
[Op::ChannelWithdraw(ChannelWithdrawOp {
|
||||
channel_id,
|
||||
inputs: Inputs::new([deposited]),
|
||||
})]
|
||||
.into(),
|
||||
);
|
||||
let withdraw_tx = Ops::from([Op::ChannelWithdraw(ChannelWithdrawOp {
|
||||
channel_id,
|
||||
inputs: Inputs::new([deposited]),
|
||||
})]);
|
||||
let withdraw_proof = ChannelMultiSigProof::try_new(
|
||||
[IndexedSignature::new(
|
||||
0,
|
||||
@@ -1411,11 +1440,11 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
let signed_withdraw = create_multi_signed_tx(
|
||||
withdraw_tx.0.to_vec(),
|
||||
withdraw_tx.to_vec(),
|
||||
vec![&Key::MultiSequencer(withdraw_proof)],
|
||||
);
|
||||
ledger_state = ledger_state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &signed_withdraw)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, signed_withdraw)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
@@ -1423,7 +1452,7 @@ mod tests {
|
||||
|
||||
// Replaying the signed deposit fails: its input no longer exists.
|
||||
let result =
|
||||
ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &deposit_tx);
|
||||
ledger_state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, deposit_tx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
@@ -1453,7 +1482,7 @@ mod tests {
|
||||
let deposit_ops = vec![Op::ChannelDeposit(deposit)];
|
||||
let tx = create_multi_signed_tx(deposit_ops, vec![&Key::Zk(sk)]);
|
||||
ledger_state = ledger_state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx)
|
||||
.unwrap()
|
||||
.0;
|
||||
// The deposit re-created the note as a channel note
|
||||
@@ -1470,7 +1499,7 @@ mod tests {
|
||||
inputs: Inputs::new([deposited]),
|
||||
};
|
||||
let wrong_key = Ed25519Key::from_bytes(&[42; 32]);
|
||||
let withdraw_tx = RawMantleTx([Op::ChannelWithdraw(withdraw)].into());
|
||||
let withdraw_tx = Ops::from([Op::ChannelWithdraw(withdraw)]);
|
||||
let withdraw_tx_hash = withdraw_tx.hash();
|
||||
let invalid_proof = ChannelMultiSigProof::try_new(
|
||||
[IndexedSignature::new(
|
||||
@@ -1482,13 +1511,13 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let signed_tx = create_multi_signed_tx(
|
||||
withdraw_tx.0.to_vec(),
|
||||
withdraw_tx.to_vec(),
|
||||
vec![&Key::MultiSequencer(invalid_proof), &Key::EmptyZk],
|
||||
);
|
||||
|
||||
let err = ledger_state
|
||||
.clone()
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &signed_tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, signed_tx)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
@@ -1526,7 +1555,7 @@ mod tests {
|
||||
&Key::Ed25519(signing_key.clone()),
|
||||
);
|
||||
state = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &first_tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, first_tx)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
@@ -1545,7 +1574,7 @@ mod tests {
|
||||
);
|
||||
let result = state
|
||||
.clone()
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &second_tx);
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, second_tx);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(LedgerError::VerificationError(
|
||||
@@ -1569,7 +1598,7 @@ mod tests {
|
||||
&Key::Ed25519(signing_key),
|
||||
);
|
||||
let empty_result =
|
||||
state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &empty_tx);
|
||||
state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, empty_tx);
|
||||
assert!(matches!(
|
||||
empty_result,
|
||||
Err(LedgerError::VerificationError(
|
||||
@@ -1602,7 +1631,7 @@ mod tests {
|
||||
&Key::Ed25519(signing_key),
|
||||
);
|
||||
state = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &first_tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, first_tx)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
@@ -1618,7 +1647,7 @@ mod tests {
|
||||
Op::ChannelInscribe(second_inscribe),
|
||||
&Key::Ed25519(unauthorized_signing_key),
|
||||
);
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &second_tx);
|
||||
let result = state.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, second_tx);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(LedgerError::VerificationError(
|
||||
@@ -1681,7 +1710,7 @@ mod tests {
|
||||
Op::ChannelConfig(config_op),
|
||||
Op::ChannelInscribe(inscribe_op3.clone()),
|
||||
];
|
||||
let config_tx = RawMantleTx(Ops::new_unchecked(ops.clone()));
|
||||
let config_tx = Ops::new_unchecked(ops.clone());
|
||||
let config_tx_hash = config_tx.hash();
|
||||
let config_proof = ChannelMultiSigProof::try_new(
|
||||
[IndexedSignature::new(
|
||||
@@ -1703,7 +1732,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let result = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, &tx)
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&test_config, tx)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
@@ -1854,7 +1883,10 @@ mod tests {
|
||||
|
||||
let result = ledger
|
||||
.clone()
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(&tx));
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(
|
||||
&config,
|
||||
std::iter::once(tx.clone()),
|
||||
);
|
||||
// The `unwrap` should succeed because the user pays at least the base fee of
|
||||
// 2705
|
||||
result.unwrap();
|
||||
@@ -1862,7 +1894,7 @@ mod tests {
|
||||
ledger.cryptarchia_ledger = ledger.cryptarchia_ledger.set_execution_base_fee(10.into());
|
||||
|
||||
let err = ledger
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(&tx))
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(tx))
|
||||
.unwrap_err();
|
||||
// The transaction should be rejected because the price indicated for execution
|
||||
// doesn't cover the base fee that cost 27 050
|
||||
@@ -1899,7 +1931,7 @@ mod tests {
|
||||
|
||||
let result = ledger
|
||||
.clone()
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(&tx));
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(tx));
|
||||
// The `unwrap` should succeed because the user pays at least the base fee of
|
||||
// 794
|
||||
let (no_priority_fee_ledger, events) = result.unwrap();
|
||||
@@ -1917,7 +1949,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let result = ledger
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(&tx));
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(tx));
|
||||
// The `unwrap` should succeed because the user pays at least the base fee of
|
||||
// 794
|
||||
let (priority_fee_ledger, events) = result.unwrap();
|
||||
@@ -1959,7 +1991,7 @@ mod tests {
|
||||
assert!(storage_gas.into_inner() > 0);
|
||||
|
||||
let (applied, _) = ledger
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(&tx))
|
||||
.try_apply_contents::<_, HeaderId, MainnetGasProfile>(&config, std::iter::once(tx))
|
||||
.unwrap();
|
||||
|
||||
// Storage gas consumed by the tx should be accumulated in the ledger
|
||||
@@ -1994,8 +2026,13 @@ mod tests {
|
||||
voucher_nullifier: nf.into(),
|
||||
pk: ZkPublicKey::zero(),
|
||||
};
|
||||
let signed_operation = SignedOperation::<_, _, StandardMode>::new(
|
||||
op,
|
||||
Groth16LeaderClaimProof::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
)
|
||||
.into_state_trusted();
|
||||
// Skip `op.validate` in this test to avoid having to generate a valid proof
|
||||
let (result, _events) = op
|
||||
let (result, _events) = signed_operation
|
||||
.execute(LeaderClaimExecutionContext {
|
||||
nullifiers: leaders.nullifiers_cloned(),
|
||||
reward_amount: leaders.reward_amount(),
|
||||
@@ -2033,8 +2070,15 @@ mod tests {
|
||||
voucher_nullifier: Fr::ZERO.into(), // nf of the 1st voucher
|
||||
pk: ZkPublicKey::zero(),
|
||||
};
|
||||
let signed_operation = SignedOperation::<_, _, StandardMode>::new(
|
||||
op,
|
||||
Groth16LeaderClaimProof::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
);
|
||||
let preverified_signed_operation = signed_operation.into_state_trusted::<Preverified>();
|
||||
let executable_signed_operation = preverified_signed_operation.clone().into_state_trusted();
|
||||
|
||||
// Skip `op.validate` in this test to avoid having to generate a valid proof
|
||||
let (result, _events) = op
|
||||
let (result, _events) = executable_signed_operation
|
||||
.execute(LeaderClaimExecutionContext {
|
||||
nullifiers: leaders.nullifiers_cloned(),
|
||||
reward_amount: leaders.reward_amount(),
|
||||
@@ -2053,16 +2097,15 @@ mod tests {
|
||||
let tx_hash = TxHash::from([0u8; 32]);
|
||||
let tx_hash_view = TxHashView::from(tx_hash);
|
||||
// Use a dummy proof since duplication is detected before proof verification
|
||||
let proof = Groth16LeaderClaimProof::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let err = op
|
||||
.verify(
|
||||
&proof,
|
||||
&LeaderClaimVerificationContext {
|
||||
nullifiers: leaders.nullifiers(),
|
||||
claimable_vouchers_root: leaders.vouchers_snapshot_root(),
|
||||
tx_hash_view: &tx_hash_view,
|
||||
},
|
||||
)
|
||||
// let proof =
|
||||
// Groth16LeaderClaimProof::new(CompressedGroth16Proof::from_bytes(&[0u8;
|
||||
// 128]));
|
||||
let err = preverified_signed_operation
|
||||
.verify(&LeaderClaimVerificationContext {
|
||||
nullifiers: leaders.nullifiers(),
|
||||
claimable_vouchers_root: leaders.vouchers_snapshot_root(),
|
||||
tx_hash_view: &tx_hash_view,
|
||||
})
|
||||
.unwrap_err();
|
||||
assert_eq!(err, LeaderClaimError::DuplicatedVoucherNullifier);
|
||||
}
|
||||
@@ -2190,9 +2233,11 @@ mod tests {
|
||||
assert!(difficulty_at(&test_ledger, block_1) > genesis_difficulty);
|
||||
}
|
||||
|
||||
fn claim_tx() -> MantleTransaction<Preverified> {
|
||||
let mantle_tx = RawMantleTx([Op::ClaimPowReward(claim_op())].into());
|
||||
MantleTransaction::new(mantle_tx, [OpProof::None(NoOpProof)].into())
|
||||
fn claim_tx() -> SignedOps<Preverified, StandardMode> {
|
||||
let mantle_tx = Ops::from([Op::ClaimPowReward(claim_op())]);
|
||||
let op_proofs = OpProofs::from([OpProof::None(NoOpProof)]);
|
||||
SignedOps::from_parts(mantle_tx, op_proofs)
|
||||
.unwrap()
|
||||
.preverify()
|
||||
.expect("claim op with OpProof::None should pass preverification")
|
||||
}
|
||||
@@ -2220,7 +2265,7 @@ mod tests {
|
||||
assert_eq!(state.mantle_ledger.pow.epoch_reward(), 0);
|
||||
|
||||
let err = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, &claim_tx())
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, claim_tx())
|
||||
.expect_err("claim should fail validation");
|
||||
|
||||
assert!(matches!(
|
||||
@@ -2239,7 +2284,7 @@ mod tests {
|
||||
let (state, config) = pow_ledger_state(1_000);
|
||||
|
||||
let err = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, &claim_tx())
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, claim_tx())
|
||||
.expect_err("claim should fail validation");
|
||||
|
||||
assert!(matches!(
|
||||
@@ -2276,7 +2321,7 @@ mod tests {
|
||||
let epoch_reward = state.mantle_ledger.pow.epoch_reward();
|
||||
|
||||
let (state, _balance, events) = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, &claim_tx())
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, claim_tx())
|
||||
.expect("claim should validate and execute");
|
||||
|
||||
assert_eq!(
|
||||
@@ -2315,11 +2360,11 @@ mod tests {
|
||||
// during tx-level validation.
|
||||
let (state, config) = claim_accepting_state();
|
||||
let (state, _, _) = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, &claim_tx())
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, claim_tx())
|
||||
.expect("first claim should succeed");
|
||||
|
||||
let err = state
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, &claim_tx())
|
||||
.try_apply_tx::<_, HeaderId, MainnetGasProfile>(&config, claim_tx())
|
||||
.expect_err("second claim should be rejected");
|
||||
|
||||
assert!(matches!(
|
||||
@@ -2346,11 +2391,14 @@ mod tests {
|
||||
let pool_before = state.mantle_ledger.pow.reward_pool();
|
||||
let epoch_reward = state.mantle_ledger.pow.epoch_reward();
|
||||
let op = claim_op();
|
||||
let signed_operation =
|
||||
SignedOperation::<_, _, StandardMode>::new(op.clone(), NoOpProof)
|
||||
.into_state_trusted();
|
||||
let tx_hash = TxHash::from([9u8; 32]);
|
||||
|
||||
let (state, _balance, events) = state
|
||||
.try_apply_op::<HeaderId, MainnetGasProfile>(
|
||||
&Op::ClaimPowReward(op.clone()),
|
||||
signed_operation.into(),
|
||||
&config,
|
||||
&tx_hash,
|
||||
0,
|
||||
@@ -2414,14 +2462,29 @@ mod tests {
|
||||
.add_seen_block_slots(claim_op().block_hash, Slot::from(0u64));
|
||||
let pool_before = state.mantle_ledger.pow.reward_pool();
|
||||
let epoch_reward = state.mantle_ledger.pow.epoch_reward();
|
||||
let op = Op::ClaimPowReward(claim_op());
|
||||
let op = claim_op();
|
||||
let signed_operation =
|
||||
SignedOperation::<_, _, StandardMode>::new(op, NoOpProof).into_state_trusted();
|
||||
|
||||
let tx_hash = TxHash::from([9u8; 32]);
|
||||
|
||||
let (state, _, _) = state
|
||||
.try_apply_op::<HeaderId, MainnetGasProfile>(&op, &config, &tx_hash, 0, Vec::new())
|
||||
.try_apply_op::<HeaderId, MainnetGasProfile>(
|
||||
signed_operation.clone().into(),
|
||||
&config,
|
||||
&tx_hash,
|
||||
0,
|
||||
Vec::new(),
|
||||
)
|
||||
.expect("first claim should succeed");
|
||||
let (state, _, _) = state
|
||||
.try_apply_op::<HeaderId, MainnetGasProfile>(&op, &config, &tx_hash, 0, Vec::new())
|
||||
.try_apply_op::<HeaderId, MainnetGasProfile>(
|
||||
signed_operation.into(),
|
||||
&config,
|
||||
&tx_hash,
|
||||
0,
|
||||
Vec::new(),
|
||||
)
|
||||
.expect("second claim currently also succeeds (no validation)");
|
||||
|
||||
assert_eq!(
|
||||
|
||||
+15
-11
@@ -9,8 +9,9 @@ use lb_core::{
|
||||
events::TxEvent,
|
||||
mantle::{
|
||||
NoteId, Value,
|
||||
ledger::ExecutableOperation as _,
|
||||
ledger::verification_mode::{GenesisMode, StandardMode},
|
||||
ops::{
|
||||
SignedOperation,
|
||||
channel::{
|
||||
config::{ChannelConfigExecutionContext, ChannelConfigOp},
|
||||
inscribe::{InscriptionExecutionContext, InscriptionOp},
|
||||
@@ -20,7 +21,7 @@ use lb_core::{
|
||||
sdp::{SDPActiveOp, SDPDeclareOp, SDPWithdrawOp},
|
||||
transfer::TransferError,
|
||||
},
|
||||
traits::GenesisTx,
|
||||
transactions::states::{Preverified, Verified},
|
||||
},
|
||||
sdp::locked_notes::LockedNotes,
|
||||
};
|
||||
@@ -76,14 +77,15 @@ impl LedgerState {
|
||||
}
|
||||
|
||||
pub fn from_genesis_tx(
|
||||
tx: impl GenesisTx,
|
||||
signed_operation_inscription: SignedOperation<InscriptionOp, Verified, GenesisMode>,
|
||||
signed_operation_declarations: Vec<SignedOperation<SDPDeclareOp, Preverified, GenesisMode>>,
|
||||
config: &Config,
|
||||
utxo_tree: &UtxoTree,
|
||||
epoch_state: &EpochState,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let mut tx_events = Vec::new();
|
||||
|
||||
let (channels, events) = channel::Channels::from_genesis(tx.genesis_inscription())?;
|
||||
let (channels, events) = channel::Channels::from_genesis(signed_operation_inscription)?;
|
||||
tx_events.extend(events);
|
||||
|
||||
let (sdp, events) = sdp::SdpLedger::from_genesis(
|
||||
@@ -91,7 +93,7 @@ impl LedgerState {
|
||||
utxo_tree,
|
||||
&channels,
|
||||
epoch_state,
|
||||
tx.sdp_declarations(),
|
||||
signed_operation_declarations,
|
||||
)?;
|
||||
tx_events.extend(events);
|
||||
|
||||
@@ -175,14 +177,15 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_channel_inscription(
|
||||
mut self,
|
||||
inscription_op: &InscriptionOp,
|
||||
signed_operation: SignedOperation<InscriptionOp, Verified, StandardMode>,
|
||||
block_slot: Slot,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (result, events) = inscription_op
|
||||
let (result, events) = signed_operation
|
||||
.execute(InscriptionExecutionContext {
|
||||
channels: self.channels,
|
||||
block_slot,
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)
|
||||
.inspect_err(
|
||||
|err| error!(target: LOG_TARGET, %err, "failed to apply channel inscribe message"),
|
||||
)?;
|
||||
@@ -193,7 +196,7 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_channel_config(
|
||||
mut self,
|
||||
config_op: &ChannelConfigOp,
|
||||
config_op: SignedOperation<ChannelConfigOp, Verified, StandardMode>,
|
||||
block_slot: Slot,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (result, events) = config_op
|
||||
@@ -201,6 +204,7 @@ impl LedgerState {
|
||||
channels: self.channels,
|
||||
block_slot,
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)
|
||||
.inspect_err(
|
||||
|err| error!(target: LOG_TARGET, %err, "failed to apply channel set-keys message"),
|
||||
)?;
|
||||
@@ -211,7 +215,7 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_sdp_declaration(
|
||||
mut self,
|
||||
sdp_declare_op: &SDPDeclareOp,
|
||||
sdp_declare_op: SignedOperation<SDPDeclareOp, Verified, StandardMode>,
|
||||
utxo_tree: &UtxoTree,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
@@ -227,7 +231,7 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_sdp_active(
|
||||
mut self,
|
||||
sdp_active_op: &SDPActiveOp,
|
||||
sdp_active_op: SignedOperation<SDPActiveOp, Verified, StandardMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (result, events) = self
|
||||
@@ -242,7 +246,7 @@ impl LedgerState {
|
||||
|
||||
pub fn try_apply_sdp_withdraw(
|
||||
mut self,
|
||||
sdp_withdraw_op: &SDPWithdrawOp,
|
||||
sdp_withdraw_op: SignedOperation<SDPWithdrawOp, Verified, StandardMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (result, events) = self
|
||||
|
||||
+163
-81
@@ -9,14 +9,18 @@ use lb_core::{
|
||||
block::BlockNumber,
|
||||
events::{HeaderEvent, TxEvent},
|
||||
mantle::{
|
||||
NoteId, OpProof, Utxo, Value,
|
||||
NoteId, Utxo, Value,
|
||||
channel::Channels,
|
||||
ledger::{ExecutableOperation, VerifiableOperation, verification_mode::GenesisMode},
|
||||
ops::sdp::{
|
||||
SDPActiveExecutionContext, SDPActiveOp, SDPDeclareExecutionContext, SDPDeclareOp,
|
||||
SDPWithdrawExecutionContext, SDPWithdrawOp,
|
||||
declare::SDPDeclareGenesisValidationContext,
|
||||
ledger::verification_mode::{GenesisMode, StandardMode},
|
||||
ops::{
|
||||
SignedOperation,
|
||||
sdp::{
|
||||
SDPActiveExecutionContext, SDPActiveOp, SDPDeclareExecutionContext, SDPDeclareOp,
|
||||
SDPWithdrawExecutionContext, SDPWithdrawOp,
|
||||
declare::SDPDeclareGenesisValidationContext,
|
||||
},
|
||||
},
|
||||
transactions::states::{Preverified, Verified},
|
||||
},
|
||||
sdp::{
|
||||
ActivityMetadata, Declaration, DeclarationId, MinStake, Nonce, ProviderId,
|
||||
@@ -300,42 +304,37 @@ impl SdpLedger {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_genesis<'a>(
|
||||
pub fn from_genesis(
|
||||
config: &Config,
|
||||
utxo_tree: &UtxoTree,
|
||||
channels: &Channels,
|
||||
epoch_state: &EpochState,
|
||||
ops: impl Iterator<Item = (&'a SDPDeclareOp, &'a OpProof)> + 'a,
|
||||
declarations: impl IntoIterator<Item = SignedOperation<SDPDeclareOp, Preverified, GenesisMode>>,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let mut sdp = Self::new(epoch_state.epoch())
|
||||
.with_blend_service(&config.service_rewards_params.blend, epoch_state);
|
||||
|
||||
let mut all_events = Vec::new();
|
||||
for (op, proof) in ops {
|
||||
// TODO: remove this match once op/proof pairing is enforced by
|
||||
// construction (e.g. via `SignedOp`) instead of at this call site.
|
||||
let OpProof::ZkAndEd25519Sigs(proof) = proof else {
|
||||
return Err(Error::InvalidProof);
|
||||
for declaration in declarations {
|
||||
let service_state = {
|
||||
let operation = declaration.operation();
|
||||
sdp.services
|
||||
.get(&operation.service_type)
|
||||
.ok_or(Error::ServiceNotFound(operation.service_type))?
|
||||
};
|
||||
|
||||
let service_state = sdp
|
||||
.services
|
||||
.get(&op.service_type)
|
||||
.ok_or(Error::ServiceNotFound(op.service_type))?;
|
||||
|
||||
<SDPDeclareOp as VerifiableOperation<GenesisMode>>::verify(
|
||||
op,
|
||||
proof,
|
||||
&SDPDeclareGenesisValidationContext {
|
||||
let verified_declaration = declaration
|
||||
.into_verified(&SDPDeclareGenesisValidationContext {
|
||||
utxo_tree,
|
||||
channels,
|
||||
locked_notes: &sdp.locked_notes,
|
||||
declarations: service_state.declarations(),
|
||||
min_stake: &config.min_stake,
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
|
||||
let (result, events) = sdp.try_apply_genesis_sdp_declaration(utxo_tree, op, config)?;
|
||||
let (result, events) =
|
||||
sdp.try_apply_genesis_sdp_declaration(utxo_tree, verified_declaration, config)?;
|
||||
sdp = result;
|
||||
all_events.extend(events);
|
||||
}
|
||||
@@ -417,24 +416,25 @@ impl SdpLedger {
|
||||
pub fn try_apply_genesis_sdp_declaration(
|
||||
mut self,
|
||||
utxo_tree: &UtxoTree,
|
||||
op: &SDPDeclareOp,
|
||||
declaration: SignedOperation<SDPDeclareOp, Verified, GenesisMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let Some(service_state) = self.services.get_mut(&op.service_type) else {
|
||||
return Err(Error::ServiceNotFound(op.service_type));
|
||||
let operation = declaration.operation();
|
||||
|
||||
let Some(service_state) = self.services.get_mut(&operation.service_type) else {
|
||||
return Err(Error::ServiceNotFound(operation.service_type));
|
||||
};
|
||||
|
||||
// Execute SDP Declare
|
||||
let (result, events) = <SDPDeclareOp as ExecutableOperation>::execute(
|
||||
op,
|
||||
SDPDeclareExecutionContext {
|
||||
let (result, events) = declaration
|
||||
.execute(SDPDeclareExecutionContext {
|
||||
utxo_tree: utxo_tree.clone(),
|
||||
epoch: self.epoch,
|
||||
declarations: service_state.declarations_clone(),
|
||||
locked_notes: self.locked_notes.clone(),
|
||||
min_stake: config.min_stake,
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
|
||||
self.locked_notes = result.locked_notes;
|
||||
service_state.update_declarations(result.declarations);
|
||||
@@ -444,23 +444,23 @@ impl SdpLedger {
|
||||
pub fn try_apply_sdp_declaration(
|
||||
mut self,
|
||||
utxo_tree: &UtxoTree,
|
||||
op: &SDPDeclareOp,
|
||||
signed_operation: SignedOperation<SDPDeclareOp, Verified, StandardMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let Some(service_state) = self.services.get_mut(&op.service_type) else {
|
||||
return Err(Error::ServiceNotFound(op.service_type));
|
||||
let operation = signed_operation.operation();
|
||||
let Some(service_state) = self.services.get_mut(&operation.service_type) else {
|
||||
return Err(Error::ServiceNotFound(operation.service_type));
|
||||
};
|
||||
|
||||
let (result, events) = <SDPDeclareOp as ExecutableOperation>::execute(
|
||||
op,
|
||||
SDPDeclareExecutionContext {
|
||||
let (result, events) = signed_operation
|
||||
.execute(SDPDeclareExecutionContext {
|
||||
utxo_tree: utxo_tree.clone(),
|
||||
epoch: self.epoch,
|
||||
declarations: service_state.declarations_clone(),
|
||||
locked_notes: self.locked_notes.clone(),
|
||||
min_stake: config.min_stake,
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
|
||||
self.locked_notes = result.locked_notes;
|
||||
service_state.update_declarations(result.declarations);
|
||||
@@ -469,46 +469,60 @@ impl SdpLedger {
|
||||
|
||||
pub fn apply_active_msg(
|
||||
mut self,
|
||||
op: &SDPActiveOp,
|
||||
signed_operation: SignedOperation<SDPActiveOp, Verified, StandardMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (service, _) = self.get_service(&op.declaration_id, config)?;
|
||||
let operation = signed_operation.operation();
|
||||
let operation_declaration_id = operation.declaration_id;
|
||||
let operation_metadata = operation.metadata.clone();
|
||||
|
||||
let (service, _) = self.get_service(&operation.declaration_id, config)?;
|
||||
let Some(service_state) = self.services.get_mut(&service) else {
|
||||
return Err(Error::ServiceNotFound(service));
|
||||
};
|
||||
|
||||
let (result, events) = op.execute(SDPActiveExecutionContext {
|
||||
epoch: self.epoch,
|
||||
declarations: service_state.declarations_clone(),
|
||||
})?;
|
||||
let (result, events) = signed_operation
|
||||
.execute(SDPActiveExecutionContext {
|
||||
epoch: self.epoch,
|
||||
declarations: service_state.declarations_clone(),
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
|
||||
let provider_id = result
|
||||
.declarations
|
||||
.get(&op.declaration_id)
|
||||
.get(&operation_declaration_id)
|
||||
.expect("the declaration should be in the list after execution")
|
||||
.provider_id;
|
||||
|
||||
service_state.update_declarations(result.declarations);
|
||||
service_state.update_rewards(provider_id, &op.metadata, &config.service_rewards_params)?;
|
||||
service_state.update_rewards(
|
||||
provider_id,
|
||||
&operation_metadata,
|
||||
&config.service_rewards_params,
|
||||
)?;
|
||||
|
||||
Ok((self, events))
|
||||
}
|
||||
|
||||
pub fn apply_withdrawn_msg(
|
||||
mut self,
|
||||
op: &SDPWithdrawOp,
|
||||
signed_operation: SignedOperation<SDPWithdrawOp, Verified, StandardMode>,
|
||||
config: &Config,
|
||||
) -> Result<(Self, Vec<TxEvent>), Error> {
|
||||
let (service, _) = self.get_service(&op.declaration_id, config)?;
|
||||
let operation = signed_operation.operation();
|
||||
|
||||
let (service, _) = self.get_service(&operation.declaration_id, config)?;
|
||||
let Some(service_state) = self.services.get_mut(&service) else {
|
||||
return Err(Error::ServiceNotFound(service));
|
||||
};
|
||||
|
||||
let (result, events) = op.execute(SDPWithdrawExecutionContext {
|
||||
declarations: service_state.declarations_clone(),
|
||||
locked_notes: self.locked_notes.clone(),
|
||||
epoch: self.epoch,
|
||||
})?;
|
||||
let (result, events) = signed_operation
|
||||
.execute(SDPWithdrawExecutionContext {
|
||||
declarations: service_state.declarations_clone(),
|
||||
locked_notes: self.locked_notes.clone(),
|
||||
epoch: self.epoch,
|
||||
})
|
||||
.map_err(|(_signed_operation, error)| error)?;
|
||||
|
||||
self.locked_notes = result.locked_notes;
|
||||
service_state.update_declarations(result.declarations);
|
||||
@@ -637,11 +651,11 @@ mod tests {
|
||||
use std::{num::NonZeroU64, sync::Arc};
|
||||
|
||||
use lb_core::{
|
||||
mantle::ledger::Utxos,
|
||||
mantle::{ledger::Utxos, ops::ZkAndEd25519Proof},
|
||||
sdp::{Locator, SNAPSHOT_FINALIZATION_DELAY},
|
||||
};
|
||||
use lb_groth16::{AdditiveGroup as _, Fr};
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, ZkKey};
|
||||
use lb_groth16::{AdditiveGroup as _, CompressedGroth16Proof, Fr};
|
||||
use lb_key_management_system_keys::keys::{Ed25519Key, Ed25519Signature, ZkKey, ZkSignature};
|
||||
use lb_utils::math::NonNegativeF64;
|
||||
use num_bigint::BigUint;
|
||||
|
||||
@@ -768,7 +782,7 @@ mod tests {
|
||||
let (_utxo_sk, utxo) = utxo_with_sk();
|
||||
let signing_key = create_signing_key();
|
||||
let zk_key = create_zk_key(1);
|
||||
let declare_op = &SDPDeclareOp {
|
||||
let declare_op = SDPDeclareOp {
|
||||
service_type: ServiceType::BlendNetwork,
|
||||
locked_note_id: utxo.id(),
|
||||
zk_id: zk_key.to_public_key(),
|
||||
@@ -776,8 +790,14 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation = SignedOperation::new(declare_op, proof).into_state_trusted();
|
||||
|
||||
let ledger = ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), signed_operation, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -821,7 +841,7 @@ mod tests {
|
||||
let (_utxo_sk, utxo) = utxo_with_sk();
|
||||
let signing_key = create_signing_key();
|
||||
let zk_key = create_zk_key(1);
|
||||
let declare_op = &SDPDeclareOp {
|
||||
let declare_op = SDPDeclareOp {
|
||||
service_type: ServiceType::BlendNetwork,
|
||||
locked_note_id: utxo.id(),
|
||||
zk_id: zk_key.to_public_key(),
|
||||
@@ -829,8 +849,14 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation = SignedOperation::new(declare_op, proof).into_state_trusted();
|
||||
|
||||
let ledger = ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), signed_operation, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -874,7 +900,7 @@ mod tests {
|
||||
let note_id = utxo.id();
|
||||
let signing_key = create_signing_key();
|
||||
let zk_key = create_zk_key(1);
|
||||
let declare_op = &SDPDeclareOp {
|
||||
let declare_op = SDPDeclareOp {
|
||||
service_type: ServiceType::BlendNetwork,
|
||||
locked_note_id: note_id,
|
||||
zk_id: zk_key.to_public_key(),
|
||||
@@ -882,19 +908,29 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare = SignedOperation::new(declare_op, proof).into_state_trusted();
|
||||
|
||||
let ledger = ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), signed_operation_declare, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
// Withdraw at epoch 1: `withdrawn = 1 + SNAPSHOT_FINALIZATION_DELAY = 3`.
|
||||
let withdraw_op = &SDPWithdrawOp {
|
||||
let withdraw_op = SDPWithdrawOp {
|
||||
declaration_id,
|
||||
nonce: 1,
|
||||
locked_note_id: note_id,
|
||||
};
|
||||
let proof = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_operation_withdraw =
|
||||
SignedOperation::new(withdraw_op, proof).into_state_trusted();
|
||||
|
||||
let ledger = ledger
|
||||
.apply_withdrawn_msg(withdraw_op, &config)
|
||||
.apply_withdrawn_msg(signed_operation_withdraw, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
let withdraw_at = ledger
|
||||
@@ -957,8 +993,15 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare =
|
||||
SignedOperation::new(declare_op.clone(), proof).into_state_trusted();
|
||||
|
||||
ledger = ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), signed_operation_declare, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
let declarations = ledger
|
||||
@@ -994,8 +1037,11 @@ mod tests {
|
||||
&config.service_rewards_params.blend,
|
||||
))),
|
||||
};
|
||||
let proof = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_operation_active = SignedOperation::new(active_op, proof).into_state_trusted();
|
||||
|
||||
ledger = ledger
|
||||
.apply_active_msg(&active_op, &config)
|
||||
.apply_active_msg(signed_operation_active, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
let declarations = ledger
|
||||
@@ -1054,7 +1100,7 @@ mod tests {
|
||||
let note_id = utxo.id();
|
||||
let signing_key = create_signing_key();
|
||||
let zk_key = create_zk_key(1);
|
||||
let declare_op = &SDPDeclareOp {
|
||||
let declare_op = SDPDeclareOp {
|
||||
service_type: ServiceType::BlendNetwork,
|
||||
locked_note_id: note_id,
|
||||
zk_id: zk_key.to_public_key(),
|
||||
@@ -1062,8 +1108,14 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare = SignedOperation::new(declare_op, proof).into_state_trusted();
|
||||
|
||||
ledger = ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree(vec![utxo]), signed_operation_declare, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -1092,8 +1144,11 @@ mod tests {
|
||||
&config.service_rewards_params.blend,
|
||||
))),
|
||||
};
|
||||
let proof = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_operation_active = SignedOperation::new(active_op, proof).into_state_trusted();
|
||||
|
||||
let ledger = ledger
|
||||
.apply_active_msg(&active_op, &config)
|
||||
.apply_active_msg(signed_operation_active, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -1161,13 +1216,19 @@ mod tests {
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declaration_id_a = declare_a.id();
|
||||
let proof_a = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare_a =
|
||||
SignedOperation::new(declare_a, proof_a).into_state_trusted();
|
||||
|
||||
let epoch0 = dummy_epoch_state(0.into());
|
||||
let sdp_ledger = dummy_sdp_ledger(0.into(), &config);
|
||||
let utxos = utxo_tree(vec![utxo_a, utxo_b]);
|
||||
|
||||
let sdp_ledger = sdp_ledger
|
||||
.try_apply_sdp_declaration(&utxos, &declare_a, &config)
|
||||
.try_apply_sdp_declaration(&utxos, signed_operation_declare_a, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -1177,8 +1238,12 @@ mod tests {
|
||||
nonce: 1,
|
||||
locked_note_id: utxo_a.id(),
|
||||
};
|
||||
let proof_withdraw = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_operation_withdraw =
|
||||
SignedOperation::new(withdraw_op, proof_withdraw).into_state_trusted();
|
||||
|
||||
let (sdp_ledger, _events) = sdp_ledger
|
||||
.apply_withdrawn_msg(&withdraw_op, &config)
|
||||
.apply_withdrawn_msg(signed_operation_withdraw, &config)
|
||||
.unwrap();
|
||||
|
||||
let withdraw_epoch = sdp_ledger
|
||||
@@ -1211,8 +1276,15 @@ mod tests {
|
||||
provider_id: ProviderId(signing_key.public_key()),
|
||||
locators: "/ip4/2.2.2.2/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let proof_b = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare_b =
|
||||
SignedOperation::new(declare_b, proof_b).into_state_trusted();
|
||||
|
||||
sdp_ledger
|
||||
.try_apply_sdp_declaration(&utxos, &declare_b, &config)
|
||||
.try_apply_sdp_declaration(&utxos, signed_operation_declare_b, &config)
|
||||
.expect(
|
||||
"Declaration reusing A's provider_id and zk_id must be accepted after A is removed",
|
||||
);
|
||||
@@ -1231,14 +1303,20 @@ mod tests {
|
||||
let signing_key = create_signing_key();
|
||||
let zk_key = create_zk_key(1);
|
||||
|
||||
let declare_op = &SDPDeclareOp {
|
||||
let declare_op = SDPDeclareOp {
|
||||
service_type: service_a,
|
||||
locked_note_id: note_id,
|
||||
zk_id: zk_key.to_public_key(),
|
||||
provider_id: ProviderId(signing_key.public_key()),
|
||||
locators: "/ip4/1.1.1.1/udp/0".parse::<Locator>().unwrap().into(),
|
||||
};
|
||||
let declare_locked_note_id = declare_op.locked_note_id;
|
||||
let declaration_id = declare_op.id();
|
||||
let proof = ZkAndEd25519Proof {
|
||||
zk_sig: ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128])),
|
||||
ed25519_sig: Ed25519Signature::zero(),
|
||||
};
|
||||
let signed_operation_declare = SignedOperation::new(declare_op, proof).into_state_trusted();
|
||||
|
||||
// Initialize ledger with service config and declare
|
||||
let epoch0 = dummy_epoch_state(0.into());
|
||||
@@ -1246,7 +1324,7 @@ mod tests {
|
||||
|
||||
let utxo_tree = utxo_tree(vec![utxo]);
|
||||
let sdp_ledger = sdp_ledger
|
||||
.try_apply_sdp_declaration(&utxo_tree, declare_op, &config)
|
||||
.try_apply_sdp_declaration(&utxo_tree, signed_operation_declare, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -1254,13 +1332,17 @@ mod tests {
|
||||
assert!(sdp_ledger.get_declaration(&declaration_id).is_some());
|
||||
|
||||
// Withdraw the declaration
|
||||
let withdraw_op = &SDPWithdrawOp {
|
||||
let withdraw_op = SDPWithdrawOp {
|
||||
declaration_id,
|
||||
nonce: 1,
|
||||
locked_note_id: note_id,
|
||||
};
|
||||
let proof_withdraw = ZkSignature::new(CompressedGroth16Proof::from_bytes(&[0u8; 128]));
|
||||
let signed_operation_withdraw =
|
||||
SignedOperation::new(withdraw_op, proof_withdraw).into_state_trusted();
|
||||
|
||||
let sdp_ledger = sdp_ledger
|
||||
.apply_withdrawn_msg(withdraw_op, &config)
|
||||
.apply_withdrawn_msg(signed_operation_withdraw, &config)
|
||||
.map(|(sdp_ledger, _)| sdp_ledger)
|
||||
.unwrap();
|
||||
|
||||
@@ -1293,7 +1375,7 @@ mod tests {
|
||||
assert!(
|
||||
sdp_ledger
|
||||
.locked_notes()
|
||||
.is_locked_for_service(&declare_op.locked_note_id, &ServiceType::BlendNetwork),
|
||||
.is_locked_for_service(&declare_locked_note_id, &ServiceType::BlendNetwork),
|
||||
"the provider's note must still be locked before the withdrawn epoch is reached"
|
||||
);
|
||||
|
||||
@@ -1315,7 +1397,7 @@ mod tests {
|
||||
assert!(
|
||||
!sdp_ledger
|
||||
.locked_notes()
|
||||
.is_locked_for_service(&declare_op.locked_note_id, &ServiceType::BlendNetwork),
|
||||
.is_locked_for_service(&declare_locked_note_id, &ServiceType::BlendNetwork),
|
||||
"the provider's note must be unlocked at the withdrawn epoch"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user