def test_create_membership_proof(): leaves = [b'a', b'b', b'c'] merkle = FixedMerkle(2, leaves) proof_1 = merkle.create_membership_proof(b'a') proof_2 = merkle.create_membership_proof(b'c') assert merkle.check_membership(b'a', 0, proof_1) is True assert merkle.check_membership(b'c', 2, proof_2) is True
def withdraw(self, tx_id, oindex, exitor): transaction = self.transactions[tx_id] tx = transaction['tx'] encoded_tx = rlp.encode(tx).hex() tx_bytes = rlp.encode(tx, UnsignedTransaction) sigs = tx.sig1 + tx.sig2 + transaction['confirm_sigs'] blknum, txindex = self.child_chain.get_tx_pos(encoded_tx) utxo_pos = blknum * 1000000000 + txindex * 10000 + oindex * 1 if transaction['is_deposit']: deposit_amount = tx.amount1 self.root_chain.transact({ 'from': exitor['address'] }).startDepositExit(utxo_pos + 1, NULL_ADDRESS_HEX, deposit_amount) else: output_block = self.child_chain.blocks[blknum] hashed_transaction_set = [transaction.merkle_hash for transaction in output_block.transaction_set] merkle = FixedMerkle(16, hashed_transaction_set, hashed=True) proof = merkle.create_membership_proof(tx.merkle_hash) self.root_chain.transact({ 'from': exitor['address'] }).startExit(utxo_pos, tx_bytes, proof, sigs)
def start_standard_exit(self, output_id, key, bond=None): output_tx = self.child_chain.get_transaction(output_id) merkle = FixedMerkle(16, [output_tx.encoded]) proof = merkle.create_membership_proof(output_tx.encoded) bond = bond if bond is not None else self.root_chain.standardExitBond() self.root_chain.startStandardExit(output_id, output_tx.encoded, proof, value=bond, sender=key)
def test_challenge_exit(t, u, root_chain, assert_tx_failed): owner, value_1, key = t.a1, 100, t.k1 tx1 = Transaction(0, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) deposit_tx_hash = get_deposit_hash(owner, NULL_ADDRESS, value_1) utxo_pos1 = encode_utxo_id(root_chain.getDepositBlock(), 0, 0) root_chain.deposit(value=value_1, sender=key) utxo_pos2 = encode_utxo_id(root_chain.getDepositBlock(), 0, 0) root_chain.deposit(value=value_1, sender=key) merkle = FixedMerkle(16, [deposit_tx_hash], True) proof = merkle.create_membership_proof(deposit_tx_hash) confirmSig1 = confirm_tx(tx1, root_chain.getPlasmaBlock(utxo_pos1)[0], key) sigs = tx1.sig1 + tx1.sig2 + confirmSig1 root_chain.startDepositExit(utxo_pos1, NULL_ADDRESS, tx1.amount1, sender=key) tx3 = Transaction(utxo_pos2, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) tx3.sign1(key) tx_bytes3 = rlp.encode(tx3, UnsignedTransaction) merkle = FixedMerkle(16, [tx3.merkle_hash], True) proof = merkle.create_membership_proof(tx3.merkle_hash) child_blknum = root_chain.currentChildBlock() root_chain.submitBlock(merkle.root) confirmSig = confirm_tx(tx3, root_chain.getPlasmaBlock(child_blknum)[0], key) sigs = tx3.sig1 + tx3.sig2 utxo_pos3 = encode_utxo_id(child_blknum, 0, 0) tx4 = Transaction(utxo_pos1, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) tx4.sign1(key) tx_bytes4 = rlp.encode(tx4, UnsignedTransaction) merkle = FixedMerkle(16, [tx4.merkle_hash], True) proof = merkle.create_membership_proof(tx4.merkle_hash) child_blknum = root_chain.currentChildBlock() root_chain.submitBlock(merkle.root) confirmSig = confirm_tx(tx4, root_chain.getPlasmaBlock(child_blknum)[0], key) sigs = tx4.sig1 + tx4.sig2 utxo_pos4 = encode_utxo_id(child_blknum, 0, 0) oindex1 = 0 assert root_chain.exits(utxo_pos1) == [ '0x' + owner.hex(), NULL_ADDRESS_HEX, 100 ] # Fails if transaction after exit doesn't reference the utxo being exited assert_tx_failed(lambda: root_chain.challengeExit( utxo_pos3, oindex1, tx_bytes3, proof, sigs, confirmSig)) # Fails if transaction proof is incorrect assert_tx_failed(lambda: root_chain.challengeExit( utxo_pos4, oindex1, tx_bytes4, proof[::-1], sigs, confirmSig)) # Fails if transaction confirmation is incorrect assert_tx_failed(lambda: root_chain.challengeExit( utxo_pos4, oindex1, tx_bytes4, proof, sigs, confirmSig[::-1])) root_chain.challengeExit(utxo_pos4, oindex1, tx_bytes4, proof, sigs, confirmSig) assert root_chain.exits(utxo_pos1) == [ NULL_ADDRESS_HEX, NULL_ADDRESS_HEX, value_1 ]
def start_standard_exit_with_tx_body(self, output_id, output_tx, key, bond=None): merkle = FixedMerkle(16, [output_tx.encoded]) proof = merkle.create_membership_proof(output_tx.encoded) bond = bond if bond is not None else self.root_chain.standardExitBond() self.root_chain.startStandardExit(output_id, output_tx.encoded, proof, value=bond, sender=key)
def test_initialize_with_leaves_more_than_depth_permits(): depth = 1 leaves = [b'dummy leaf'] * (2**depth + 1) with pytest.raises(ValueError) as e: FixedMerkle(depth, leaves, True) assert str( e.value) == 'num of leaves exceed max avaiable num with the depth'
def test_initialize_with_too_many_leaves(): depth = 1 leaves = [b'asdf'] * (2**depth + 1) with pytest.raises(ValueError) as e: FixedMerkle(depth, leaves) assert str(e.value) == 'number of leaves should be at most depth ** 2'
def test_initialize_with_leaves(num_leaves): depth = math.ceil(math.log(num_leaves, 2)) leaves = [b'asdf'] * num_leaves hashed_leaves = [sha3(leaf) for leaf in leaves] empty_leaves = [sha3(NULL_HASH)] * (2**depth - num_leaves) assert FixedMerkle(depth, leaves).leaves == hashed_leaves + empty_leaves
def test_create_membership_proof(): leaf = b'c' leaves = [b'a', b'b', leaf] proof = FixedMerkle(2, leaves).create_membership_proof(leaf) sibling_hash = sha3(LEAF_SALT + NULL_HASH) node_hash = sha3(NODE_SALT + sha3(LEAF_SALT + leaves[0]) + sha3(LEAF_SALT + leaves[1])) assert proof == sibling_hash + node_hash
def test_deposit_valid_values_should_succeed(ethtester, testlang): owner, amount = testlang.accounts[0], 100 deposit_id = testlang.deposit(owner, amount) deposit_tx = testlang.child_chain.get_transaction(deposit_id) merkle = FixedMerkle(16, [deposit_tx.encoded]) assert testlang.root_chain.blocks(1) == [merkle.root, ethtester.chain.head_state.timestamp] assert testlang.root_chain.nextDepositBlock() == 2
def start_standard_exit_with_tx_body(self, output_id, output_tx, account, bond=None, block=None): transactions = [output_tx] if block: transactions = block.transactions merkle = FixedMerkle(16, list(map(lambda tx: tx.encoded, transactions))) proof = merkle.create_membership_proof(output_tx.encoded) bond = bond if bond is not None else self.root_chain.standardExitBond() self.root_chain.startStandardExit( output_id, output_tx.encoded, proof, **{ 'value': bond, 'from': account.address })
def challenge_exit(self, blknum, confirmSig, account): oindex = 0 utxo_pos = blknum * 1000000000 + 10000 * 0 + oindex tx = self.get_transaction(utxo_pos) tx_bytes = rlp.encode(tx, UnsignedTransaction) merkle = FixedMerkle(16, [tx.merkle_hash], True) proof = merkle.create_membership_proof(tx.merkle_hash) sigs = tx.sig1 + tx.sig2 return self.root_chain.challengeExit(utxo_pos, oindex, tx_bytes, proof, sigs, confirmSig, transact={ 'from': account, 'gas': 40000000 })
def test_check_membership(u): leaf_1 = b'\xff' * 31 + b'\x01' leaf_2 = b'\xff' * 31 + b'\x02' leaf_3 = b'\xff' * 31 + b'\x03' leaf_4 = b'\xff' * 31 + b'\x04' root = u.sha3(u.sha3(leaf_1 + leaf_2) + u.sha3(leaf_3 + leaf_4)) zeros_hashes = get_empty_merkle_tree_hash(2) for _ in range(13): root = u.sha3(root + zeros_hashes[-32:]) zeros_hashes += u.sha3(zeros_hashes[-32:] + zeros_hashes[-32:]) left_proof = leaf_2 + u.sha3(leaf_3 + leaf_4) + zeros_hashes left_middle_proof = leaf_1 + u.sha3(leaf_3 + leaf_4) + zeros_hashes right_middle_proof = leaf_4 + u.sha3(leaf_1 + leaf_2) + zeros_hashes right_proof = leaf_3 + u.sha3(leaf_1 + leaf_2) + zeros_hashes fixed_merkle = FixedMerkle(16, [leaf_1, leaf_2, leaf_3, leaf_4], True) assert fixed_merkle.check_membership(leaf_1, 0, left_proof) is True assert fixed_merkle.check_membership(leaf_2, 1, left_middle_proof) is True assert fixed_merkle.check_membership(leaf_3, 2, right_middle_proof) is True assert fixed_merkle.check_membership(leaf_4, 3, right_proof) is True
def merkle_tree(self): hashed_transaction_set = [ transaction.merkle_hash for transaction in self.transaction_set ] return FixedMerkle(16, hashed_transaction_set, hashed=True)
def test_non_member(): leaves = [b'a', b'b', b'c'] merkle = FixedMerkle(2, leaves, True) assert merkle.not_member(b'b') is False assert merkle.not_member(b'd') is True
def test_initial_state(): assert FixedMerkle(2).leaves == [NULL_HASH] * 4 assert FixedMerkle(3).leaves == [NULL_HASH] * 8 assert FixedMerkle(12).leaves == [NULL_HASH] * (2**12)
def test_initial_state(depth): assert FixedMerkle(depth).leaves == [sha3(NULL_HASH)] * (2**depth)
def test_initialize_with_leaves(): leaves_1 = [b'a', b'c', b'c'] leaves_2 = [b'a', b'c', b'c', b'd', b'e'] assert FixedMerkle(2, leaves_1, True).leaves == leaves_1 + [NULL_HASH] assert FixedMerkle(3, leaves_2, True).leaves == leaves_2 + [NULL_HASH] * 3
def test_hash_empty_tree(): root_1 = sha3(NULL_HASH + NULL_HASH) root_2 = sha3(root_1 + root_1) assert FixedMerkle(1, [], True).root == root_1 assert FixedMerkle(2, [], True).root == root_2 assert FixedMerkle(16, [], True).root == get_empty_merkle_tree_hash(16)
def get_merkle_of_leaves(depth, leaves): return FixedMerkle(depth, leaves)
def test_empty_tree(depth): assert FixedMerkle(depth).root == get_empty_tree_hash(depth)
def test_create_membership_proof(): leaves = [b'a', b'b', b'c'] proof = FixedMerkle(2, leaves).create_membership_proof(leaves[2]) assert proof == sha3(NULL_HASH) + sha3(sha3(leaves[0]) + sha3(leaves[1]))
def merklize_transaction_set(self): hashed_transaction_set = [ transaction.merkle_hash for transaction in self.transaction_set ] self.merkle = FixedMerkle(16, hashed_transaction_set, hashed=True) return self.merkle.root
def test_check_membership(): leaves = [b'a', b'b', b'c'] merkle = FixedMerkle(2, leaves) proof = merkle.create_membership_proof(leaves[2]) assert merkle.check_membership(leaves[2], 2, proof)
def test_start_exit(t, root_chain, assert_tx_failed): week_and_a_half = 60 * 60 * 24 * 13 owner, value_1, key = t.a1, 100, t.k1 tx1 = Transaction(0, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) deposit_tx_hash = get_deposit_hash(owner, NULL_ADDRESS, value_1) dep_blknum = root_chain.getDepositBlock() assert dep_blknum == 1 root_chain.deposit(value=value_1, sender=key) merkle = FixedMerkle(16, [deposit_tx_hash], True) proof = merkle.create_membership_proof(deposit_tx_hash) confirmSig1 = tx1.confirm(root_chain.getChildChain(dep_blknum)[0], key) priority1 = dep_blknum * 1000000000 + 10000 * 0 + 1 snapshot = t.chain.snapshot() sigs = tx1.sig1 + tx1.sig2 + confirmSig1 utxoId = dep_blknum * 1000000000 + 10000 * 0 + 1 # Deposit exit root_chain.startDepositExit(utxoId, NULL_ADDRESS, tx1.amount1, sender=key) t.chain.head_state.timestamp += week_and_a_half # Cannot exit twice off of the same utxo utxo_pos1 = dep_blknum * 1000000000 + 10000 * 0 + 1 assert_tx_failed(lambda: root_chain.startExit( utxo_pos1, deposit_tx_hash, proof, sigs, sender=key)) assert root_chain.getExit(priority1) == [ address_to_hex(owner), NULL_ADDRESS_HEX, 100 ] t.chain.revert(snapshot) tx2 = Transaction(dep_blknum, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) tx2.sign1(key) tx_bytes2 = rlp.encode(tx2, UnsignedTransaction) merkle = FixedMerkle(16, [tx2.merkle_hash], True) proof = merkle.create_membership_proof(tx2.merkle_hash) child_blknum = root_chain.currentChildBlock() assert child_blknum == 1000 root_chain.submitBlock(merkle.root) confirmSig1 = tx2.confirm(root_chain.getChildChain(child_blknum)[0], key) priority2 = child_blknum * 1000000000 + 10000 * 0 + 0 sigs = tx2.sig1 + tx2.sig2 + confirmSig1 snapshot = t.chain.snapshot() # # Single input exit utxo_pos2 = child_blknum * 1000000000 + 10000 * 0 + 0 root_chain.startExit(utxo_pos2, tx_bytes2, proof, sigs, sender=key) assert root_chain.getExit(priority2) == [ address_to_hex(owner), NULL_ADDRESS_HEX, 100 ] t.chain.revert(snapshot) dep2_blknum = root_chain.getDepositBlock() assert dep2_blknum == 1001 root_chain.deposit(value=value_1, sender=key) tx3 = Transaction(child_blknum, 0, 0, dep2_blknum, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0, 0) tx3.sign1(key) tx3.sign2(key) tx_bytes3 = rlp.encode(tx3, UnsignedTransaction) merkle = FixedMerkle(16, [tx3.merkle_hash], True) proof = merkle.create_membership_proof(tx3.merkle_hash) child2_blknum = root_chain.currentChildBlock() assert child2_blknum == 2000 root_chain.submitBlock(merkle.root) confirmSig1 = tx3.confirm(root_chain.getChildChain(child2_blknum)[0], key) confirmSig2 = tx3.confirm(root_chain.getChildChain(child2_blknum)[0], key) priority3 = child2_blknum * 1000000000 + 10000 * 0 + 0 sigs = tx3.sig1 + tx3.sig2 + confirmSig1 + confirmSig2 # Double input exit utxoPos3 = child2_blknum * 1000000000 + 10000 * 0 + 0 root_chain.startExit(utxoPos3, tx_bytes3, proof, sigs, sender=key) assert root_chain.getExit(priority3) == [ address_to_hex(owner), NULL_ADDRESS_HEX, 100 ]
def test_start_exit(t, root_chain, assert_tx_failed): week_and_a_half = 60 * 60 * 24 * 13 owner, value_1, key = t.a1, 100, t.k1 tx1 = Transaction(0, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) deposit_tx_hash = get_deposit_hash(owner, NULL_ADDRESS, value_1) dep_blknum = root_chain.getDepositBlock() assert dep_blknum == 1 root_chain.deposit(value=value_1, sender=key) merkle = FixedMerkle(16, [deposit_tx_hash], True) proof = merkle.create_membership_proof(deposit_tx_hash) confirmSig1 = confirm_tx(tx1, root_chain.getPlasmaBlock(dep_blknum)[0], key) snapshot = t.chain.snapshot() sigs = tx1.sig1 + tx1.sig2 + confirmSig1 utxoId = encode_utxo_id(dep_blknum, 0, 0) # Deposit exit exit_bond = root_chain.EXIT_BOND() root_chain.startDepositExit(utxoId, NULL_ADDRESS, tx1.amount1, sender=key, value=exit_bond) t.chain.head_state.timestamp += week_and_a_half # Cannot exit twice off of the same utxo utxo_pos1 = encode_utxo_id(dep_blknum, 0, 0) assert_tx_failed(lambda: root_chain.startExit( utxo_pos1, deposit_tx_hash, proof, sigs, sender=key, value=exit_bond)) assert root_chain.getExit(utxo_pos1) == [ '0x' + owner.hex(), NULL_ADDRESS_HEX, 100 ] t.chain.revert(snapshot) tx2 = Transaction(dep_blknum, 0, 0, 0, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0) tx2.sign1(key) tx_bytes2 = rlp.encode(tx2, UnsignedTransaction) merkle = FixedMerkle(16, [tx2.merkle_hash], True) proof = merkle.create_membership_proof(tx2.merkle_hash) child_blknum = root_chain.currentChildBlock() assert child_blknum == 1000 root_chain.submitBlock(merkle.root) confirmSig1 = confirm_tx(tx2, root_chain.getPlasmaBlock(child_blknum)[0], key) sigs = tx2.sig1 + tx2.sig2 + confirmSig1 snapshot = t.chain.snapshot() # # Single input exit utxo_pos2 = encode_utxo_id(child_blknum, 0, 0) root_chain.startExit(utxo_pos2, tx_bytes2, proof, sigs, sender=key, value=exit_bond) assert root_chain.getExit(utxo_pos2) == [ '0x' + owner.hex(), NULL_ADDRESS_HEX, 100 ] t.chain.revert(snapshot) dep2_blknum = root_chain.getDepositBlock() assert dep2_blknum == 1001 root_chain.deposit(value=value_1, sender=key) tx3 = Transaction(child_blknum, 0, 0, dep2_blknum, 0, 0, NULL_ADDRESS, owner, value_1, NULL_ADDRESS, 0, 0) tx3.sign1(key) tx3.sign2(key) tx_bytes3 = rlp.encode(tx3, UnsignedTransaction) merkle = FixedMerkle(16, [tx3.merkle_hash], True) proof = merkle.create_membership_proof(tx3.merkle_hash) child2_blknum = root_chain.currentChildBlock() assert child2_blknum == 2000 root_chain.submitBlock(merkle.root) confirmSig1 = confirm_tx(tx3, root_chain.getPlasmaBlock(child2_blknum)[0], key) confirmSig2 = confirm_tx(tx3, root_chain.getPlasmaBlock(child2_blknum)[0], key) sigs = tx3.sig1 + tx3.sig2 + confirmSig1 + confirmSig2 # Double input exit utxo_pos3 = encode_utxo_id(child2_blknum, 0, 0) root_chain.startExit(utxo_pos3, tx_bytes3, proof, sigs, sender=key, value=exit_bond) assert root_chain.getExit(utxo_pos3) == [ '0x' + owner.hex(), NULL_ADDRESS_HEX, 100 ]
def merklized_transaction_set(self): encoded_transactions = [tx.encoded for tx in self.transactions] return FixedMerkle(16, encoded_transactions)
def merklized_transaction_set(self): hashed_transactions = [tx.merkle_hash for tx in self.transaction_set] return FixedMerkle(16, hashed_transactions, hashed=True)