     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55

    use chain::Transaction;
    use ser::Serializable;
    use storage::TransactionProvider;

    pub fn transaction_fee(store: &TransactionProvider, transaction: &Transaction) -> u64 {
    	let inputs_sum = transaction.inputs.iter().map(|input| {
    		let input_transaction = store.transaction(&input.previous_output.hash)
    			.expect("transaction must be verified by caller");
    		input_transaction.outputs[input.previous_output.index as usize].value
    	}).sum::<u64>();
    	let outputs_sum = transaction.outputs.iter().map(|output| output.value).sum();
    	inputs_sum.saturating_sub(outputs_sum)
    }

    pub fn transaction_fee_rate(store: &TransactionProvider, transaction: &Transaction) -> u64 {
    	transaction_fee(store, transaction) / transaction.serialized_size() as u64
    }

    #[cfg(test)]
    mod tests {
    	extern crate test_data;

    	use std::sync::Arc;
    	use storage::{AsSubstore};
    	use db::BlockChainDatabase;
    	use super::*;

    	#[test]
    	fn test_transaction_fee() {
    		let b0 = test_data::block_builder().header().nonce(1).build()
    			.transaction()
    				.output().value(1_000_000).build()
    				.output().value(2_000_000).build()
    				.build()
    			.build();
    		let tx0 = b0.transactions[0].clone();
    		let tx0_hash = tx0.hash();
    		let b1 = test_data::block_builder().header().parent(b0.hash().clone()).nonce(2).build()
    			.transaction()
    				.input().hash(tx0_hash.clone()).index(0).build()
    				.input().hash(tx0_hash).index(1).build()
    				.output().value(2_500_000).build()
    				.build()
    			.build();
    		let tx2 = b1.transactions[0].clone();

    		let db = Arc::new(BlockChainDatabase::init_test_chain(vec![b0.into(), b1.into()]));

    		assert_eq!(transaction_fee(db.as_transaction_provider(), &tx0), 0);
    		assert_eq!(transaction_fee(db.as_transaction_provider(), &tx2), 500_000);

    		assert_eq!(transaction_fee_rate(db.as_transaction_provider(), &tx0), 0);
    		assert_eq!(transaction_fee_rate(db.as_transaction_provider(), &tx2), 4_901);
    	}
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g. `str,u8` or `String,struct:Vec,test`)