Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redefine "pegout" to better match elementsd RPC #17

Merged
merged 3 commits into from
May 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "elements"
version = "0.7.0"
version = "0.7.1"
authors = ["Andrew Poelstra <[email protected]>"]
description = "Library with support for de/serialization, parsing and executing on data structures and network messages related to Elements"
license = "CC0-1.0"
Expand Down
182 changes: 168 additions & 14 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,8 @@ impl<D: Decoder> Decodable<D> for TxOut {
}

impl TxOut {
/// Whether this data represents nulldata (OP_RETURN followed by pushes)
/// Whether this data represents nulldata (OP_RETURN followed by pushes,
/// not necessarily minimal)
pub fn is_null_data(&self) -> bool {
let mut iter = self.script_pubkey.iter(false);
if iter.next() == Some(Instruction::Op(opcodes::all::OP_RETURN)) {
Expand All @@ -363,12 +364,15 @@ impl TxOut {
}
}

/// Whether this output is a pegout
/// Whether this output is a pegout, which is a subset of nulldata with the
/// following extra rules: (a) there must be at least 2 pushes, the first of
/// which must be 32 bytes and the second of which must be nonempty; (b) all
/// pushes must use a push opcode rather than a numeric or reserved opcode
pub fn is_pegout(&self) -> bool {
self.pegout_data().is_some()
}

/// Whether this output is a pegout; if so, returns the destination genesis block,
/// If this output is a pegout, returns the destination genesis block,
/// the destination script pubkey, and any additional data
pub fn pegout_data(&self) -> Option<PegoutData> {
// Must be NULLDATA
Expand All @@ -383,7 +387,7 @@ impl TxOut {
return None;
};

let mut iter = self.script_pubkey.iter(true);
let mut iter = self.script_pubkey.iter(false);

iter.next(); // Skip OP_RETURN

Expand All @@ -400,23 +404,37 @@ impl TxOut {

// Parse destination scriptpubkey
let script_pubkey = if let Some(Instruction::PushBytes(data)) = iter.next() {
Script::from(data.to_owned())
if data.is_empty() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elements was modified to make 0 byte pushes legal @ https://github.com/ElementsProject/elements/pull/610/files#diff-f7ca24fb80ddba0f291cb66344ca6fcbR222

So this block needs to be reverted now.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not merged yet! but looks like ACKs from relevant parties

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh indeed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

610 is now merged and this needs to be reverted now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#20

return None;
} else {
Script::from(data.to_owned())
}
} else {
return None;
};

// Return everything
let mut found_non_data_push = false;
let remainder = iter
.map(|x| if let Instruction::PushBytes(data) = x { data } else { unreachable!() })
.filter_map(|x| if let Instruction::PushBytes(data) = x {
Some(data)
} else {
found_non_data_push = true;
None
})
.collect();

Some(PegoutData {
asset: self.asset,
value: value,
genesis_hash: genesis_hash,
script_pubkey: script_pubkey,
extra_data: remainder,
})
if found_non_data_push {
None
} else {
Some(PegoutData {
asset: self.asset,
value: value,
genesis_hash: genesis_hash,
script_pubkey: script_pubkey,
extra_data: remainder,
})
}
}

/// Whether or not this output is a fee output
Expand Down Expand Up @@ -1481,9 +1499,145 @@ mod tests {
fdfdfdfdfd3ca059fdf2226a20000000000000000000000000000000000000000\
0000000000000000000000000\
");

assert!(output.is_null_data());
assert!(!output.is_pegout());
}

#[test]
fn pegout_tx_vector_1() {
let tx: Transaction = hex_deserialize!("\
0200000000021c39a226160dd8962eb273772950f0b603c319a8e4aa9912c9e8e\
36b5bdf71a2000000006a473044022071212fcde89d1055d5b74f17a162b3dbe5\
348ac8527a131dab5dcf8a97d67d2f02202edf12f3c69fed1fa0c23da608e6ade\
d86dd5c7b09da42f61b453c3a838e8cab012103557f25ff40f976670ddf59c719\
38bade91684b76ad69dfed27049de2afec59e5feffffff853db31f986dd89c81f\
e87a84f385d7099c5ea841d762b26b03166e5e798dfbe000000006a4730440220\
42c70729fb50930179a9d76f5febbda5b0ee50e62febf92de4dd10b9393554d80\
2203140b107519243e4110c065017c8ae1ac04843f94b3f20a1e5faf7343dd761\
59012102797ffcf7ccc8e2012a90e71962901a1ad740f2a28f2f563c76f9eb42a\
8100f5efeffffff03016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a\
713d1c04ede979026f0100000000000f7869001976a914216d878ebff0c623909\
889265d8dc1ab26e2ff4388ac016d521c38ec1ea15734ae22b7c46064412829c0\
d0579f0a713d1c04ede979026f0100000000000186a000fd02026a206fe28c0ab\
6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000001976a914df\
662e2dd70fd82acba2d252cc897cb6e618093288ac21025f756509f5dbac47d54\
c9ef5ccf49895a4dbac4759005a74375f66c480e6c0864da1010ce552be292c37\
e7242d7e58e678a19349021d22f2712ea68de397b66167d141b09f98e3294e05b\
51c1469bab3ddb7096f5aa2817e218d137879fb54dbe1659353e6e64add9cb2d6\
f9e8647bd1ca94d9a6a80d193d76f115596f7bcc8a07eaf85c738f31f4fb192b7\
85aa2934bcb5e4f6a7b444da2bc64da3527a33cc7f0792630f57b92ba07dd0e47\
2d5e2e08b2bca8f1c06e18a07f226dac8acbcc1dfafe8be893d9c5092808b1dec\
fbb955c5f82968bed609b0b2e2c55abe4b0c12bc0c7ea3976e0af2c6aadab3c90\
ed862a9846fc1a1c20ef220a050538d3c9ff12669653f9b055606dd45fe66f18a\
a819c8cda5c1b224dc19c0fbf028133d1256588834ea14cb44a84da3af8344365\
7f9ff3eaa14216dc4ed06a92c0ce19be4fe066c9d830ee3acdd3062b9336ace12\
cc5935953284946bf6bc5c89f9a13d37dddd63e85173174a164f4b68cbc94d347\
b3d4a7e4ec79044b049375cc7b43b7657123b80f5834afca696b6bc7bf47fa677\
42e1caa609424cba3ec9d9d156b5909debd0475d91d31134acce50420c2ea694e\
2c2ea477a0bd14e670bccb42a0fb7009b41ee86a016d521c38ec1ea15734ae22b\
7c46064412829c0d0579f0a713d1c04ede979026f0100000000000006fc000054\
840300\
");

assert_eq!(tx.input.len(), 2);
assert_eq!(tx.output.len(), 3);
assert!(!tx.output[0].is_null_data());
assert!(!tx.output[0].is_pegout());
assert!(!tx.output[0].is_fee());

assert!(tx.output[1].is_null_data());
assert!(tx.output[1].is_pegout());
assert!(tx.output[1].pegout_data().is_some());
assert!(!tx.output[1].is_fee());

assert!(!tx.output[2].is_null_data());
assert!(!tx.output[2].is_pegout());
assert!(tx.output[2].is_fee());

assert_eq!(tx.output[0].asset, tx.output[1].asset);
assert_eq!(tx.output[2].asset, tx.output[1].asset);
}

#[test]
fn pegout_with_numeric_pak() {
let tx: Transaction = hex_deserialize!("\
0200000000021c39a226160dd8962eb273772950f0b603c319a8e4aa9912c9e8\
e36b5bdf71a2000000006a473044022071212fcde89d1055d5b74f17a162b3db\
e5348ac8527a131dab5dcf8a97d67d2f02202edf12f3c69fed1fa0c23da608e6\
aded86dd5c7b09da42f61b453c3a838e8cab012103557f25ff40f976670ddf59\
c71938bade91684b76ad69dfed27049de2afec59e5feffffff853db31f986dd8\
9c81fe87a84f385d7099c5ea841d762b26b03166e5e798dfbe000000006a4730\
44022042c70729fb50930179a9d76f5febbda5b0ee50e62febf92de4dd10b939\
3554d802203140b107519243e4110c065017c8ae1ac04843f94b3f20a1e5faf7\
343dd76159012102797ffcf7ccc8e2012a90e71962901a1ad740f2a28f2f563c\
76f9eb42a8100f5efeffffff03016d521c38ec1ea15734ae22b7c46064412829\
c0d0579f0a713d1c04ede979026f0100000000000f7869001976a914216d878e\
bff0c623909889265d8dc1ab26e2ff4388ac016d521c38ec1ea15734ae22b7c4\
6064412829c0d0579f0a713d1c04ede979026f0100000000000186a0005f6a20\
6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000\
1976a914df662e2dd70fd82acba2d252cc897cb6e618093288ac21025f756509\
f5dbac47d54c9ef5ccf49895a4dbac4759005a74375f66c480e6c08651016d52\
1c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04ede979026f0100\
000000000006fc000054840300\
");

assert_eq!(tx.input.len(), 2);
assert_eq!(tx.output.len(), 3);
assert!(!tx.output[0].is_null_data());
assert!(!tx.output[0].is_pegout());
assert!(!tx.output[0].is_fee());

assert!(tx.output[1].is_null_data());
assert!(!tx.output[1].is_pegout());
assert!(!tx.output[1].is_fee());

assert!(!tx.output[2].is_null_data());
assert!(!tx.output[2].is_pegout());
assert!(tx.output[2].is_fee());

assert_eq!(tx.output[0].asset, tx.output[1].asset);
assert_eq!(tx.output[2].asset, tx.output[1].asset);
}

#[test]
fn pegout_with_null_scriptpubkey() {
let tx: Transaction = hex_deserialize!("\
0200000000021c39a226160dd8962eb273772950f0b603c319a8e4aa9912c9e8\
e36b5bdf71a2000000006a473044022071212fcde89d1055d5b74f17a162b3db\
e5348ac8527a131dab5dcf8a97d67d2f02202edf12f3c69fed1fa0c23da608e6\
aded86dd5c7b09da42f61b453c3a838e8cab012103557f25ff40f976670ddf59\
c71938bade91684b76ad69dfed27049de2afec59e5feffffff853db31f986dd8\
9c81fe87a84f385d7099c5ea841d762b26b03166e5e798dfbe000000006a4730\
44022042c70729fb50930179a9d76f5febbda5b0ee50e62febf92de4dd10b939\
3554d802203140b107519243e4110c065017c8ae1ac04843f94b3f20a1e5faf7\
343dd76159012102797ffcf7ccc8e2012a90e71962901a1ad740f2a28f2f563c\
76f9eb42a8100f5efeffffff03016d521c38ec1ea15734ae22b7c46064412829\
c0d0579f0a713d1c04ede979026f0100000000000f7869001976a914216d878e\
bff0c623909889265d8dc1ab26e2ff4388ac016d521c38ec1ea15734ae22b7c4\
6064412829c0d0579f0a713d1c04ede979026f0100000000000186a000466a20\
6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000\
0021025f756509f5dbac47d54c9ef5ccf49895a4dbac4759005a74375f66c480\
e6c08600016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04\
ede979026f0100000000000006fc000054840300\
");

assert_eq!(tx.input.len(), 2);
assert_eq!(tx.output.len(), 3);
assert!(!tx.output[0].is_null_data());
assert!(!tx.output[0].is_pegout());
assert!(!tx.output[0].is_fee());

assert!(tx.output[1].is_null_data());
assert!(!tx.output[1].is_pegout());
assert!(!tx.output[1].is_fee());

assert!(!tx.output[2].is_null_data());
assert!(!tx.output[2].is_pegout());
assert!(tx.output[2].is_fee());

assert_eq!(tx.output[0].asset, tx.output[1].asset);
assert_eq!(tx.output[2].asset, tx.output[1].asset);
}
}