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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use network::ConsensusFork;
use chain::Transaction;
use storage::TransactionOutputProvider;
use script::{Script, ScriptWitness};
pub fn transaction_sigops(
transaction: &Transaction,
store: &TransactionOutputProvider,
bip16_active: bool,
checkdatasig_active: bool,
) -> usize {
let output_sigops: usize = transaction.outputs.iter().map(|output| {
let output_script: Script = output.script_pubkey.clone().into();
output_script.sigops_count(checkdatasig_active, false)
}).sum();
if transaction.is_coinbase() {
return output_sigops;
}
let mut input_sigops = 0usize;
let mut bip16_sigops = 0usize;
for input in &transaction.inputs {
let input_script: Script = input.script_sig.clone().into();
input_sigops += input_script.sigops_count(checkdatasig_active, false);
if bip16_active {
let previous_output = match store.transaction_output(&input.previous_output, usize::max_value()) {
Some(output) => output,
None => continue,
};
let prevout_script: Script = previous_output.script_pubkey.into();
bip16_sigops += input_script.pay_to_script_hash_sigops(checkdatasig_active, &prevout_script);
}
}
input_sigops + output_sigops + bip16_sigops
}
pub fn transaction_sigops_cost(
transaction: &Transaction,
store: &TransactionOutputProvider,
sigops: usize,
) -> usize {
let sigops_cost = sigops * ConsensusFork::witness_scale_factor();
let witness_sigops_cost: usize = transaction.inputs.iter()
.map(|input| store.transaction_output(&input.previous_output, usize::max_value())
.map(|output| witness_sigops(&Script::new(input.script_sig.clone()), &Script::new(output.script_pubkey.clone()), &input.script_witness,))
.unwrap_or(0))
.sum();
sigops_cost + witness_sigops_cost
}
fn witness_sigops(
script_sig: &Script,
script_pubkey: &Script,
script_witness: &ScriptWitness,
) -> usize {
if let Some((witness_version, witness_program)) = script_pubkey.parse_witness_program() {
return witness_program_sigops(witness_version, witness_program, script_witness);
}
if script_pubkey.is_pay_to_script_hash() && script_sig.is_push_only() {
if let Some(Ok(instruction)) = script_sig.iter().last() {
if let Some(data) = instruction.data {
let subscript = Script::new(data.into());
if let Some((witness_version, witness_program)) = subscript.parse_witness_program() {
return witness_program_sigops(witness_version, witness_program, script_witness);
}
}
}
}
0
}
fn witness_program_sigops(
witness_version: u8,
witness_program: &[u8],
script_witness: &ScriptWitness,
) -> usize {
match witness_version {
0 if witness_program.len() == 20 => 1,
0 if witness_program.len() == 32 => match script_witness.last() {
Some(subscript) => Script::new(subscript.clone()).sigops_count(false, true),
_ => 0,
},
_ => 0,
}
}