cleaning up
This commit is contained in:
parent
14df21533d
commit
aa692d8a90
|
@ -23,8 +23,6 @@ pub struct ConsensusParams {
|
||||||
pub miner_confirmation_window: u32,
|
pub miner_confirmation_window: u32,
|
||||||
/// BIP68, BIP112, BIP113 deployment
|
/// BIP68, BIP112, BIP113 deployment
|
||||||
pub csv_deployment: Option<Deployment>,
|
pub csv_deployment: Option<Deployment>,
|
||||||
/// BIP141, BIP143, BIP147 deployment
|
|
||||||
pub segwit_deployment: Option<Deployment>,
|
|
||||||
|
|
||||||
/// Interval (in blocks) to calculate average work.
|
/// Interval (in blocks) to calculate average work.
|
||||||
pub pow_averaging_window: u32,
|
pub pow_averaging_window: u32,
|
||||||
|
@ -45,7 +43,6 @@ impl ConsensusParams {
|
||||||
bip34_height: 1,
|
bip34_height: 1,
|
||||||
bip65_height: 0,
|
bip65_height: 0,
|
||||||
bip66_height: 0,
|
bip66_height: 0,
|
||||||
segwit_deployment: None,
|
|
||||||
rule_change_activation_threshold: 1916, // 95%
|
rule_change_activation_threshold: 1916, // 95%
|
||||||
miner_confirmation_window: 2016,
|
miner_confirmation_window: 2016,
|
||||||
csv_deployment: None,
|
csv_deployment: None,
|
||||||
|
@ -61,7 +58,6 @@ impl ConsensusParams {
|
||||||
bip34_height: 1,
|
bip34_height: 1,
|
||||||
bip65_height: 0,
|
bip65_height: 0,
|
||||||
bip66_height: 0,
|
bip66_height: 0,
|
||||||
segwit_deployment: None,
|
|
||||||
rule_change_activation_threshold: 1512, // 75%
|
rule_change_activation_threshold: 1512, // 75%
|
||||||
miner_confirmation_window: 2016,
|
miner_confirmation_window: 2016,
|
||||||
csv_deployment: None,
|
csv_deployment: None,
|
||||||
|
@ -77,7 +73,6 @@ impl ConsensusParams {
|
||||||
bip34_height: 100000000,
|
bip34_height: 100000000,
|
||||||
bip65_height: 0,
|
bip65_height: 0,
|
||||||
bip66_height: 0,
|
bip66_height: 0,
|
||||||
segwit_deployment: None,
|
|
||||||
rule_change_activation_threshold: 108, // 75%
|
rule_change_activation_threshold: 108, // 75%
|
||||||
miner_confirmation_window: 144,
|
miner_confirmation_window: 144,
|
||||||
csv_deployment: None,
|
csv_deployment: None,
|
||||||
|
|
|
@ -87,8 +87,8 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
|
||||||
VerboseBlock {
|
VerboseBlock {
|
||||||
confirmations: confirmations,
|
confirmations: confirmations,
|
||||||
size: block_size as u32,
|
size: block_size as u32,
|
||||||
strippedsize: block_size as u32, // TODO: segwit
|
strippedsize: block_size as u32,
|
||||||
weight: block_size as u32, // TODO: segwit
|
weight: block_size as u32,
|
||||||
height: height,
|
height: height,
|
||||||
mediantime: Some(median_time),
|
mediantime: Some(median_time),
|
||||||
difficulty: block.header.raw.bits.to_f64(self.network.max_bits().into()),
|
difficulty: block.header.raw.bits.to_f64(self.network.max_bits().into()),
|
||||||
|
|
|
@ -11,8 +11,6 @@ pub enum ScriptType {
|
||||||
ScriptHash,
|
ScriptHash,
|
||||||
Multisig,
|
Multisig,
|
||||||
NullData,
|
NullData,
|
||||||
WitnessScript,
|
|
||||||
WitnessKey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<GlobalScriptType> for ScriptType {
|
impl From<GlobalScriptType> for ScriptType {
|
||||||
|
@ -24,8 +22,6 @@ impl From<GlobalScriptType> for ScriptType {
|
||||||
GlobalScriptType::ScriptHash => ScriptType::ScriptHash,
|
GlobalScriptType::ScriptHash => ScriptType::ScriptHash,
|
||||||
GlobalScriptType::Multisig => ScriptType::Multisig,
|
GlobalScriptType::Multisig => ScriptType::Multisig,
|
||||||
GlobalScriptType::NullData => ScriptType::NullData,
|
GlobalScriptType::NullData => ScriptType::NullData,
|
||||||
GlobalScriptType::WitnessScript => ScriptType::WitnessScript,
|
|
||||||
GlobalScriptType::WitnessKey => ScriptType::WitnessKey,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,8 +35,6 @@ impl Serialize for ScriptType {
|
||||||
ScriptType::ScriptHash => "scripthash".serialize(serializer),
|
ScriptType::ScriptHash => "scripthash".serialize(serializer),
|
||||||
ScriptType::Multisig => "multisig".serialize(serializer),
|
ScriptType::Multisig => "multisig".serialize(serializer),
|
||||||
ScriptType::NullData => "nulldata".serialize(serializer),
|
ScriptType::NullData => "nulldata".serialize(serializer),
|
||||||
ScriptType::WitnessScript => "witness_v0_scripthash".serialize(serializer),
|
|
||||||
ScriptType::WitnessKey => "witness_v0_keyhash".serialize(serializer),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,8 +60,6 @@ impl<'a> Deserialize<'a> for ScriptType {
|
||||||
"scripthash" => Ok(ScriptType::ScriptHash),
|
"scripthash" => Ok(ScriptType::ScriptHash),
|
||||||
"multisig" => Ok(ScriptType::Multisig),
|
"multisig" => Ok(ScriptType::Multisig),
|
||||||
"nulldata" => Ok(ScriptType::NullData),
|
"nulldata" => Ok(ScriptType::NullData),
|
||||||
"witness_v0_scripthash" => Ok(ScriptType::WitnessScript),
|
|
||||||
"witness_v0_keyhash" => Ok(ScriptType::WitnessKey),
|
|
||||||
_ => Err(E::invalid_value(Unexpected::Str(value), &self)),
|
_ => Err(E::invalid_value(Unexpected::Str(value), &self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +82,6 @@ mod tests {
|
||||||
assert_eq!(serde_json::to_string(&ScriptType::ScriptHash).unwrap(), r#""scripthash""#);
|
assert_eq!(serde_json::to_string(&ScriptType::ScriptHash).unwrap(), r#""scripthash""#);
|
||||||
assert_eq!(serde_json::to_string(&ScriptType::Multisig).unwrap(), r#""multisig""#);
|
assert_eq!(serde_json::to_string(&ScriptType::Multisig).unwrap(), r#""multisig""#);
|
||||||
assert_eq!(serde_json::to_string(&ScriptType::NullData).unwrap(), r#""nulldata""#);
|
assert_eq!(serde_json::to_string(&ScriptType::NullData).unwrap(), r#""nulldata""#);
|
||||||
assert_eq!(serde_json::to_string(&ScriptType::WitnessScript).unwrap(), r#""witness_v0_scripthash""#);
|
|
||||||
assert_eq!(serde_json::to_string(&ScriptType::WitnessKey).unwrap(), r#""witness_v0_keyhash""#);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -102,7 +92,5 @@ mod tests {
|
||||||
assert_eq!(serde_json::from_str::<ScriptType>(r#""scripthash""#).unwrap(), ScriptType::ScriptHash);
|
assert_eq!(serde_json::from_str::<ScriptType>(r#""scripthash""#).unwrap(), ScriptType::ScriptHash);
|
||||||
assert_eq!(serde_json::from_str::<ScriptType>(r#""multisig""#).unwrap(), ScriptType::Multisig);
|
assert_eq!(serde_json::from_str::<ScriptType>(r#""multisig""#).unwrap(), ScriptType::Multisig);
|
||||||
assert_eq!(serde_json::from_str::<ScriptType>(r#""nulldata""#).unwrap(), ScriptType::NullData);
|
assert_eq!(serde_json::from_str::<ScriptType>(r#""nulldata""#).unwrap(), ScriptType::NullData);
|
||||||
assert_eq!(serde_json::from_str::<ScriptType>(r#""witness_v0_scripthash""#).unwrap(), ScriptType::WitnessScript);
|
|
||||||
assert_eq!(serde_json::from_str::<ScriptType>(r#""witness_v0_keyhash""#).unwrap(), ScriptType::WitnessKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,6 @@ pub enum Error {
|
||||||
// BIP62
|
// BIP62
|
||||||
SignatureHashtype,
|
SignatureHashtype,
|
||||||
SignatureDer,
|
SignatureDer,
|
||||||
SignatureIllegalForkId,
|
|
||||||
SignatureMustUseForkId,
|
|
||||||
Minimaldata,
|
Minimaldata,
|
||||||
SignaturePushOnly,
|
SignaturePushOnly,
|
||||||
SignatureHighS,
|
SignatureHighS,
|
||||||
|
@ -57,15 +55,6 @@ pub enum Error {
|
||||||
// Softfork safeness
|
// Softfork safeness
|
||||||
DiscourageUpgradableNops,
|
DiscourageUpgradableNops,
|
||||||
DiscourageUpgradableWitnessProgram,
|
DiscourageUpgradableWitnessProgram,
|
||||||
|
|
||||||
// SegWit-related errors
|
|
||||||
WitnessProgramWrongLength,
|
|
||||||
WitnessProgramWitnessEmpty,
|
|
||||||
WitnessProgramMismatch,
|
|
||||||
WitnessMalleated,
|
|
||||||
WitnessMalleatedP2SH,
|
|
||||||
WitnessUnexpected,
|
|
||||||
WitnessPubKeyType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -110,8 +99,6 @@ impl fmt::Display for Error {
|
||||||
// BIP62
|
// BIP62
|
||||||
Error::SignatureHashtype => "Invalid Signature Hashtype".fmt(f),
|
Error::SignatureHashtype => "Invalid Signature Hashtype".fmt(f),
|
||||||
Error::SignatureDer => "Invalid Signature".fmt(f),
|
Error::SignatureDer => "Invalid Signature".fmt(f),
|
||||||
Error::SignatureIllegalForkId => "Illegal use of SIGHASH_FORKID".fmt(f),
|
|
||||||
Error::SignatureMustUseForkId => "Signature must use SIGHASH_FORKID".fmt(f),
|
|
||||||
Error::Minimaldata => "Check minimaldata failed".fmt(f),
|
Error::Minimaldata => "Check minimaldata failed".fmt(f),
|
||||||
Error::SignaturePushOnly => "Only push opcodes are allowed in this signature".fmt(f),
|
Error::SignaturePushOnly => "Only push opcodes are allowed in this signature".fmt(f),
|
||||||
Error::SignatureHighS => "Invalid High S in Signature".fmt(f),
|
Error::SignatureHighS => "Invalid High S in Signature".fmt(f),
|
||||||
|
@ -122,15 +109,6 @@ impl fmt::Display for Error {
|
||||||
// Softfork safeness
|
// Softfork safeness
|
||||||
Error::DiscourageUpgradableNops => "Discourage Upgradable Nops".fmt(f),
|
Error::DiscourageUpgradableNops => "Discourage Upgradable Nops".fmt(f),
|
||||||
Error::DiscourageUpgradableWitnessProgram => "Discourage Upgradable Witness Program".fmt(f),
|
Error::DiscourageUpgradableWitnessProgram => "Discourage Upgradable Witness Program".fmt(f),
|
||||||
|
|
||||||
// SegWit-related errors
|
|
||||||
Error::WitnessProgramWrongLength => "Witness program has incorrect length".fmt(f),
|
|
||||||
Error::WitnessProgramWitnessEmpty => "Witness program was passed an empty witness".fmt(f),
|
|
||||||
Error::WitnessProgramMismatch => "Witness program hash mismatch".fmt(f),
|
|
||||||
Error::WitnessMalleated => "Witness requires empty scriptSig".fmt(f),
|
|
||||||
Error::WitnessMalleatedP2SH => "Witness requires only-redeemscript scriptSig".fmt(f),
|
|
||||||
Error::WitnessUnexpected => "Witness provided for non-witness script".fmt(f),
|
|
||||||
Error::WitnessPubKeyType => "Using non-compressed keys in segwit".fmt(f),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ use bytes::Bytes;
|
||||||
use keys::{Message, Signature, Public};
|
use keys::{Message, Signature, Public};
|
||||||
use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG;
|
use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG;
|
||||||
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
||||||
use sign::{SignatureVersion, Sighash};
|
use sign::Sighash;
|
||||||
use script::MAX_SCRIPT_ELEMENT_SIZE;
|
use script::MAX_SCRIPT_ELEMENT_SIZE;
|
||||||
use {
|
use {
|
||||||
script, Builder, Script, ScriptWitness, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack
|
script, Builder, Script, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper function.
|
/// Helper function.
|
||||||
|
@ -15,7 +15,6 @@ fn check_signature(
|
||||||
mut script_sig: Vec<u8>,
|
mut script_sig: Vec<u8>,
|
||||||
public: Vec<u8>,
|
public: Vec<u8>,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
version: SignatureVersion
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let public = match Public::from_slice(&public) {
|
let public = match Public::from_slice(&public) {
|
||||||
Ok(public) => public,
|
Ok(public) => public,
|
||||||
|
@ -29,7 +28,7 @@ fn check_signature(
|
||||||
let hash_type = script_sig.pop().unwrap() as u32;
|
let hash_type = script_sig.pop().unwrap() as u32;
|
||||||
let signature = script_sig.into();
|
let signature = script_sig.into();
|
||||||
|
|
||||||
checker.check_signature(&signature, &public, script_code, hash_type, version)
|
checker.check_signature(&signature, &public, script_code, hash_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function.
|
/// Helper function.
|
||||||
|
@ -169,19 +168,15 @@ fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_defined_hashtype_signature(version: SignatureVersion, sig: &[u8]) -> bool {
|
fn is_defined_hashtype_signature(sig: &[u8]) -> bool {
|
||||||
if sig.is_empty() {
|
if sig.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sighash::is_defined(version, sig[sig.len() - 1] as u32)
|
Sighash::is_defined(sig[sig.len() - 1] as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_hash_type(version: SignatureVersion, sig: &[u8]) -> Sighash {
|
fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
|
||||||
Sighash::from_u32(version, if sig.is_empty() { 0 } else { sig[sig.len() - 1] as u32 })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: SignatureVersion) -> Result<(), Error> {
|
|
||||||
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
||||||
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
||||||
|
|
||||||
|
@ -197,21 +192,10 @@ fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: Sign
|
||||||
is_low_der_signature(sig)?;
|
is_low_der_signature(sig)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.verify_strictenc && !is_defined_hashtype_signature(version, sig) {
|
if flags.verify_strictenc && !is_defined_hashtype_signature(sig) {
|
||||||
return Err(Error::SignatureHashtype)
|
return Err(Error::SignatureHashtype)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify_strictenc is currently enabled for BitcoinCash only
|
|
||||||
if flags.verify_strictenc {
|
|
||||||
let uses_fork_id = parse_hash_type(version, sig).fork_id;
|
|
||||||
let enabled_fork_id = version == SignatureVersion::ForkId;
|
|
||||||
if uses_fork_id && !enabled_fork_id {
|
|
||||||
return Err(Error::SignatureIllegalForkId)
|
|
||||||
} else if !uses_fork_id && enabled_fork_id {
|
|
||||||
return Err(Error::SignatureMustUseForkId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,10 +248,8 @@ fn cast_to_bool(data: &[u8]) -> bool {
|
||||||
pub fn verify_script(
|
pub fn verify_script(
|
||||||
script_sig: &Script,
|
script_sig: &Script,
|
||||||
script_pubkey: &Script,
|
script_pubkey: &Script,
|
||||||
witness: &ScriptWitness,
|
|
||||||
flags: &VerificationFlags,
|
flags: &VerificationFlags,
|
||||||
checker: &SignatureChecker,
|
checker: &SignatureChecker,
|
||||||
version: SignatureVersion,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if flags.verify_sigpushonly && !script_sig.is_push_only() {
|
if flags.verify_sigpushonly && !script_sig.is_push_only() {
|
||||||
return Err(Error::SignaturePushOnly);
|
return Err(Error::SignaturePushOnly);
|
||||||
|
@ -275,35 +257,18 @@ pub fn verify_script(
|
||||||
|
|
||||||
let mut stack = Stack::new();
|
let mut stack = Stack::new();
|
||||||
let mut stack_copy = Stack::new();
|
let mut stack_copy = Stack::new();
|
||||||
let mut had_witness = false;
|
|
||||||
|
|
||||||
eval_script(&mut stack, script_sig, flags, checker, version)?;
|
eval_script(&mut stack, script_sig, flags, checker)?;
|
||||||
|
|
||||||
if flags.verify_p2sh {
|
if flags.verify_p2sh {
|
||||||
stack_copy = stack.clone();
|
stack_copy = stack.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = eval_script(&mut stack, script_pubkey, flags, checker, version)?;
|
let res = eval_script(&mut stack, script_pubkey, flags, checker)?;
|
||||||
if !res {
|
if !res {
|
||||||
return Err(Error::EvalFalse);
|
return Err(Error::EvalFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify witness program
|
|
||||||
let mut verify_cleanstack = flags.verify_cleanstack;
|
|
||||||
if flags.verify_witness {
|
|
||||||
if let Some((witness_version, witness_program)) = script_pubkey.parse_witness_program() {
|
|
||||||
if !script_sig.is_empty() {
|
|
||||||
return Err(Error::WitnessMalleated);
|
|
||||||
}
|
|
||||||
|
|
||||||
had_witness = true;
|
|
||||||
verify_cleanstack = false;
|
|
||||||
if !verify_witness_program(witness, witness_version, witness_program, flags, checker)? {
|
|
||||||
return Err(Error::EvalFalse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional validation for spend-to-script-hash transactions:
|
// Additional validation for spend-to-script-hash transactions:
|
||||||
if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() {
|
if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() {
|
||||||
if !script_sig.is_push_only() {
|
if !script_sig.is_push_only() {
|
||||||
|
@ -319,118 +284,27 @@ pub fn verify_script(
|
||||||
|
|
||||||
let pubkey2: Script = stack.pop()?.into();
|
let pubkey2: Script = stack.pop()?.into();
|
||||||
|
|
||||||
let res = eval_script(&mut stack, &pubkey2, flags, checker, version)?;
|
let res = eval_script(&mut stack, &pubkey2, flags, checker)?;
|
||||||
if !res {
|
if !res {
|
||||||
return Err(Error::EvalFalse);
|
return Err(Error::EvalFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.verify_witness {
|
|
||||||
if let Some((witness_version, witness_program)) = pubkey2.parse_witness_program() {
|
|
||||||
if script_sig != &Builder::default().push_data(&pubkey2).into_script() {
|
|
||||||
return Err(Error::WitnessMalleatedP2SH);
|
|
||||||
}
|
|
||||||
|
|
||||||
had_witness = true;
|
|
||||||
verify_cleanstack = false;
|
|
||||||
if !verify_witness_program(witness, witness_version, witness_program, flags, checker)? {
|
|
||||||
return Err(Error::EvalFalse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The CLEANSTACK check is only performed after potential P2SH evaluation,
|
// The CLEANSTACK check is only performed after potential P2SH evaluation,
|
||||||
// as the non-P2SH evaluation of a P2SH script will obviously not result in
|
// as the non-P2SH evaluation of a P2SH script will obviously not result in
|
||||||
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
|
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
|
||||||
if verify_cleanstack {
|
if flags.verify_cleanstack {
|
||||||
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
|
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
|
||||||
// would be possible, which is not a softfork (and P2SH should be one).
|
// would be possible, which is not a softfork (and P2SH should be one).
|
||||||
assert!(flags.verify_p2sh);
|
assert!(flags.verify_p2sh);
|
||||||
if stack.len() != 1 {
|
if stack.len() != 1 {
|
||||||
return Err(Error::Cleanstack);
|
return Err(Error::Cleanstack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.verify_witness {
|
|
||||||
// We can't check for correct unexpected witness data if P2SH was off, so require
|
|
||||||
// that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
|
|
||||||
// possible, which is not a softfork.
|
|
||||||
assert!(flags.verify_p2sh);
|
|
||||||
if !had_witness && !witness.is_empty() {
|
|
||||||
return Err(Error::WitnessUnexpected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_witness_program(
|
|
||||||
witness: &ScriptWitness,
|
|
||||||
witness_version: u8,
|
|
||||||
witness_program: &[u8],
|
|
||||||
flags: &VerificationFlags,
|
|
||||||
checker: &SignatureChecker,
|
|
||||||
) -> Result<bool, Error> {
|
|
||||||
if witness_version != 0 {
|
|
||||||
if flags.verify_discourage_upgradable_witness_program {
|
|
||||||
return Err(Error::DiscourageUpgradableWitnessProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let witness_stack = witness;
|
|
||||||
let witness_stack_len = witness_stack.len();
|
|
||||||
let (mut stack, script_pubkey): (Stack<_>, Script) = match witness_program.len() {
|
|
||||||
32 => {
|
|
||||||
if witness_stack_len == 0 {
|
|
||||||
return Err(Error::WitnessProgramWitnessEmpty);
|
|
||||||
}
|
|
||||||
|
|
||||||
let script_pubkey = &witness_stack[witness_stack_len - 1];
|
|
||||||
let stack = &witness_stack[0..witness_stack_len - 1];
|
|
||||||
let script_pubkey_hash = sha256(script_pubkey);
|
|
||||||
|
|
||||||
if script_pubkey_hash != witness_program[0..32].into() {
|
|
||||||
return Err(Error::WitnessProgramMismatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
(stack.iter().cloned().collect::<Vec<_>>().into(), Script::new(script_pubkey.clone()))
|
|
||||||
},
|
|
||||||
20 => {
|
|
||||||
if witness_stack_len != 2 {
|
|
||||||
return Err(Error::WitnessProgramMismatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
let script_pubkey = Builder::default()
|
|
||||||
.push_opcode(Opcode::OP_DUP)
|
|
||||||
.push_opcode(Opcode::OP_HASH160)
|
|
||||||
.push_data(witness_program)
|
|
||||||
.push_opcode(Opcode::OP_EQUALVERIFY)
|
|
||||||
.push_opcode(Opcode::OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
|
|
||||||
(witness_stack.clone().into(), script_pubkey)
|
|
||||||
},
|
|
||||||
_ => return Err(Error::WitnessProgramWrongLength),
|
|
||||||
};
|
|
||||||
|
|
||||||
if stack.iter().any(|s| s.len() > MAX_SCRIPT_ELEMENT_SIZE) {
|
|
||||||
return Err(Error::PushSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eval_script(&mut stack, &script_pubkey, flags, checker, SignatureVersion::WitnessV0)? {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if stack.len() != 1 {
|
|
||||||
return Err(Error::EvalFalse);
|
|
||||||
}
|
|
||||||
|
|
||||||
let success = cast_to_bool(stack.last().expect("stack.len() == 1; last() only returns errors when stack is empty; qed"));
|
|
||||||
Ok(success)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluautes the script
|
/// Evaluautes the script
|
||||||
#[cfg_attr(feature="cargo-clippy", allow(match_same_arms))]
|
#[cfg_attr(feature="cargo-clippy", allow(match_same_arms))]
|
||||||
pub fn eval_script(
|
pub fn eval_script(
|
||||||
|
@ -438,7 +312,6 @@ pub fn eval_script(
|
||||||
script: &Script,
|
script: &Script,
|
||||||
flags: &VerificationFlags,
|
flags: &VerificationFlags,
|
||||||
checker: &SignatureChecker,
|
checker: &SignatureChecker,
|
||||||
version: SignatureVersion
|
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
if script.len() > script::MAX_SCRIPT_SIZE {
|
if script.len() > script::MAX_SCRIPT_SIZE {
|
||||||
return Err(Error::ScriptSize);
|
return Err(Error::ScriptSize);
|
||||||
|
@ -1024,21 +897,14 @@ pub fn eval_script(
|
||||||
Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => {
|
Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => {
|
||||||
let pubkey = stack.pop()?;
|
let pubkey = stack.pop()?;
|
||||||
let signature = stack.pop()?;
|
let signature = stack.pop()?;
|
||||||
let sighash = parse_hash_type(version, &signature);
|
|
||||||
let mut subscript = script.subscript(begincode);
|
let mut subscript = script.subscript(begincode);
|
||||||
match version {
|
let signature_script = Builder::default().push_data(&*signature).into_script();
|
||||||
SignatureVersion::ForkId if sighash.fork_id => (),
|
subscript = subscript.find_and_delete(&*signature_script);
|
||||||
SignatureVersion::WitnessV0 => (),
|
|
||||||
SignatureVersion::Base | SignatureVersion::ForkId => {
|
|
||||||
let signature_script = Builder::default().push_data(&*signature).into_script();
|
|
||||||
subscript = subscript.find_and_delete(&*signature_script);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
check_signature_encoding(&signature, flags, version)?;
|
check_signature_encoding(&signature, flags)?;
|
||||||
check_pubkey_encoding(&pubkey, flags)?;
|
check_pubkey_encoding(&pubkey, flags)?;
|
||||||
|
|
||||||
let success = check_signature(checker, signature.into(), pubkey.into(), &subscript, version);
|
let success = check_signature(checker, signature.into(), pubkey.into(), &subscript);
|
||||||
match opcode {
|
match opcode {
|
||||||
Opcode::OP_CHECKSIG => {
|
Opcode::OP_CHECKSIG => {
|
||||||
if success {
|
if success {
|
||||||
|
@ -1071,17 +937,9 @@ pub fn eval_script(
|
||||||
let sigs = (0..sigs_count).into_iter().map(|_| stack.pop()).collect::<Result<Vec<_>, _>>()?;
|
let sigs = (0..sigs_count).into_iter().map(|_| stack.pop()).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut subscript = script.subscript(begincode);
|
let mut subscript = script.subscript(begincode);
|
||||||
|
|
||||||
for signature in &sigs {
|
for signature in &sigs {
|
||||||
let sighash = parse_hash_type(version, &signature);
|
let signature_script = Builder::default().push_data(&*signature).into_script();
|
||||||
match version {
|
subscript = subscript.find_and_delete(&*signature_script);
|
||||||
SignatureVersion::ForkId if sighash.fork_id => (),
|
|
||||||
SignatureVersion::WitnessV0 => (),
|
|
||||||
SignatureVersion::Base | SignatureVersion::ForkId => {
|
|
||||||
let signature_script = Builder::default().push_data(&*signature).into_script();
|
|
||||||
subscript = subscript.find_and_delete(&*signature_script);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut success = true;
|
let mut success = true;
|
||||||
|
@ -1092,10 +950,10 @@ pub fn eval_script(
|
||||||
let key = keys[k].clone();
|
let key = keys[k].clone();
|
||||||
let sig = sigs[s].clone();
|
let sig = sigs[s].clone();
|
||||||
|
|
||||||
check_signature_encoding(&sig, flags, version)?;
|
check_signature_encoding(&sig, flags)?;
|
||||||
check_pubkey_encoding(&key, flags)?;
|
check_pubkey_encoding(&key, flags)?;
|
||||||
|
|
||||||
let ok = check_signature(checker, sig.into(), key.into(), &subscript, version);
|
let ok = check_signature(checker, sig.into(), key.into(), &subscript);
|
||||||
if ok {
|
if ok {
|
||||||
s += 1;
|
s += 1;
|
||||||
}
|
}
|
||||||
|
@ -1139,7 +997,7 @@ pub fn eval_script(
|
||||||
let message = stack.pop()?;
|
let message = stack.pop()?;
|
||||||
let signature = stack.pop()?;
|
let signature = stack.pop()?;
|
||||||
|
|
||||||
check_signature_encoding(&signature, flags, version)?;
|
check_signature_encoding(&signature, flags)?;
|
||||||
check_pubkey_encoding(&pubkey, flags)?;
|
check_pubkey_encoding(&pubkey, flags)?;
|
||||||
|
|
||||||
let signature: Vec<u8> = signature.into();
|
let signature: Vec<u8> = signature.into();
|
||||||
|
@ -1187,10 +1045,9 @@ mod tests {
|
||||||
use chain::Transaction;
|
use chain::Transaction;
|
||||||
use crypto::sha256;
|
use crypto::sha256;
|
||||||
use keys::{KeyPair, Private, Message, Network};
|
use keys::{KeyPair, Private, Message, Network};
|
||||||
use sign::SignatureVersion;
|
|
||||||
use script::MAX_SCRIPT_ELEMENT_SIZE;
|
use script::MAX_SCRIPT_ELEMENT_SIZE;
|
||||||
use {
|
use {
|
||||||
Opcode, Script, ScriptWitness, VerificationFlags, Builder, Error, Num, TransactionInputSigner,
|
Opcode, Script, VerificationFlags, Builder, Error, Num, TransactionInputSigner,
|
||||||
NoopSignatureChecker, TransactionSignatureChecker, Stack
|
NoopSignatureChecker, TransactionSignatureChecker, Stack
|
||||||
};
|
};
|
||||||
use super::{eval_script, verify_script, is_public_key};
|
use super::{eval_script, verify_script, is_public_key};
|
||||||
|
@ -1212,7 +1069,6 @@ mod tests {
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
let checker = NoopSignatureChecker;
|
let checker = NoopSignatureChecker;
|
||||||
let version = SignatureVersion::Base;
|
|
||||||
let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into();
|
let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into();
|
||||||
let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into();
|
let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into();
|
||||||
let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into();
|
let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into();
|
||||||
|
@ -1222,10 +1078,10 @@ mod tests {
|
||||||
let mut pushdata1_stack = Stack::new();
|
let mut pushdata1_stack = Stack::new();
|
||||||
let mut pushdata2_stack = Stack::new();
|
let mut pushdata2_stack = Stack::new();
|
||||||
let mut pushdata4_stack = Stack::new();
|
let mut pushdata4_stack = Stack::new();
|
||||||
assert!(eval_script(&mut direct_stack, &direct, &flags, &checker, version).unwrap());
|
assert!(eval_script(&mut direct_stack, &direct, &flags, &checker).unwrap());
|
||||||
assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker, version).unwrap());
|
assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker).unwrap());
|
||||||
assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker, version).unwrap());
|
assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker).unwrap());
|
||||||
assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker, version).unwrap());
|
assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker).unwrap());
|
||||||
|
|
||||||
assert_eq!(direct_stack, expected);
|
assert_eq!(direct_stack, expected);
|
||||||
assert_eq!(pushdata1_stack, expected);
|
assert_eq!(pushdata1_stack, expected);
|
||||||
|
@ -1235,9 +1091,8 @@ mod tests {
|
||||||
|
|
||||||
fn basic_test_with_flags(script: &Script, flags: &VerificationFlags, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) {
|
fn basic_test_with_flags(script: &Script, flags: &VerificationFlags, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) {
|
||||||
let checker = NoopSignatureChecker;
|
let checker = NoopSignatureChecker;
|
||||||
let version = SignatureVersion::Base;
|
|
||||||
let mut stack = Stack::new();
|
let mut stack = Stack::new();
|
||||||
assert_eq!(eval_script(&mut stack, script, &flags, &checker, version), expected);
|
assert_eq!(eval_script(&mut stack, script, &flags, &checker), expected);
|
||||||
if expected.is_ok() {
|
if expected.is_ok() {
|
||||||
assert_eq!(stack, expected_stack);
|
assert_eq!(stack, expected_stack);
|
||||||
}
|
}
|
||||||
|
@ -2144,7 +1999,7 @@ mod tests {
|
||||||
let output: Script = "76a914df3bd30160e6c6145baaf2c88a8844c13a00d1d588ac".into();
|
let output: Script = "76a914df3bd30160e6c6145baaf2c88a8844c13a00d1d588ac".into();
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
|
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
|
||||||
|
@ -2161,7 +2016,7 @@ mod tests {
|
||||||
let output: Script = "a9141a8b0026343166625c7475f01e48b5ede8c0252e87".into();
|
let output: Script = "a9141a8b0026343166625c7475f01e48b5ede8c0252e87".into();
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blockchain.info/en/tx/12b5633bad1f9c167d523ad1aa1947b2732a865bf5414eab2f9e5ae5d5c191ba?show_adv=true
|
// https://blockchain.info/en/tx/12b5633bad1f9c167d523ad1aa1947b2732a865bf5414eab2f9e5ae5d5c191ba?show_adv=true
|
||||||
|
@ -2178,7 +2033,7 @@ mod tests {
|
||||||
let output: Script = "410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac".into();
|
let output: Script = "410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac".into();
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blockchain.info/rawtx/fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d
|
// https://blockchain.info/rawtx/fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d
|
||||||
|
@ -2195,7 +2050,7 @@ mod tests {
|
||||||
let output: Script = "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac".into();
|
let output: Script = "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac".into();
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blockchain.info/rawtx/eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb
|
// https://blockchain.info/rawtx/eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb
|
||||||
|
@ -2213,12 +2068,12 @@ mod tests {
|
||||||
|
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
|
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true)
|
.verify_p2sh(true)
|
||||||
.verify_locktime(true);
|
.verify_locktime(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Err(Error::NumberOverflow));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Err(Error::NumberOverflow));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blockchain.info/rawtx/54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f
|
// https://blockchain.info/rawtx/54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f
|
||||||
|
@ -2234,7 +2089,7 @@ mod tests {
|
||||||
let input: Script = "483045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e014f".into();
|
let input: Script = "483045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e014f".into();
|
||||||
let output: Script = "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c".into();
|
let output: Script = "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c".into();
|
||||||
let flags = VerificationFlags::default();
|
let flags = VerificationFlags::default();
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -2287,84 +2142,10 @@ mod tests {
|
||||||
|
|
||||||
let flags = VerificationFlags::default()
|
let flags = VerificationFlags::default()
|
||||||
.verify_p2sh(true);
|
.verify_p2sh(true);
|
||||||
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(()));
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_script_with_forkid_signature() {
|
|
||||||
use sign::UnsignedTransactionInput;
|
|
||||||
use chain::{OutPoint, TransactionOutput};
|
|
||||||
|
|
||||||
let key_pair = KeyPair::from_private(Private { network: Network::Mainnet, secret: 1.into(), compressed: false, }).unwrap();
|
|
||||||
let redeem_script = Builder::default()
|
|
||||||
.push_data(key_pair.public())
|
|
||||||
.push_opcode(Opcode::OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
|
|
||||||
|
|
||||||
let amount = 12345000000000;
|
|
||||||
let sighashtype = 0x41; // All + ForkId
|
|
||||||
let checker = TransactionSignatureChecker {
|
|
||||||
input_index: 0,
|
|
||||||
input_amount: amount,
|
|
||||||
signer: TransactionInputSigner {
|
|
||||||
version: 1,
|
|
||||||
inputs: vec![
|
|
||||||
UnsignedTransactionInput {
|
|
||||||
previous_output: OutPoint {
|
|
||||||
hash: 0u8.into(),
|
|
||||||
index: 0xffffffff,
|
|
||||||
},
|
|
||||||
sequence: 0xffffffff,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
outputs: vec![
|
|
||||||
TransactionOutput {
|
|
||||||
value: amount,
|
|
||||||
script_pubkey: redeem_script.to_bytes(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
lock_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let script_pubkey = redeem_script;
|
|
||||||
let flags = VerificationFlags::default();
|
|
||||||
|
|
||||||
// valid signature
|
|
||||||
{
|
|
||||||
let signed_input = checker.signer.signed_input(&key_pair, 0, amount, &script_pubkey, SignatureVersion::ForkId, sighashtype);
|
|
||||||
let script_sig = signed_input.script_sig.into();
|
|
||||||
|
|
||||||
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::ForkId), Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// signature with wrong amount
|
|
||||||
{
|
|
||||||
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::ForkId, sighashtype);
|
|
||||||
let script_sig = signed_input.script_sig.into();
|
|
||||||
|
|
||||||
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::ForkId), Err(Error::EvalFalse));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fork-id signature passed when not expected
|
|
||||||
{
|
|
||||||
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::ForkId, sighashtype);
|
|
||||||
let script_sig = signed_input.script_sig.into();
|
|
||||||
|
|
||||||
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Err(Error::EvalFalse));
|
|
||||||
}
|
|
||||||
|
|
||||||
// non-fork-id signature passed when expected
|
|
||||||
{
|
|
||||||
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::Base, 1);
|
|
||||||
let script_sig = signed_input.script_sig.into();
|
|
||||||
|
|
||||||
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags.verify_strictenc(true), &checker, SignatureVersion::ForkId), Err(Error::SignatureMustUseForkId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_cat_disabled_by_default() {
|
fn op_cat_disabled_by_default() {
|
||||||
let script = Builder::default()
|
let script = Builder::default()
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub use self::interpreter::{eval_script, verify_script};
|
||||||
pub use self::opcode::Opcode;
|
pub use self::opcode::Opcode;
|
||||||
pub use self::num::Num;
|
pub use self::num::Num;
|
||||||
pub use self::script::{Script, ScriptType, ScriptAddress, ScriptWitness, is_witness_commitment_script};
|
pub use self::script::{Script, ScriptType, ScriptAddress, ScriptWitness, is_witness_commitment_script};
|
||||||
pub use self::sign::{TransactionInputSigner, UnsignedTransactionInput, SignatureVersion};
|
pub use self::sign::{TransactionInputSigner, UnsignedTransactionInput};
|
||||||
pub use self::stack::Stack;
|
pub use self::stack::Stack;
|
||||||
pub use self::verify::{SignatureChecker, NoopSignatureChecker, TransactionSignatureChecker};
|
pub use self::verify::{SignatureChecker, NoopSignatureChecker, TransactionSignatureChecker};
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,6 @@ pub enum ScriptType {
|
||||||
ScriptHash,
|
ScriptHash,
|
||||||
Multisig,
|
Multisig,
|
||||||
NullData,
|
NullData,
|
||||||
WitnessScript,
|
|
||||||
WitnessKey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Address from Script
|
/// Address from Script
|
||||||
|
@ -350,10 +348,6 @@ impl Script {
|
||||||
ScriptType::Multisig
|
ScriptType::Multisig
|
||||||
} else if self.is_null_data_script() {
|
} else if self.is_null_data_script() {
|
||||||
ScriptType::NullData
|
ScriptType::NullData
|
||||||
} else if self.is_pay_to_witness_key_hash() {
|
|
||||||
ScriptType::WitnessKey
|
|
||||||
} else if self.is_pay_to_witness_script_hash() {
|
|
||||||
ScriptType::WitnessScript
|
|
||||||
} else {
|
} else {
|
||||||
ScriptType::NonStandard
|
ScriptType::NonStandard
|
||||||
}
|
}
|
||||||
|
@ -448,12 +442,6 @@ impl Script {
|
||||||
ScriptType::NullData => {
|
ScriptType::NullData => {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
},
|
},
|
||||||
ScriptType::WitnessScript => {
|
|
||||||
Ok(vec![]) // TODO
|
|
||||||
},
|
|
||||||
ScriptType::WitnessKey => {
|
|
||||||
Ok(vec![]) // TODO
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,6 @@ use ser::Stream;
|
||||||
use chain::{Transaction, TransactionOutput, OutPoint, TransactionInput};
|
use chain::{Transaction, TransactionOutput, OutPoint, TransactionInput};
|
||||||
use {Script, Builder};
|
use {Script, Builder};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
|
||||||
pub enum SignatureVersion {
|
|
||||||
Base,
|
|
||||||
WitnessV0,
|
|
||||||
ForkId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum SighashBase {
|
pub enum SighashBase {
|
||||||
|
@ -65,12 +58,9 @@ impl Sighash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used by SCRIPT_VERIFY_STRICTENC
|
/// Used by SCRIPT_VERIFY_STRICTENC
|
||||||
pub fn is_defined(version: SignatureVersion, u: u32) -> bool {
|
pub fn is_defined(u: u32) -> bool {
|
||||||
// reset anyone_can_pay && fork_id (if applicable) bits
|
// reset anyone_can_pay && fork_id (if applicable) bits
|
||||||
let u = match version {
|
let u = u & !(0x80);
|
||||||
SignatureVersion::ForkId => u & !(0x40 | 0x80),
|
|
||||||
_ => u & !(0x80),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only exact All | None | Single values are passing this check
|
// Only exact All | None | Single values are passing this check
|
||||||
match u {
|
match u {
|
||||||
|
@ -80,16 +70,15 @@ impl Sighash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates Sighash from any u, even if is_defined() == false
|
/// Creates Sighash from any u, even if is_defined() == false
|
||||||
pub fn from_u32(version: SignatureVersion, u: u32) -> Self {
|
pub fn from_u32(u: u32) -> Self {
|
||||||
let anyone_can_pay = (u & 0x80) == 0x80;
|
let anyone_can_pay = (u & 0x80) == 0x80;
|
||||||
let fork_id = version == SignatureVersion::ForkId && (u & 0x40) == 0x40;
|
|
||||||
let base = match u & 0x1f {
|
let base = match u & 0x1f {
|
||||||
2 => SighashBase::None,
|
2 => SighashBase::None,
|
||||||
3 => SighashBase::Single,
|
3 => SighashBase::Single,
|
||||||
1 | _ => SighashBase::All,
|
1 | _ => SighashBase::All,
|
||||||
};
|
};
|
||||||
|
|
||||||
Sighash::new(base, anyone_can_pay, fork_id)
|
Sighash::new(base, anyone_can_pay, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,41 +119,9 @@ impl From<Transaction> for TransactionInputSigner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransactionInputSigner {
|
impl TransactionInputSigner {
|
||||||
pub fn signature_hash(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sigversion: SignatureVersion, sighashtype: u32) -> H256 {
|
pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32) -> H256 {
|
||||||
let sighash = Sighash::from_u32(sigversion, sighashtype);
|
let sighash = Sighash::from_u32(sighashtype);
|
||||||
match sigversion {
|
self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash)
|
||||||
SignatureVersion::ForkId if sighash.fork_id => self.signature_hash_fork_id(input_index, input_amount, script_pubkey, sighashtype, sighash),
|
|
||||||
SignatureVersion::Base | SignatureVersion::ForkId => self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash),
|
|
||||||
SignatureVersion::WitnessV0 => self.signature_hash_witness0(input_index, input_amount, script_pubkey, sighashtype, sighash),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// input_index - index of input to sign
|
|
||||||
/// script_pubkey - script_pubkey of input's previous_output pubkey
|
|
||||||
pub fn signed_input(
|
|
||||||
&self,
|
|
||||||
keypair: &KeyPair,
|
|
||||||
input_index: usize,
|
|
||||||
input_amount: u64,
|
|
||||||
script_pubkey: &Script,
|
|
||||||
sigversion: SignatureVersion,
|
|
||||||
sighash: u32,
|
|
||||||
) -> TransactionInput {
|
|
||||||
let hash = self.signature_hash(input_index, input_amount, script_pubkey, sigversion, sighash);
|
|
||||||
|
|
||||||
let mut signature: Vec<u8> = keypair.private().sign(&hash).unwrap().into();
|
|
||||||
signature.push(sighash as u8);
|
|
||||||
let script_sig = Builder::default()
|
|
||||||
.push_data(&signature)
|
|
||||||
//.push_data(keypair.public())
|
|
||||||
.into_script();
|
|
||||||
|
|
||||||
let unsigned_input = &self.inputs[input_index];
|
|
||||||
TransactionInput {
|
|
||||||
previous_output: unsigned_input.previous_output.clone(),
|
|
||||||
sequence: unsigned_input.sequence,
|
|
||||||
script_sig: script_sig.to_bytes(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature_hash_original(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 {
|
pub fn signature_hash_original(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 {
|
||||||
|
@ -232,80 +189,30 @@ impl TransactionInputSigner {
|
||||||
dhash256(&out)
|
dhash256(&out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_hash_witness0(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 {
|
/// input_index - index of input to sign
|
||||||
let hash_prevouts = compute_hash_prevouts(sighash, &self.inputs);
|
/// script_pubkey - script_pubkey of input's previous_output pubkey
|
||||||
let hash_sequence = compute_hash_sequence(sighash, &self.inputs);
|
pub fn signed_input(
|
||||||
let hash_outputs = compute_hash_outputs(sighash, input_index, &self.outputs);
|
&self,
|
||||||
|
keypair: &KeyPair,
|
||||||
|
input_index: usize,
|
||||||
|
script_pubkey: &Script,
|
||||||
|
sighash: u32,
|
||||||
|
) -> TransactionInput {
|
||||||
|
let hash = self.signature_hash(input_index, script_pubkey, sighash);
|
||||||
|
|
||||||
let mut stream = Stream::default();
|
let mut signature: Vec<u8> = keypair.private().sign(&hash).unwrap().into();
|
||||||
stream.append(&self.version);
|
signature.push(sighash as u8);
|
||||||
stream.append(&hash_prevouts);
|
let script_sig = Builder::default()
|
||||||
stream.append(&hash_sequence);
|
.push_data(&signature)
|
||||||
stream.append(&self.inputs[input_index].previous_output);
|
//.push_data(keypair.public())
|
||||||
stream.append_list(&**script_pubkey);
|
.into_script();
|
||||||
stream.append(&input_amount);
|
|
||||||
stream.append(&self.inputs[input_index].sequence);
|
|
||||||
stream.append(&hash_outputs);
|
|
||||||
stream.append(&self.lock_time);
|
|
||||||
stream.append(&sighashtype); // this also includes 24-bit fork id. which is 0 for BitcoinCash
|
|
||||||
let out = stream.out();
|
|
||||||
dhash256(&out)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature_hash_fork_id(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 {
|
let unsigned_input = &self.inputs[input_index];
|
||||||
if input_index >= self.inputs.len() {
|
TransactionInput {
|
||||||
return 1u8.into();
|
previous_output: unsigned_input.previous_output.clone(),
|
||||||
|
sequence: unsigned_input.sequence,
|
||||||
|
script_sig: script_sig.to_bytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if sighash.base == SighashBase::Single && input_index >= self.outputs.len() {
|
|
||||||
return 1u8.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.signature_hash_witness0(input_index, input_amount, script_pubkey, sighashtype, sighash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_hash_prevouts(sighash: Sighash, inputs: &[UnsignedTransactionInput]) -> H256 {
|
|
||||||
match sighash.anyone_can_pay {
|
|
||||||
false => {
|
|
||||||
let mut stream = Stream::default();
|
|
||||||
for input in inputs {
|
|
||||||
stream.append(&input.previous_output);
|
|
||||||
}
|
|
||||||
dhash256(&stream.out())
|
|
||||||
},
|
|
||||||
true => 0u8.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_hash_sequence(sighash: Sighash, inputs: &[UnsignedTransactionInput]) -> H256 {
|
|
||||||
match sighash.base {
|
|
||||||
SighashBase::All if !sighash.anyone_can_pay => {
|
|
||||||
let mut stream = Stream::default();
|
|
||||||
for input in inputs {
|
|
||||||
stream.append(&input.sequence);
|
|
||||||
}
|
|
||||||
dhash256(&stream.out())
|
|
||||||
},
|
|
||||||
_ => 0u8.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_hash_outputs(sighash: Sighash, input_index: usize, outputs: &[TransactionOutput]) -> H256 {
|
|
||||||
match sighash.base {
|
|
||||||
SighashBase::All => {
|
|
||||||
let mut stream = Stream::default();
|
|
||||||
for output in outputs {
|
|
||||||
stream.append(output);
|
|
||||||
}
|
|
||||||
dhash256(&stream.out())
|
|
||||||
},
|
|
||||||
SighashBase::Single if input_index < outputs.len() => {
|
|
||||||
let mut stream = Stream::default();
|
|
||||||
stream.append(&outputs[input_index]);
|
|
||||||
dhash256(&stream.out())
|
|
||||||
},
|
|
||||||
_ => 0u8.into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +223,7 @@ mod tests {
|
||||||
use keys::{KeyPair, Private, Address};
|
use keys::{KeyPair, Private, Address};
|
||||||
use chain::{OutPoint, TransactionOutput, Transaction};
|
use chain::{OutPoint, TransactionOutput, Transaction};
|
||||||
use script::Script;
|
use script::Script;
|
||||||
use super::{Sighash, UnsignedTransactionInput, TransactionInputSigner, SighashBase, SignatureVersion};
|
use super::{Sighash, UnsignedTransactionInput, TransactionInputSigner, SighashBase};
|
||||||
|
|
||||||
// http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
|
// http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
|
||||||
// https://blockchain.info/rawtx/81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48
|
// https://blockchain.info/rawtx/81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48
|
||||||
|
@ -358,7 +265,7 @@ mod tests {
|
||||||
outputs: vec![output],
|
outputs: vec![output],
|
||||||
};
|
};
|
||||||
|
|
||||||
let hash = input_signer.signature_hash(0, 0, &previous_output, SignatureVersion::Base, SighashBase::All.into());
|
let hash = input_signer.signature_hash(0, &previous_output, SighashBase::All.into());
|
||||||
assert_eq!(hash, expected_signature_hash);
|
assert_eq!(hash, expected_signature_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +281,7 @@ mod tests {
|
||||||
let script: Script = script.into();
|
let script: Script = script.into();
|
||||||
let expected = H256::from_reversed_str(result);
|
let expected = H256::from_reversed_str(result);
|
||||||
|
|
||||||
let sighash = Sighash::from_u32(SignatureVersion::Base, hash_type as u32);
|
let sighash = Sighash::from_u32(hash_type as u32);
|
||||||
let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash);
|
let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash);
|
||||||
assert_eq!(expected, hash);
|
assert_eq!(expected, hash);
|
||||||
}
|
}
|
||||||
|
@ -888,17 +795,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sighash_forkid_from_u32() {
|
fn test_sighash_forkid_from_u32() {
|
||||||
assert!(!Sighash::is_defined(SignatureVersion::Base, 0xFFFFFF82));
|
assert!(!Sighash::is_defined(0xFFFFFF82));
|
||||||
assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000182));
|
assert!(!Sighash::is_defined(0x00000182));
|
||||||
assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000080));
|
assert!(!Sighash::is_defined(0x00000080));
|
||||||
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000001));
|
assert!( Sighash::is_defined(0x00000001));
|
||||||
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000082));
|
assert!( Sighash::is_defined(0x00000082));
|
||||||
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000003));
|
assert!( Sighash::is_defined(0x00000003));
|
||||||
|
|
||||||
assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0xFFFFFFC2));
|
|
||||||
assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0x000001C2));
|
|
||||||
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000081));
|
|
||||||
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x000000C2));
|
|
||||||
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000043));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ use chain::constants::{
|
||||||
SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
|
SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
|
||||||
SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD
|
SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD
|
||||||
};
|
};
|
||||||
use sign::SignatureVersion;
|
|
||||||
use {Script, TransactionInputSigner, Num};
|
use {Script, TransactionInputSigner, Num};
|
||||||
|
|
||||||
/// Checks transaction signature
|
/// Checks transaction signature
|
||||||
|
@ -21,7 +20,6 @@ pub trait SignatureChecker {
|
||||||
public: &Public,
|
public: &Public,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
sighashtype: u32,
|
sighashtype: u32,
|
||||||
version: SignatureVersion
|
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
fn check_lock_time(&self, lock_time: Num) -> bool;
|
fn check_lock_time(&self, lock_time: Num) -> bool;
|
||||||
|
@ -36,7 +34,7 @@ impl SignatureChecker for NoopSignatureChecker {
|
||||||
public.verify(hash, signature).unwrap_or(false)
|
public.verify(hash, signature).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u32, _: SignatureVersion) -> bool {
|
fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u32) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,9 +70,8 @@ impl SignatureChecker for TransactionSignatureChecker {
|
||||||
public: &Public,
|
public: &Public,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
sighashtype: u32,
|
sighashtype: u32,
|
||||||
version: SignatureVersion
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let hash = self.signer.signature_hash(self.input_index, self.input_amount, script_code, version, sighashtype);
|
let hash = self.signer.signature_hash(self.input_index, script_code, sighashtype);
|
||||||
self.verify_signature(signature, public, &hash)
|
self.verify_signature(signature, public, &hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,6 @@ pub struct MerkleBlockArtefacts {
|
||||||
|
|
||||||
/// Connected peers
|
/// Connected peers
|
||||||
pub trait Peers : Send + Sync + PeersContainer + PeersFilters + PeersOptions {
|
pub trait Peers : Send + Sync + PeersContainer + PeersFilters + PeersOptions {
|
||||||
/// Require peers services.
|
|
||||||
fn require_peer_services(&self, services: Services);
|
|
||||||
/// Get peer connection
|
/// Get peer connection
|
||||||
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef>;
|
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef>;
|
||||||
}
|
}
|
||||||
|
@ -123,19 +121,6 @@ impl Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peers for PeersImpl {
|
impl Peers for PeersImpl {
|
||||||
fn require_peer_services(&self, services: Services) {
|
|
||||||
// possible optimization: force p2p level to establish connections to SegWit-nodes only
|
|
||||||
// without it, all other nodes will be eventually banned (this could take some time, though)
|
|
||||||
let mut peers = self.peers.write();
|
|
||||||
for peer_index in peers.iter().filter(|&(_, p)| p.services.includes(&services)).map(|(p, _)| *p).collect::<Vec<_>>() {
|
|
||||||
let peer = peers.remove(&peer_index).expect("iterating peers keys; qed");
|
|
||||||
let expected_services: u64 = services.into();
|
|
||||||
let actual_services: u64 = peer.services.into();
|
|
||||||
warn!(target: "sync", "Disconnecting from peer#{} because of insufficient services. Expected {:x}, actual: {:x}", peer_index, expected_services, actual_services);
|
|
||||||
peer.connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef> {
|
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef> {
|
||||||
self.peers.read().get(&peer_index).map(|peer| peer.connection.clone())
|
self.peers.read().get(&peer_index).map(|peer| peer.connection.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use storage::{TransactionMetaProvider, TransactionOutputProvider};
|
use storage::{TransactionMetaProvider, TransactionOutputProvider};
|
||||||
use network::{ConsensusParams};
|
use network::{ConsensusParams};
|
||||||
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner, SignatureVersion};
|
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
|
||||||
use duplex_store::DuplexTransactionOutputProvider;
|
use duplex_store::DuplexTransactionOutputProvider;
|
||||||
use deployments::BlockDeployments;
|
use deployments::BlockDeployments;
|
||||||
use sigops::transaction_sigops;
|
use sigops::transaction_sigops;
|
||||||
|
@ -275,7 +275,6 @@ pub struct TransactionEval<'a> {
|
||||||
verify_magnetic_anomaly_opcodes: bool,
|
verify_magnetic_anomaly_opcodes: bool,
|
||||||
verify_sigpushonly: bool,
|
verify_sigpushonly: bool,
|
||||||
verify_cleanstack: bool,
|
verify_cleanstack: bool,
|
||||||
signature_version: SignatureVersion,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TransactionEval<'a> {
|
impl<'a> TransactionEval<'a> {
|
||||||
|
@ -294,7 +293,6 @@ impl<'a> TransactionEval<'a> {
|
||||||
let verify_dersig = height >= params.bip66_height;
|
let verify_dersig = height >= params.bip66_height;
|
||||||
let verify_monolith_opcodes = false;
|
let verify_monolith_opcodes = false;
|
||||||
let verify_magnetic_anomaly_opcodes = false;
|
let verify_magnetic_anomaly_opcodes = false;
|
||||||
let signature_version = SignatureVersion::Base;
|
|
||||||
|
|
||||||
let verify_checksequence = deployments.csv();
|
let verify_checksequence = deployments.csv();
|
||||||
let verify_sigpushonly = verify_magnetic_anomaly_opcodes;
|
let verify_sigpushonly = verify_magnetic_anomaly_opcodes;
|
||||||
|
@ -314,7 +312,6 @@ impl<'a> TransactionEval<'a> {
|
||||||
verify_magnetic_anomaly_opcodes: verify_magnetic_anomaly_opcodes,
|
verify_magnetic_anomaly_opcodes: verify_magnetic_anomaly_opcodes,
|
||||||
verify_sigpushonly: verify_sigpushonly,
|
verify_sigpushonly: verify_sigpushonly,
|
||||||
verify_cleanstack: verify_cleanstack,
|
verify_cleanstack: verify_cleanstack,
|
||||||
signature_version: signature_version,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +363,7 @@ impl<'a> TransactionEval<'a> {
|
||||||
.verify_sigpushonly(self.verify_sigpushonly)
|
.verify_sigpushonly(self.verify_sigpushonly)
|
||||||
.verify_cleanstack(self.verify_cleanstack);
|
.verify_cleanstack(self.verify_cleanstack);
|
||||||
|
|
||||||
try!(verify_script(&input, &output, &Default::default(), &flags, &checker, self.signature_version)
|
try!(verify_script(&input, &output, &flags, &checker)
|
||||||
.map_err(|e| TransactionError::Signature(index, e)));
|
.map_err(|e| TransactionError::Signature(index, e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,17 +78,6 @@ impl Deployments {
|
||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if SegWit deployment is active
|
|
||||||
pub fn segwit(&self, number: u32, headers: &BlockHeaderProvider, consensus: &ConsensusParams) -> bool {
|
|
||||||
match consensus.segwit_deployment {
|
|
||||||
Some(segwit) => {
|
|
||||||
let mut cache = self.cache.lock();
|
|
||||||
threshold_state(&mut cache, segwit, number, headers, consensus.miner_confirmation_window, consensus.rule_change_activation_threshold).is_active()
|
|
||||||
},
|
|
||||||
None => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BlockDeployments<'a> {
|
impl<'a> BlockDeployments<'a> {
|
||||||
|
@ -104,10 +93,6 @@ impl<'a> BlockDeployments<'a> {
|
||||||
pub fn csv(&self) -> bool {
|
pub fn csv(&self) -> bool {
|
||||||
self.deployments.csv(self.number, self.headers, self.consensus)
|
self.deployments.csv(self.number, self.headers, self.consensus)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn segwit(&self) -> bool {
|
|
||||||
self.deployments.segwit(self.number, self.headers, self.consensus)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Deployments> for Deployments {
|
impl AsRef<Deployments> for Deployments {
|
||||||
|
|
Loading…
Reference in New Issue