Skip to content

Commit a69f6ae

Browse files
committed
redefine "pegout" to better match elementsd RPC
1 parent 865bffa commit a69f6ae

File tree

1 file changed

+123
-13
lines changed

1 file changed

+123
-13
lines changed

src/transaction.rs

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ impl<D: Decoder> Decodable<D> for TxOut {
346346
}
347347

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

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

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

386-
let mut iter = self.script_pubkey.iter(true);
390+
let mut iter = self.script_pubkey.iter(false);
387391

388392
iter.next(); // Skip OP_RETURN
389393

@@ -406,17 +410,27 @@ impl TxOut {
406410
};
407411

408412
// Return everything
413+
let mut found_non_data_push = false;
409414
let remainder = iter
410-
.map(|x| if let Instruction::PushBytes(data) = x { data } else { unreachable!() })
415+
.filter_map(|x| if let Instruction::PushBytes(data) = x {
416+
Some(data)
417+
} else {
418+
found_non_data_push = true;
419+
None
420+
})
411421
.collect();
412422

413-
Some(PegoutData {
414-
asset: self.asset,
415-
value: value,
416-
genesis_hash: genesis_hash,
417-
script_pubkey: script_pubkey,
418-
extra_data: remainder,
419-
})
423+
if found_non_data_push {
424+
None
425+
} else {
426+
Some(PegoutData {
427+
asset: self.asset,
428+
value: value,
429+
genesis_hash: genesis_hash,
430+
script_pubkey: script_pubkey,
431+
extra_data: remainder,
432+
})
433+
}
420434
}
421435

