mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
create_tx and sign_tx create threshold conditions by default if there
are multiple current owners. Created tests
This commit is contained in:
parent
74a1e14183
commit
4c4cae8f81
@ -194,8 +194,8 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
|||||||
conditions = []
|
conditions = []
|
||||||
for fulfillment in fulfillments:
|
for fulfillment in fulfillments:
|
||||||
if len(new_owners) > 1:
|
if len(new_owners) > 1:
|
||||||
|
condition = ThresholdSha256Fulfillment(threshold=len(new_owners))
|
||||||
for new_owner in new_owners:
|
for new_owner in new_owners:
|
||||||
condition = ThresholdSha256Fulfillment(threshold=len(new_owners))
|
|
||||||
condition.add_subfulfillment(Ed25519Fulfillment(public_key=new_owner))
|
condition.add_subfulfillment(Ed25519Fulfillment(public_key=new_owner))
|
||||||
elif len(new_owners) == 1:
|
elif len(new_owners) == 1:
|
||||||
condition = Ed25519Fulfillment(public_key=new_owners[0])
|
condition = Ed25519Fulfillment(public_key=new_owners[0])
|
||||||
@ -231,7 +231,7 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
|||||||
|
|
||||||
|
|
||||||
# TODO: Change sign_tx to populate the fulfillments
|
# TODO: Change sign_tx to populate the fulfillments
|
||||||
def sign_tx(transaction, sk):
|
def sign_tx(transaction, sks):
|
||||||
"""Sign a transaction
|
"""Sign a transaction
|
||||||
|
|
||||||
A transaction signed with the `current_owner` corresponding private key.
|
A transaction signed with the `current_owner` corresponding private key.
|
||||||
@ -244,7 +244,20 @@ def sign_tx(transaction, sk):
|
|||||||
dict: transaction with the `fulfillment` fields populated.
|
dict: transaction with the `fulfillment` fields populated.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
sk = crypto.SigningKey(sk)
|
# validate sk
|
||||||
|
if not isinstance(sks, list):
|
||||||
|
sks = [sks]
|
||||||
|
|
||||||
|
if len(sks) == 1:
|
||||||
|
sk = crypto.SigningKey(sks[0])
|
||||||
|
else:
|
||||||
|
# create a mapping between sk and vk so that we can match the private key to the current_owners
|
||||||
|
key_pairs = {}
|
||||||
|
for sk in sks:
|
||||||
|
signing_key = crypto.SigningKey(sk)
|
||||||
|
vk = signing_key.get_verifying_key().to_ascii().decode()
|
||||||
|
key_pairs[vk] = signing_key
|
||||||
|
|
||||||
tx = copy.deepcopy(transaction)
|
tx = copy.deepcopy(transaction)
|
||||||
|
|
||||||
for fulfillment in tx['transaction']['fulfillments']:
|
for fulfillment in tx['transaction']['fulfillments']:
|
||||||
@ -254,7 +267,19 @@ def sign_tx(transaction, sk):
|
|||||||
parsed_fulfillment = Ed25519Fulfillment(public_key=sk.get_verifying_key())
|
parsed_fulfillment = Ed25519Fulfillment(public_key=sk.get_verifying_key())
|
||||||
else:
|
else:
|
||||||
parsed_fulfillment = Fulfillment.from_json(fulfillment_message['condition']['condition']['details'])
|
parsed_fulfillment = Fulfillment.from_json(fulfillment_message['condition']['condition']['details'])
|
||||||
parsed_fulfillment.sign(serialize(fulfillment_message), sk)
|
|
||||||
|
# single current owner
|
||||||
|
if isinstance(parsed_fulfillment, Ed25519Fulfillment):
|
||||||
|
parsed_fulfillment.sign(serialize(fulfillment_message), sk)
|
||||||
|
# multiple current owners
|
||||||
|
elif isinstance(parsed_fulfillment, ThresholdSha256Fulfillment):
|
||||||
|
# replace the fulfillments with the signed fulfillments
|
||||||
|
parsed_fulfillment.subconditions = []
|
||||||
|
for current_owner in fulfillment['current_owners']:
|
||||||
|
subfulfillment = get_subcondition_from_vk(fulfillment_message['condition'], current_owner)
|
||||||
|
subfulfillment.sign(serialize(fulfillment_message), key_pairs[current_owner])
|
||||||
|
parsed_fulfillment.add_subfulfillment(subfulfillment)
|
||||||
|
|
||||||
signed_fulfillment = parsed_fulfillment.serialize_uri()
|
signed_fulfillment = parsed_fulfillment.serialize_uri()
|
||||||
fulfillment.update({'fulfillment': signed_fulfillment})
|
fulfillment.update({'fulfillment': signed_fulfillment})
|
||||||
|
|
||||||
@ -331,10 +356,17 @@ def get_fulfillment_message(transaction, fulfillment):
|
|||||||
# get previous condition
|
# get previous condition
|
||||||
previous_tx = b.get_transaction(fulfillment['input']['txid'])
|
previous_tx = b.get_transaction(fulfillment['input']['txid'])
|
||||||
conditions = sorted(previous_tx['transaction']['conditions'], key=lambda d: d['cid'])
|
conditions = sorted(previous_tx['transaction']['conditions'], key=lambda d: d['cid'])
|
||||||
fulfillment_message['condition'] = conditions[fulfillment['fid']]
|
fulfillment_message['condition'] = conditions[fulfillment['input']['cid']]
|
||||||
return fulfillment_message
|
return fulfillment_message
|
||||||
|
|
||||||
|
|
||||||
|
def get_subcondition_from_vk(condition, vk):
|
||||||
|
threshold_fulfillment = Fulfillment.from_json(condition['condition']['details'])
|
||||||
|
for subcondition in threshold_fulfillment.subconditions:
|
||||||
|
if subcondition['body'].public_key.to_ascii().decode() == vk:
|
||||||
|
return subcondition['body']
|
||||||
|
|
||||||
|
|
||||||
def transform_create(tx):
|
def transform_create(tx):
|
||||||
"""Change the owner and signature for a ``CREATE`` transaction created by a node"""
|
"""Change the owner and signature for a ``CREATE`` transaction created by a node"""
|
||||||
|
|
||||||
|
@ -745,16 +745,167 @@ class TestBigchainBlock(object):
|
|||||||
|
|
||||||
|
|
||||||
class TestMultipleInputs(object):
|
class TestMultipleInputs(object):
|
||||||
def test_transfer_single_owners_single_input(self, b):
|
def test_transfer_single_owners_single_input(self, b, user_sk, user_vk, inputs):
|
||||||
|
# create a new user
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inp = owned_inputs.pop()
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction([user_vk], [user2_sk], inp, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user_sk)
|
||||||
|
|
||||||
|
# validate transaction
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 1
|
||||||
|
|
||||||
|
def test_transfer_single_owners_multiple_inputs(self, b, user_sk, user_vk):
|
||||||
|
# create a new user
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create inputs to spend
|
||||||
|
transactions = []
|
||||||
|
for i in range(10):
|
||||||
|
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||||
|
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||||
|
transactions.append(tx_signed)
|
||||||
|
b.write_transaction(tx_signed)
|
||||||
|
block = b.create_block(transactions)
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inputs = owned_inputs[:3]
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction(user_vk, user2_vk, inputs, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user_sk)
|
||||||
|
|
||||||
|
# validate transaction
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 3
|
||||||
|
|
||||||
|
def test_transfer_single_owners_single_input_from_multiple_outputs(self, b, user_sk, user_vk):
|
||||||
|
# create a new user
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create inputs to spend
|
||||||
|
transactions = []
|
||||||
|
for i in range(10):
|
||||||
|
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||||
|
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||||
|
transactions.append(tx_signed)
|
||||||
|
b.write_transaction(tx_signed)
|
||||||
|
block = b.create_block(transactions)
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inputs = owned_inputs[:3]
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction(user_vk, user2_vk, inputs, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user_sk)
|
||||||
|
|
||||||
|
# create block with the transaction
|
||||||
|
block = b.create_block([tx_signed])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
# get inputs from user2
|
||||||
|
owned_inputs = b.get_owned_ids(user2_vk)
|
||||||
|
assert len(owned_inputs) == 3
|
||||||
|
|
||||||
|
# create a transaction with a single input from a multiple output transaction
|
||||||
|
inp = owned_inputs.pop()
|
||||||
|
tx = b.create_transaction(user2_vk, user_vk, inp, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user2_sk)
|
||||||
|
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 1
|
||||||
|
|
||||||
|
def test_single_current_owner_multiple_new_owners_single_input(self, b, user_sk, user_vk, inputs):
|
||||||
|
# create a new users
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inp = owned_inputs.pop()
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction(user_vk, [user2_sk, user3_vk], inp, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user_sk)
|
||||||
|
|
||||||
|
# validate transaction
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 1
|
||||||
|
|
||||||
|
def test_single_current_owner_multiple_new_owners_multiple_inputs(self, b, user_sk, user_vk):
|
||||||
|
# create a new users
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create inputs to spend
|
||||||
|
transactions = []
|
||||||
|
for i in range(5):
|
||||||
|
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||||
|
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||||
|
transactions.append(tx_signed)
|
||||||
|
b.write_transaction(tx_signed)
|
||||||
|
block = b.create_block(transactions)
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inputs = owned_inputs[:3]
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction(user_vk, [user2_vk, user3_vk], inputs, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, user_sk)
|
||||||
|
|
||||||
|
# validate transaction
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 3
|
||||||
|
|
||||||
|
@pytest.mark.skipif(reason='Skip until we fix default threshold signatures')
|
||||||
|
def test_multiple_current_owners_single_new_owner_single_input(self, b, user_sk, user_vk):
|
||||||
|
# create a new users
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create input to spend
|
||||||
|
tx = b.create_transaction(b.me, [user_vk, user2_vk], None, 'CREATE')
|
||||||
|
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||||
|
block = b.create_block([tx_signed])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
# get inputs
|
||||||
|
owned_inputs = b.get_owned_ids(user_vk)
|
||||||
|
inputs = owned_inputs[:3]
|
||||||
|
|
||||||
|
# create a transaction
|
||||||
|
tx = b.create_transaction([user_vk, user2_vk], user3_vk, inputs, 'TRANSFER')
|
||||||
|
tx_signed = b.sign_transaction(tx, [user_sk, user2_sk])
|
||||||
|
|
||||||
|
# validate transaction
|
||||||
|
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||||
|
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||||
|
assert len(tx_signed['transaction']['conditions']) == 3
|
||||||
|
|
||||||
|
def test_multiple_current_owners_single_new_owner_multiple_inputs(self, b, user_sk, user_vk):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_transfer_single_owners_multiple_inputs(self, b):
|
def test_multiple_current_owners_multiple_new_owners_single_input(self, b):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_transfer_single_owners_single_input_from_multiple_outputs(self, b):
|
def test_multiple_current_owners_multiple_new_owners_multiple_inputs(self, b):
|
||||||
pass
|
|
||||||
|
|
||||||
def test_multiple_owners(self, b):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_get_spent(self, b):
|
def test_get_spent(self, b):
|
||||||
@ -1034,3 +1185,9 @@ class TestCryptoconditions(object):
|
|||||||
with pytest.raises(exceptions.InvalidSignature):
|
with pytest.raises(exceptions.InvalidSignature):
|
||||||
b.validate_transaction(next_tx)
|
b.validate_transaction(next_tx)
|
||||||
assert b.is_valid_transaction(next_tx) == False
|
assert b.is_valid_transaction(next_tx) == False
|
||||||
|
|
||||||
|
def test_default_threshold_signatures_for_multiple_owners(self, b):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_subcondition_from_vk(self):
|
||||||
|
pass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user