Skip to content

Commit

Permalink
feat!: adding fee output type
Browse files Browse the repository at this point in the history
- Adding a Token::is_zero API.
- Re-adding workflow file for automatic releases.
  • Loading branch information
bochaco committed Jul 3, 2023
1 parent a4481fa commit 4fc5aa5
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 10 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/auto_merge_prs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# auto merge workflow.
#
# Auto merge PR if commit msg begins with `chore(release):`,
# or if it has been raised by Dependabot.
# Uses https://github.com/ridedott/merge-me-action.

name: Merge Version Change and Dependabot PRs automatically

on: pull_request

jobs:
merge:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '0'

- name: get commit message
run: |
commitmsg=$(git log --format=%s -n 1 ${{ github.event.pull_request.head.sha }})
echo "commitmsg=${commitmsg}" >> $GITHUB_ENV
- name: show commit message
run : echo $commitmsg

- name: Merge Version change PR
if: startsWith( env.commitmsg, 'chore(release):')
uses: ridedott/merge-me-action@81667e6ae186ddbe6d3c3186d27d91afa7475e2c
with:
GITHUB_LOGIN: dirvine
GITHUB_TOKEN: ${{ secrets.MERGE_BUMP_BRANCH_TOKEN }}
MERGE_METHOD: REBASE

- name: Dependabot Merge
uses: ridedott/merge-me-action@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MERGE_METHOD: REBASE
17 changes: 15 additions & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use crate::{
transaction::{DbcTransaction, Output},
DbcId, DerivationIndex, DerivedKey, Input, PublicAddress, Spend,
DbcId, DerivationIndex, DerivedKey, FeeOutput, Input, PublicAddress, Spend,
};
use crate::{Dbc, DbcCiphers, Error, Hash, Result, SignedSpend, Token};
#[cfg(feature = "serde")]
Expand All @@ -24,6 +24,7 @@ pub type InputSrcTx = DbcTransaction;
pub struct TransactionBuilder {
inputs: Vec<Input>,
outputs: Vec<Output>,
fee: FeeOutput,
input_details: BTreeMap<DbcId, (DerivedKey, InputSrcTx)>,
output_details: BTreeMap<DbcId, (PublicAddress, DerivationIndex)>,
}
Expand Down Expand Up @@ -100,6 +101,12 @@ impl TransactionBuilder {
self
}

/// Sets the given fee output.
pub fn set_fee_output(mut self, output: FeeOutput) -> Self {
self.fee = output;
self
}

