Skip to content

Commit

Permalink
Merge pull request #5 from asonnino/master
Browse files Browse the repository at this point in the history
merge latest
  • Loading branch information
musalbas authored Jun 26, 2017
2 parents 7b1bece + f4583d9 commit 2717319
Show file tree
Hide file tree
Showing 17 changed files with 1,275 additions and 568 deletions.
104 changes: 104 additions & 0 deletions chainspacecontract/chainspacecontract/examples/bank_authenticated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""A smart contract that implements a simple, authenticated bank."""

#############################################################################################
# imports
#############################################################################################
from chainspacecontract import ChainspaceContract
from hashlib import sha256
from petlib.ec import EcGroup, EcPt
from petlib.ecdsa import do_ecdsa_sign, do_ecdsa_verify
from petlib.bn import Bn
from binascii import hexlify, unhexlify
from json import dumps

contract = ChainspaceContract('bank_authenticated')


#############################################################################################
# init
#############################################################################################
@contract.method('init')
def init():
return {
'outputs': (
{'name': 'alice', 'balance': 10},
{'name': 'bob', 'balance': 10}
)
}


#############################################################################################
# contract method
#
# NOTE: all extra parameters (like secret_key) will be ingored by the framwork; they will
# not be sent anywhere
#############################################################################################
@contract.method('auth_transfer')
def auth_transfer(inputs, reference_inputs, parameters, sk):
from_account = inputs[0]
to_account = inputs[1]

# compute outputs
from_account['balance'] -= parameters['amount']
to_account['balance'] += parameters['amount']

# hash message to sign
hasher = sha256()
hasher.update(dumps(inputs).encode('utf8'))
hasher.update(dumps(reference_inputs).encode('utf8'))
hasher.update(dumps({'amount' : parameters["amount"]}).encode('utf8'))

# sign message
G = EcGroup()
priv = Bn.from_hex(sk)
g = G.generator()
sig = do_ecdsa_sign(G, priv, hasher.digest())

# return
return {
'outputs': (from_account, to_account),
'extra_parameters' : {
'signature' : {'r': Bn.hex(sig[0]), 's': Bn.hex(sig[1])}
}
}


#############################################################################################
# checker
#############################################################################################
@contract.checker('auth_transfer')
def auth_transfer_checker(inputs, reference_inputs, parameters, outputs, returns):

# load public key
G = EcGroup()
pub = EcPt.from_binary(
unhexlify('03951d4b7141e99fe1e9d568ef0489db884e37615a6e5968665485a973'),
G
)

# hash message to verify signature
hasher = sha256()
hasher.update(dumps(inputs).encode('utf8'))
hasher.update(dumps(reference_inputs).encode('utf8'))
hasher.update(dumps({'amount' : parameters["amount"]}).encode('utf8'))

# recompose signed digest
sig = (
Bn.from_hex(parameters['signature']['r']),
Bn.from_hex(parameters['signature']['s'])
)

# verify signature
return do_ecdsa_verify(G, pub, sig, hasher.digest())



#############################################################################################
# main
#############################################################################################
if __name__ == '__main__':
contract.run()



#############################################################################################
43 changes: 43 additions & 0 deletions chainspacecontract/chainspacecontract/test/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
from chainspacecontract.examples.increment import contract as increment_contract
from chainspacecontract.examples.increment_with_custom_checker import contract as increment_with_custom_checker_contract
from chainspacecontract.examples.bank_unauthenticated import contract as bank_unauthenticated_contract
from chainspacecontract.examples.bank_authenticated import contract as bank_authenticated_contract
from chainspacecontract.examples import bank_authenticated


class TestIncrement(unittest.TestCase):
"""
def test_increment_checker_service(self):
checker_service_process = Process(target=increment_contract.run_checker_service)
checker_service_process.start()
Expand Down Expand Up @@ -94,6 +97,46 @@ def test_bank_unauthenticated_checker_service(self):
checker_service_process.terminate()
checker_service_process.join()
"""



#############################################################################################
# test an authenticated bank transfer
#############################################################################################
def test_bank_authenticated_checker_service(self):
checker_service_process = Process(target=bank_authenticated_contract.run_checker_service)
checker_service_process.start()
time.sleep(0.1)

# NOTE: export public key
"""
G = EcGroup()
g = G.generator()
priv = G.order().random()
pub = priv * g
byte_string = pub.export()
print hexlify(byte_string)
print EcPt.from_binary(byte_string, G) == pub
"""

response = requests.post('http://127.0.0.1:5000/auth_transfer',
json=bank_authenticated.auth_transfer(
[{'name': 'alice', 'balance': 10}, {'name': 'bob', 'balance': 10}],
None,
{'amount': 3},
'83C72CF7E1BA9F120C5A45135A0FE3DA59D7771BB9C670B63134A8B0'
)
)
response_json = response.json()
self.assertTrue(response_json['success'])

checker_service_process.terminate()
checker_service_process.join()





if __name__ == '__main__':
unittest.main()
40 changes: 32 additions & 8 deletions examples/bank_transfer_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,36 @@ def ccheck(V, msg):
# checker
# -------------------------------------------------------------------------------
def checker_function(T):
# check transfer's format
ccheck(len(T["referenceInputs"]) == 0, "Expect no references")



if (T[u"contractID"] == 102):

parameter = loads(T[u"parameters"][0])
output = loads(T[u"outputs"][0])

if int(parameter["token"]) * 2 == int(output):
return {"status": "OK"}
else:
raise Exception("hey!")


if (T[u"contractID"] != 10):
return {"status": "OK"}




# retrieve inputs
from_account, to_account = T[u"inputs"]
amount = T[u"parameters"]["amount"]
from_account_new, to_account_new = T[u"outputs"]
from_account = loads(T[u"inputs"][0])
to_account = loads(T[u"inputs"][1])
amount = loads(T[u"parameters"][0])["amount"]
from_account_new = loads(T[u"outputs"][0])
to_account_new = loads(T[u"outputs"][1])


# check transfer's format
ccheck(len(T["referenceInputs"]) == 0, "Expect no references")

# check positive amount
ccheck(0 < amount, "Transfer should be positive")
Expand All @@ -45,6 +68,7 @@ def checker_function(T):
ccheck(from_account["amount"] - amount == from_account_new["amount"], "Incorrect new balance")
ccheck(to_account["amount"] + amount == to_account_new["amount"], "Incorrect new balance")


# return
return {"status": "OK"}

Expand All @@ -66,11 +90,11 @@ def check():
try:
return dumps(checker_function(loads(request.data)))
except KeyError as e:
return dumps({"status": "Error", "message": e.args})
return dumps({"status": "ERROR", "message": str(e)})
except Exception as e:
return dumps({"status": "Error", "message": e.args})
return dumps({"status": "ERROR", "message": str(e)})
else:
return dumps({"status": "Error", "message":"Use POST method."})
return dumps({"status": "ERROR", "message":"Use POST method."})


##################################################################################
Expand Down
Loading

0 comments on commit 2717319

Please sign in to comment.