python test support for issuance and peg-in serialization and data

This commit is contained in:
Gregory Sanders 2019-03-22 16:03:30 -04:00
parent 8140a87dec
commit ac98ca4eb1
2 changed files with 95 additions and 6 deletions

View file

@ -13,6 +13,11 @@ from test_framework.util import (
assert_raises_rpc_error,
assert_equal,
)
from test_framework.messages import (
CTransaction,
CTxInWitness,
FromHex,
)
from decimal import Decimal
def get_new_unconfidential_address(node, addr_type="p2sh-segwit"):
@ -212,6 +217,12 @@ class FedPegTest(BitcoinTestFramework):
raw_pegin = sidechain.createrawpegin(raw, proof)['hex']
signed_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)
sample_pegin_struct = FromHex(CTransaction(), signed_pegin["hex"])
# Round-trip peg-in transaction using python serialization
assert_equal(signed_pegin["hex"], sample_pegin_struct.serialize().hex())
# Store this for later (evil laugh)
sample_pegin_witness = sample_pegin_struct.wit.vtxinwit[0].peginWitness
pegtxid1 = sidechain.claimpegin(raw, proof)
# Will invalidate the block that confirms this transaction later
@ -388,6 +399,21 @@ class FedPegTest(BitcoinTestFramework):
assert(sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)
# Test superfluous peg-in witness data on regular spend before we have no funds
raw_spend = sidechain.createrawtransaction([], {sidechain.getnewaddress():1})
fund_spend = sidechain.fundrawtransaction(raw_spend)
sign_spend = sidechain.signrawtransactionwithwallet(fund_spend["hex"])
signed_struct = FromHex(CTransaction(), sign_spend["hex"])
# Non-witness tx has no witness serialized yet
if len(signed_struct.wit.vtxinwit) == 0:
signed_struct.wit.vtxinwit = [CTxInWitness()]
signed_struct.wit.vtxinwit[0].peginWitness.stack = sample_pegin_witness.stack
assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["allowed"], False)
assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["reject-reason"], "68: extra-pegin-witness")
signed_struct.wit.vtxinwit[0].peginWitness.stack = [b'\x00'*100000] # lol
assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["allowed"], False)
assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["reject-reason"], "68: extra-pegin-witness")
peg_out_txid = sidechain.sendtomainchain(some_btc_addr, 1)
peg_out_details = sidechain.decoderawtransaction(sidechain.getrawtransaction(peg_out_txid))

View file

@ -285,6 +285,38 @@ class COutPoint():
def __repr__(self):
return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n)
OUTPOINT_ISSUANCE_FLAG = (1 << 31)
OUTPOINT_PEGIN_FLAG = (1 << 30)
OUTPOINT_INDEX_MASK = 0x3fffffff
class CAssetIssuance():
def __init__(self):
self.assetBlindingNonce = 0
self.assetEntropy = 0
self.nAmount = CTxOutValue()
self.nInflationKeys = CTxOutValue()
def isNull(self):
return self.nAmount.isNull() and self.nInflationKeys.isNull()
def deserialize(self, f):
self.assetBlindingNonce = deser_uint256(f)
self.assetEntropy = deser_uint256(f)
self.nAmount = CTxOutValue()
self.nAmount.deserialize(f)
self.nInflationKeys = CTxOutValue()
self.nInflatoinKeys.deserialize(f)
def serialize(self):
r = b""
r += ser_uint256(self.assetBlindingNonce)
r += ser_uint256(self.assetEntropy)
r += self.nAmount.serialize()
r += self.nInflationKeys.serialize()
return r
def __repr__(self):
return "CAssetIssuance(assetBlindingNonce=%064x assetEntropy=%064x nAmount=%s nInflationKeys=%s)" % (self.assetBlindingNonce, self.assetEntropy, self.nAmount.vchCommitment, self.nInflationKeys.vchCommitment)
class CTxIn():
def __init__(self, outpoint=None, scriptSig=b"", nSequence=0):
@ -294,24 +326,52 @@ class CTxIn():
self.prevout = outpoint
self.scriptSig = scriptSig
self.nSequence = nSequence
self.m_is_pegin = False
self.assetIssuance = CAssetIssuance()
def deserialize(self, f):
self.prevout = COutPoint()
self.prevout.deserialize(f)
has_asset_issuance = False
# Do masking, extract presence of assetIssuance
if not self.prevout.isNull(): # ignore coinbase for issuance/pegin
if self.prevout.n & OUTPOINT_ISSUANCE_FLAG > 0:
has_asset_issuance = True
if self.prevout.n & OUTPOINT_PEGIN_FLAG > 0:
self.m_is_pegin = True
self.prevout.n = self.prevout.n & OUTPOINT_INDEX_MASK
self.scriptSig = deser_string(f)
self.nSequence = struct.unpack("<I", f.read(4))[0]
if has_asset_issuance:
self.assetIssuance = CAssetIssuance()
self.assetIssuance.deserialize(f)
def serialize(self):
outpoint = COutPoint()
outpoint.hash = self.prevout.hash
outpoint.n = self.prevout.n
# First apply peg-in and issuance logic to prevout.n, before serializing
if self.prevout.n != 4294967295: # ignore coinbase for issuance/pegin
if not self.assetIssuance.isNull():
outpoint.n |= OUTPOINT_ISSUANCE_FLAG
if self.m_is_pegin:
outpoint.n |= OUTPOINT_PEGIN_FLAG
r = b""
r += self.prevout.serialize()
r += outpoint.serialize()
r += ser_string(self.scriptSig)
r += struct.pack("<I", self.nSequence)
if self.prevout.n != 4294967295 and outpoint.n & OUTPOINT_ISSUANCE_FLAG:
r += self.assetIssuance.serialize()
return r
def __repr__(self):
return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" \
return "CTxIn(prevout=%s scriptSig=%s nSequence=%i m_is_pegin=%s assetIssuance=%s)" \
% (repr(self.prevout), bytes_to_hex_str(self.scriptSig),
self.nSequence)
self.nSequence, self.m_is_pegin, self.assetIssuance)
class CTxOutAsset(object):
def __init__(self, vchCommitment=b"\x00"):
@ -356,6 +416,9 @@ class CTxOutValue(object):
def setNull(self):
self.vchCommitment = b'\x00'
def isNull(self):
return self.vchCommitment == b'\x00'
def deserialize(self, f):
version = ord(f.read(1))
if version == 0:
@ -510,8 +573,8 @@ class CTxInWitness(object):
return calcfastmerkleroot(leaves)
def __repr__(self):
return "CTxInWitness (%s, %s, %s)" % (self.vchIssuanceAmountRangeproof,
self.vchInflationKeysRangeproof, self.scriptWitness)
return "CTxInWitness (%s, %s, %s %s)" % (self.vchIssuanceAmountRangeproof,
self.vchInflationKeysRangeproof, self.scriptWitness, self.peginWitness)
def is_null(self):
return len(self.vchIssuanceAmountRangeproof) == 0 \
@ -799,7 +862,7 @@ class CBlockHeader():
return self.sha256
def __repr__(self):
return "CBlockHeader(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x block_height=%s nTime=%s)" \
return "CBlockHeader(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x ntime=%s block_height=%s)" \
% (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,
time.ctime(self.nTime), self.block_height)