/// Get a list of input ids.
pub fn input_ids(&self) -> Vec<DbcId> {
self.inputs.iter().map(|i| i.dbc_id()).collect()
Expand All @@ -113,7 +120,12 @@ impl TransactionBuilder {

/// Get sum of output Tokens.
pub fn outputs_tokens_sum(&self) -> Token {
let amount = self.outputs.iter().map(|o| o.token.as_nano()).sum();
let amount = self
.outputs
.iter()
.map(|o| o.token.as_nano())
.chain(std::iter::once(self.fee.token.as_nano()))
.sum();
Token::from_nano(amount)
}

Expand All @@ -132,6 +144,7 @@ impl TransactionBuilder {
let spent_tx = DbcTransaction {
inputs: self.inputs.clone(),
outputs: self.outputs.clone(),
fee: self.fee.clone(),
};
let signed_spends: BTreeSet<_> = self
.inputs
Expand Down
19 changes: 17 additions & 2 deletions src/dbc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use crate::{
dbc_id::PublicAddress, transaction::DbcTransaction, DbcCiphers, DbcId, DerivationIndex,
DerivedKey, Error, Hash, MainKey, Result, SignedSpend, Token,
DerivedKey, Error, FeeOutput, Hash, MainKey, Result, SignedSpend, Token,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -96,6 +96,11 @@ impl Dbc {
self.ciphers.derivation_index(main_key)
}

/// Return the fee output used in the source transaction
pub fn fee_output(&self) -> &FeeOutput {
&self.src_tx.fee
}

/// Return the reason why this Dbc was spent.
/// Will be the default Hash (empty) if reason is none.
pub fn reason(&self) -> Hash {
Expand Down Expand Up @@ -194,7 +199,7 @@ pub(crate) mod tests {
mock,
rand::{CryptoRng, RngCore},
transaction::Output,
Hash, Token,
FeeOutput, Hash, Token,
};
use blsttc::{PublicKey, SecretKey};
use std::convert::TryInto;
Expand All @@ -209,6 +214,7 @@ pub(crate) mod tests {
let tx = DbcTransaction {
inputs: vec![],
outputs: vec![Output::new(derived_key.dbc_id(), amount)],
fee: FeeOutput::new(Hash::default(), 3_500, Hash::default()),
};
let ciphers = DbcCiphers::from((&main_key.public_address(), &derivation_index));
let dbc = Dbc {
Expand All @@ -222,6 +228,10 @@ pub(crate) mod tests {

let dbc = Dbc::from_hex(&hex)?;
assert_eq!(dbc.token()?.as_nano(), 1_530_000_000);

let fee_amount = dbc.fee_output().token;
assert_eq!(fee_amount, Token::from_nano(3_500));

Ok(())
}

Expand All @@ -235,6 +245,7 @@ pub(crate) mod tests {
let tx = DbcTransaction {
inputs: vec![],
outputs: vec![Output::new(derived_key.dbc_id(), amount)],
fee: FeeOutput::new(Hash::default(), 2_500, Hash::default()),
};
let ciphers = DbcCiphers::from((&main_key.public_address(), &derivation_index));
let dbc = Dbc {
Expand All @@ -249,6 +260,9 @@ pub(crate) mod tests {

assert_eq!(dbc.token()?, dbc_from_hex.token()?);

let fee_amount = dbc.fee_output().token;
assert_eq!(fee_amount, Token::from_nano(2_500));

Ok(())
}

Expand Down Expand Up @@ -286,6 +300,7 @@ pub(crate) mod tests {
let tx = DbcTransaction {
inputs: vec![],
outputs: vec![Output::new(derived_key.dbc_id(), amount)],
fee: FeeOutput::default(),
};

let ciphers = DbcCiphers::from((&main_key.public_address(), &derivation_index));
Expand Down
56 changes: 56 additions & 0 deletions src/fee_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2023, MaidSafe.
// All rights reserved.
//
// This SAFE Network Software is licensed under the BSD-3-Clause license.
// Please see the LICENSE file for more details.

use crate::{Hash, Token};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FeeOutput {
/// The id is expected (in order to be accepted by the network) to be built from: hash(root_hash + inputs' ids).
/// This requirement makes it possible for this output to be used as an input in a rewards/farming
/// claiming Tx, by making its spend location deterministic, analogous to how any other output
/// is spent using its id to determine the location to store the signed spend.
pub id: Hash,
/// Amount being paid as storage fee to the network.
pub token: Token,
/// The root hash of the proof's Merkletree corresponding to the content being paid for.
pub root_hash: Hash,
}

impl Default for FeeOutput {
fn default() -> Self {
Self {
id: Hash::default(),
token: Token::zero(),
root_hash: Hash::default(),
}
}
}

impl FeeOutput {
pub fn new(id: Hash, amount: u64, root_hash: Hash) -> Self {
Self {
id,
token: Token::from_nano(amount),
root_hash,
}
}

pub fn is_free(&self) -> bool {
self.token.is_zero()
}

pub fn to_bytes(&self) -> Vec<u8> {
let mut v = Vec::<u8>::new();
v.extend(self.id.slice());
v.extend(self.token.to_bytes());
v.extend(self.root_hash.slice());
v
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod dbc;
mod dbc_ciphers;
mod dbc_id;
mod error;
mod fee_output;
mod signed_spend;
mod spentbook;
mod token;
Expand All @@ -27,6 +28,7 @@ pub use crate::{
dbc_ciphers::DbcCiphers,
dbc_id::{random_derivation_index, DbcId, DerivationIndex, DerivedKey, MainKey, PublicAddress},
error::{Error, Result},
fee_output::FeeOutput,
signed_spend::{SignedSpend, Spend},
token::Token,
transaction::{DbcTransaction, Input, Output},
Expand Down
8 changes: 3 additions & 5 deletions src/mock/genesis_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use crate::{
builder::InputSrcTx, transaction::Output, DbcId, DbcTransaction, DerivationIndex, DerivedKey,
Input, MainKey,
FeeOutput, Input, MainKey,
};
use blsttc::IntoFr;

Expand Down Expand Up @@ -51,12 +51,10 @@ impl Default for GenesisMaterial {
let genesis_tx = DbcTransaction {
inputs: vec![input],
outputs: vec![output],
fee: FeeOutput::default(),
};

let input_src_tx = DbcTransaction {
inputs: vec![],
outputs: vec![],
};
let input_src_tx = DbcTransaction::empty();

Self {
input_dbc_id: input_derived_key.dbc_id(), // the id of the fictional dbc being reissued to genesis dbc
Expand Down
5 changes: 5 additions & 0 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ impl Token {
Self(0)
}

/// Returns whether it's a representation of zero Token.
pub const fn is_zero(&self) -> bool {
self.0 == 0
}

/// New value from a number of nano tokens.
pub const fn from_nano(value: u64) -> Self {
Self(value)
Expand Down
14 changes: 13 additions & 1 deletion src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// This SAFE Network Software is licensed under the BSD-3-Clause license.
// Please see the LICENSE file for more details.

use crate::{DbcId, SignedSpend, Token};
use crate::{DbcId, FeeOutput, SignedSpend, Token};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{cmp::Ordering, collections::BTreeSet};
Expand Down Expand Up @@ -73,6 +73,7 @@ impl Output {
pub struct DbcTransaction {
pub inputs: Vec<Input>,
pub outputs: Vec<Output>,
pub fee: FeeOutput,
}

impl PartialEq for DbcTransaction {
Expand All @@ -96,6 +97,14 @@ impl Ord for DbcTransaction {
}

impl DbcTransaction {
pub fn empty() -> Self {
Self {
inputs: vec![],
outputs: vec![],
fee: FeeOutput::default(),
}
}

pub fn to_bytes(&self) -> Vec<u8> {
let mut v: Vec<u8> = Default::default();
v.extend("inputs".as_bytes());
Expand All @@ -106,6 +115,8 @@ impl DbcTransaction {
for o in self.outputs.iter() {
v.extend(&o.to_bytes());
}
v.extend("fee".as_bytes());
v.extend(&self.fee.to_bytes());
v.extend("end".as_bytes());
v
}
Expand Down Expand Up @@ -145,6 +156,7 @@ impl DbcTransaction {
.outputs
.iter()
.map(|o| o.token)
.chain(std::iter::once(self.fee.token))
.try_fold(0, |acc: u64, o| {
acc.checked_add(o.as_nano()).ok_or(Error::NumericOverflow)
})?;
Expand Down

0 comments on commit 4fc5aa5

Please sign in to comment.