422436
/// Whether or not this output is a fee output
@@ -1481,9 +1495,105 @@ mod tests {
14811495
fdfdfdfdfd3ca059fdf2226a20000000000000000000000000000000000000000\
14821496
0000000000000000000000000\
14831497
");
1484-
1498+
14851499
assert!(output.is_null_data());
14861500
assert!(!output.is_pegout());
14871501
}
1502+
1503+
#[test]
1504+
fn pegout_tx_vector_1() {
1505+
let tx: Transaction = hex_deserialize!("\
1506+
0200000000021c39a226160dd8962eb273772950f0b603c319a8e4aa9912c9e8e\
1507+
36b5bdf71a2000000006a473044022071212fcde89d1055d5b74f17a162b3dbe5\
1508+
348ac8527a131dab5dcf8a97d67d2f02202edf12f3c69fed1fa0c23da608e6ade\
1509+
d86dd5c7b09da42f61b453c3a838e8cab012103557f25ff40f976670ddf59c719\
1510+
38bade91684b76ad69dfed27049de2afec59e5feffffff853db31f986dd89c81f\
1511+
e87a84f385d7099c5ea841d762b26b03166e5e798dfbe000000006a4730440220\
1512+
42c70729fb50930179a9d76f5febbda5b0ee50e62febf92de4dd10b9393554d80\
1513+
2203140b107519243e4110c065017c8ae1ac04843f94b3f20a1e5faf7343dd761\
1514+
59012102797ffcf7ccc8e2012a90e71962901a1ad740f2a28f2f563c76f9eb42a\
1515+
8100f5efeffffff03016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a\
1516+
713d1c04ede979026f0100000000000f7869001976a914216d878ebff0c623909\
1517+
889265d8dc1ab26e2ff4388ac016d521c38ec1ea15734ae22b7c46064412829c0\
1518+
d0579f0a713d1c04ede979026f0100000000000186a000fd02026a206fe28c0ab\
1519+
6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000001976a914df\
1520+
662e2dd70fd82acba2d252cc897cb6e618093288ac21025f756509f5dbac47d54\
1521+
c9ef5ccf49895a4dbac4759005a74375f66c480e6c0864da1010ce552be292c37\
1522+
e7242d7e58e678a19349021d22f2712ea68de397b66167d141b09f98e3294e05b\
1523+
51c1469bab3ddb7096f5aa2817e218d137879fb54dbe1659353e6e64add9cb2d6\
1524+
f9e8647bd1ca94d9a6a80d193d76f115596f7bcc8a07eaf85c738f31f4fb192b7\
1525+
85aa2934bcb5e4f6a7b444da2bc64da3527a33cc7f0792630f57b92ba07dd0e47\
1526+
2d5e2e08b2bca8f1c06e18a07f226dac8acbcc1dfafe8be893d9c5092808b1dec\
1527+
fbb955c5f82968bed609b0b2e2c55abe4b0c12bc0c7ea3976e0af2c6aadab3c90\
1528+
ed862a9846fc1a1c20ef220a050538d3c9ff12669653f9b055606dd45fe66f18a\
1529+
a819c8cda5c1b224dc19c0fbf028133d1256588834ea14cb44a84da3af8344365\
1530+
7f9ff3eaa14216dc4ed06a92c0ce19be4fe066c9d830ee3acdd3062b9336ace12\
1531+
cc5935953284946bf6bc5c89f9a13d37dddd63e85173174a164f4b68cbc94d347\
1532+
b3d4a7e4ec79044b049375cc7b43b7657123b80f5834afca696b6bc7bf47fa677\
1533+
42e1caa609424cba3ec9d9d156b5909debd0475d91d31134acce50420c2ea694e\
1534+
2c2ea477a0bd14e670bccb42a0fb7009b41ee86a016d521c38ec1ea15734ae22b\
1535+
7c46064412829c0d0579f0a713d1c04ede979026f0100000000000006fc000054\
1536+
840300\
1537+
");
1538+
1539+
assert_eq!(tx.input.len(), 2);
1540+
assert_eq!(tx.output.len(), 3);
1541+
assert!(!tx.output[0].is_null_data());
1542+
assert!(!tx.output[0].is_pegout());
1543+
assert!(!tx.output[0].is_fee());
1544+
1545+
assert!(tx.output[1].is_null_data());
1546+
assert!(tx.output[1].is_pegout());
1547+
assert!(tx.output[1].pegout_data().is_some());
1548+
assert!(!tx.output[1].is_fee());
1549+
1550+
assert!(!tx.output[2].is_null_data());
1551+
assert!(!tx.output[2].is_pegout());
1552+
assert!(tx.output[2].is_fee());
1553+
1554+
assert_eq!(tx.output[0].asset, tx.output[1].asset);
1555+
assert_eq!(tx.output[2].asset, tx.output[1].asset);
1556+
}
1557+
1558+
#[test]
1559+
fn pegout_with_numeric_pak() {
1560+
let tx: Transaction = hex_deserialize!("\
1561+
0200000000021c39a226160dd8962eb273772950f0b603c319a8e4aa9912c9e8\
1562+
e36b5bdf71a2000000006a473044022071212fcde89d1055d5b74f17a162b3db\
1563+
e5348ac8527a131dab5dcf8a97d67d2f02202edf12f3c69fed1fa0c23da608e6\
1564+
aded86dd5c7b09da42f61b453c3a838e8cab012103557f25ff40f976670ddf59\
1565+
c71938bade91684b76ad69dfed27049de2afec59e5feffffff853db31f986dd8\
1566+
9c81fe87a84f385d7099c5ea841d762b26b03166e5e798dfbe000000006a4730\
1567+
44022042c70729fb50930179a9d76f5febbda5b0ee50e62febf92de4dd10b939\
1568+
3554d802203140b107519243e4110c065017c8ae1ac04843f94b3f20a1e5faf7\
1569+
343dd76159012102797ffcf7ccc8e2012a90e71962901a1ad740f2a28f2f563c\
1570+
76f9eb42a8100f5efeffffff03016d521c38ec1ea15734ae22b7c46064412829\
1571+
c0d0579f0a713d1c04ede979026f0100000000000f7869001976a914216d878e\
1572+
bff0c623909889265d8dc1ab26e2ff4388ac016d521c38ec1ea15734ae22b7c4\
1573+
6064412829c0d0579f0a713d1c04ede979026f0100000000000186a0005f6a20\
1574+
6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000\
1575+
1976a914df662e2dd70fd82acba2d252cc897cb6e618093288ac21025f756509\
1576+
f5dbac47d54c9ef5ccf49895a4dbac4759005a74375f66c480e6c08651016d52\
1577+
1c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04ede979026f0100\
1578+
000000000006fc000054840300\
1579+
");
1580+
1581+
assert_eq!(tx.input.len(), 2);
1582+
assert_eq!(tx.output.len(), 3);
1583+
assert!(!tx.output[0].is_null_data());
1584+
assert!(!tx.output[0].is_pegout());
1585+
assert!(!tx.output[0].is_fee());
1586+
1587+
assert!(tx.output[1].is_null_data());
1588+
assert!(!tx.output[1].is_pegout());
1589+
assert!(!tx.output[1].is_fee());
1590+
1591+
assert!(!tx.output[2].is_null_data());
1592+
assert!(!tx.output[2].is_pegout());
1593+
assert!(tx.output[2].is_fee());
1594+
1595+
assert_eq!(tx.output[0].asset, tx.output[1].asset);
1596+
assert_eq!(tx.output[2].asset, tx.output[1].asset);
1597+
}
14881598
}
14891599

0 commit comments

Comments
 (0)