def build_transaction(wallet, contract: str, function: str, kwargs: dict, nonce: int, processor: str, stamps: int): payload = { 'contract': contract, 'function': function, 'kwargs': kwargs, 'nonce': nonce, 'processor': processor, 'sender': wallet.verifying_key, 'stamps_supplied': stamps, } payload = format_dictionary( payload) # Sort payload in case kwargs unsorted assert check_format( payload, rules.TRANSACTION_PAYLOAD_RULES), 'Invalid payload provided!' true_payload = encode(decode(encode(payload))) signature = wallet.sign(true_payload) metadata = {'signature': signature, 'timestamp': int(time.time())} tx = {'payload': payload, 'metadata': metadata} return encode(format_dictionary(tx))
def insert_block(self, b: dict): self.validate_block(b) self.cursor.execute('insert into blocks values (?, ?)', (b['hash'], b['index'])) for transaction in b['transactions']: args = json.dumps(transaction['input']['payload']['arguments']) self.cursor.execute('insert into transaction_inputs values (?, ?, ?, ?, ?, ?, ?, ?)', (transaction['hash'], b['hash'], transaction['input']['index'], transaction['input']['sender'], transaction['input']['signature'], transaction['input']['payload']['contract'], transaction['input']['payload']['function'], args)) updates = json.dumps(transaction['output']['updates']) self.cursor.execute('insert into transaction_outputs values (?, ?, ?, ?, ?, ?)', (transaction['hash'], b['hash'], transaction['input']['index'], transaction['output']['status'], updates, encode(transaction['output']['result']))) self.conn.commit()
def set(self, key: str, value): k = key.encode() if value is None: self.__delitem__(key) else: v = encode(value).encode() self.db[k] = v
def block_from_subblocks(subblocks, previous_hash: str, block_num: int) -> dict: block_hasher = hashlib.sha3_256() block_hasher.update(bytes.fromhex(previous_hash)) deserialized_subblocks = [] for subblock in subblocks: if subblock is None: continue sb = format_dictionary(subblock) deserialized_subblocks.append(sb) sb_without_sigs = deepcopy(sb) if sb_without_sigs.get('signatures') is not None: del sb_without_sigs['signatures'] encoded_sb = encode(sb_without_sigs) block_hasher.update(encoded_sb.encode()) block = { 'hash': block_hasher.digest().hex(), 'number': block_num, 'previous': previous_hash, 'subblocks': deserialized_subblocks } return block
def __init__(self, sender, contract: str, function: str, kwargs: dict, stamps: int, processor: bytes, nonce: int): # Stores variables in self for convenience self.sender = sender self.stamps = stamps self.processor = processor self.contract = contract self.function = function self.nonce = nonce self.kwargs = kwargs # Serializes all that it can on init self.struct = transaction_capnp.NewTransaction.new_message() self.payload = transaction_capnp.NewTransactionPayload.new_message() self.payload.sender = self.sender self.payload.processor = self.processor self.payload.stampsSupplied = self.stamps self.payload.contractName = self.contract self.payload.functionName = self.function self.payload.nonce = self.nonce self.payload.kwargs = encode(kwargs) self.payload_bytes = self.payload.to_bytes_packed() self.signature = None self.tx_signed = False
async def secure_send(msg: dict, service, wallet: Wallet, vk, ip, ctx: zmq.asyncio.Context, linger=500, cert_dir=DEFAULT_DIR): #if wallet.verifying_key == vk: # return socket = ctx.socket(zmq.DEALER) socket.setsockopt(zmq.LINGER, linger) socket.setsockopt(zmq.TCP_KEEPALIVE, 1) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk filename = str(cert_dir / f'{vk}.key') if not os.path.exists(filename): return None server_pub, _ = load_certificate(filename) socket.curve_serverkey = server_pub try: socket.connect(ip) except ZMQBaseError: socket.close() return None message = build_message(service=service, message=msg) payload = encode(message).encode() await socket.send(payload, flags=zmq.NOBLOCK) socket.close()
def test_merkle_leaf_complex_objects_works(self): tx_1_raw = b'{"hash": "503fa157e4d990f78f2b032731dffb398f6ff642b6bbc305817e24dd42b33402", "result": "None", "stamps_used": 198, "state": [{"key": "rewards.S:current_votes:masternodes", "value": 20}, {"key": "rewards.S:current_votes:delegates", "value": 20}, {"key": "rewards.S:current_votes:blackhole", "value": 5}, {"key": "rewards.S:current_votes:foundation", "value": 5}, {"key": "rewards.S:current_votes:developer", "value": 450}, {"key": "rewards.S:has_voted:b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "value": true}, {"key": "rewards.S:vote_count", "value": 5}, {"key": "rewards.S:value", "value": [{"__fixed__": "0.04"}, {"__fixed__": "0.04"}, {"__fixed__": "0.01"}, {"__fixed__": "0.01"}, {"__fixed__": "0.9"}]}, {"key": "rewards.S:election_start", "value": null}, {"key": "currency.balances:b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "value": {"__fixed__": "535.30200000"}}], "status": 0, "transaction": {"metadata": {"signature": "ceb4630c8be71f2c0c1e059790609fafa6ed948b7fceb4bb44c36dca46848fac8d55fe27f539036fee5bda6d772fff852b622393eab593aa6dce67f93f7d8f08", "timestamp": 1601411941}, "payload": {"contract": "election_house", "function": "vote", "kwargs": {"policy": "rewards", "value": [4, 4, 1, 1, 90]}, "nonce": 3, "processor": "5b09493df6c18d17cc883ebce54fcb1f5afbd507533417fe32c006009a9c3c4a", "sender": "b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "stamps_supplied": 999}}}' tx_1 = decode(tx_1_raw) txs = [encode(tx).encode() for tx in [tx_1]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc = { 'subblock': 1, 'transactions': [tx_1], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() self.assertTrue(s.sbc_is_valid(sbc, 1))
async def handle_msg(self, _id, msg): # Try to deserialize the message and run it through the rpc service try: json_command = decode(msg.decode()) self.log.info('Received command: {}'.format(json_command)) result = self.interface.process_json_rpc_command(json_command) # If this fails, just set the result to None except Exception as e: self.log.info('EXCEPTION!! -> ', str(e)) result = None # Try to send the message now. This persists if the socket fails. sent = False while not sent: try: msg = encode(result).encode() self.log.info('result sent: {}, {}'.format(msg, result)) await self.socket.send_multipart([_id, msg]) sent = True except zmq.error.ZMQError: self.log.info('zmq error: {}'.format(zmq.error.ZMQError)) self.socket.close() self.setup_socket()
def test_good_sbc_returns_true(self): tx_1 = { 'something': 'who_cares' } tx_2 = { 'something_else': 'who_cares' } txs = [encode(tx).encode() for tx in [tx_1, tx_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc = { 'subblock': 1, 'transactions': [tx_1, tx_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() self.assertTrue(s.sbc_is_valid(sbc, 1))
def set(self, key, value): if value is None: self.__delitem__(key) else: v = encode(value) with self.db_writer.begin(write=True) as tx: tx.put(key.encode(), v.encode())
def test_sign_works_properly(self): w = Wallet() tx = build_transaction( wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' } ) decoded = decode(tx) res = verify( w.verifying_key, encode(decoded['payload']), decoded['metadata']['signature'] ) self.assertTrue(res)
def check_tx_formatting(tx: dict, expected_processor: str): if not check_format(tx, rules.TRANSACTION_RULES): raise TransactionFormattingError if not wallet.verify(tx['payload']['sender'], encode(tx['payload']), tx['metadata']['signature']): raise TransactionSignatureInvalid if tx['payload']['processor'] != expected_processor: raise TransactionProcessorInvalid
def set(self, key, value): if value is None: self.__delitem__(key) else: v = encode(value) filename = self._key_to_file(key) os.makedirs(filename.parents[0], exist_ok=True) with open(filename, 'w') as f: f.write(v)
def set(self, key, value): if value is None: self.__delitem__(key) else: v = encode(value) self.db.update_one( {'_id': key}, {'$set': { 'v': v }}, upsert=True, )
async def request(msg): msg = encode(msg).encode() socket = self.ctx.socket(zmq.DEALER) socket.connect('ipc:///tmp/router') await socket.send(msg) resp = await socket.recv() resp = decode(resp) return resp
def test_environment_variables_are_working_as_they_should(self): test_contract = ''' a = Variable() b = Variable() c = Variable() @export def capture(): a.set(block_hash) b.set(block_num) c.set(now) ''' self.client.submit(test_contract, name='testing') tx = TransactionBuilder(sender='stu', contract='testing', function='capture', kwargs={}, stamps=100_000, processor=b'\x00' * 32, nonce=0) tx.sign(Wallet().signing_key()) tx.serialize() tx_batch = transaction_list_to_transaction_batch([tx.struct], wallet=Wallet()) w = Wallet() b = Delegate(socket_base='tcp://127.0.0.1', wallet=w, ctx=self.ctx) now = Datetime._from_datetime( datetime.utcfromtimestamp(tx_batch.timestamp)) results = b.execute_work([(tx_batch.timestamp, tx_batch)]) tx = results[0].transactions[0] a, b, c = tx.state self.assertEqual(a.key, b'testing.a') self.assertEqual( a.value, b'"0000000000000000000000000000000000000000000000000000000000000000"' ) self.assertEqual(b.key, b'testing.b') self.assertEqual(b.value, b'0') self.assertEqual(c.key, b'testing.c') self.assertEqual(c.value, encode(now).encode())
def store_txs(self, txs: list): # Calculate the new hash, index, and return the results after storing block_hash = hash_bytes(encode(txs).encode()) index = self.height() + 1 block_dict = { 'hash': block_hash, 'index': index, 'transactions': txs } self.insert_block(block_dict) return block_dict
def verify_proof(proof, pepper): # Proofs expire after a minute if not primatives.check_format(proof, rules.PROOF_MESSAGE_RULES): return False if int(time.time()) - proof['timestamp'] > PROOF_EXPIRY: return False message = [pepper, proof['ip'], proof['timestamp']] message_bytes = encode(message).encode() h = hashlib.sha3_256() h.update(message_bytes) return verify(proof['vk'], h.digest().hex(), proof['signature'])
def verify_tx_signature(tx: dict): tx_payload = encode(tx['payload']) tx_payload_bytes = tx_payload.encode() signature = bytes.fromhex(tx['signature']) pk = bytes.fromhex(tx['sender']) vk = ecdsa.VerifyingKey.from_string(pk, curve=ecdsa.NIST256p, hashfunc=hashlib.sha256) try: vk.verify(signature, tx_payload_bytes) except ecdsa.BadSignatureError: return False return True
def execute_work(self, driver, work, wallet, previous_block_hash, current_height=0, stamp_cost=20000, parallelism=4): # Assume single threaded, single process for now. subblocks = [] i = 0 for tx_batch in work: results = self.execute_tx_batch(driver=driver, batch=tx_batch, timestamp=tx_batch['timestamp'], input_hash=tx_batch['input_hash'], stamp_cost=stamp_cost, bhash=previous_block_hash, num=current_height) if len(results) > 0: merkle = merklize([encode(r).encode() for r in results]) proof = wallet.sign(merkle[0]) else: merkle = merklize([bytes.fromhex(tx_batch['input_hash'])]) proof = wallet.sign(tx_batch['input_hash']) merkle_tree = {'leaves': merkle, 'signature': proof} sbc = { 'input_hash': tx_batch['input_hash'], 'transactions': results, 'merkle_tree': merkle_tree, 'signer': wallet.verifying_key, 'subblock': i % parallelism, 'previous': previous_block_hash } sbc = format_dictionary(sbc) subblocks.append(sbc) i += 1 return subblocks
def make_tx(key: ecdsa.SigningKey, contract, func, arguments={}): tx = { 'sender': key.get_verifying_key().to_string().hex(), 'signature': None, 'payload': { 'contract': contract, 'function': func, 'arguments': arguments } } message = encode(tx['payload']).encode() signature = key.sign_deterministic(message, hashlib.sha256)[:64] tx['signature'] = signature.hex() return tx
async def secure_request(msg: dict, service: str, wallet: Wallet, vk: str, ip: str, ctx: zmq.asyncio.Context, linger=500, timeout=1000, cert_dir=DEFAULT_DIR): #if wallet.verifying_key == vk: # return socket = ctx.socket(zmq.DEALER) socket.setsockopt(zmq.LINGER, linger) socket.setsockopt(zmq.TCP_KEEPALIVE, 1) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk filename = str(cert_dir / f'{vk}.key') if not os.path.exists(filename): return None server_pub, _ = load_certificate(filename) socket.curve_serverkey = server_pub try: socket.connect(ip) except ZMQBaseError: logger.debug(f'Could not connect to {ip}') socket.close() return None message = build_message(service=service, message=msg) payload = encode(message).encode() await socket.send(payload) event = await socket.poll(timeout=timeout, flags=zmq.POLLIN) msg = None if event: #logger.debug(f'Message received on {ip}') response = await socket.recv() msg = decode(response) socket.close() return msg
def sbc_is_valid(self, sbc, sb_idx=0): if sbc['subblock'] != sb_idx: self.log.error(f'Subblock Contender[{sb_idx}] is out order.') return False # Make sure signer is in the delegates if len(sbc['transactions']) == 0: message = sbc['input_hash'] else: message = sbc['merkle_tree']['leaves'][0] valid_sig = verify(vk=sbc['signer'], msg=message, signature=sbc['merkle_tree']['signature']) if not valid_sig: self.log.error( f'Subblock Contender[{sb_idx}] from {sbc["signer"][:8]} has an invalid signature.' ) return False if len(sbc['merkle_tree']['leaves']) > 0: txs = [encode(tx).encode() for tx in sbc['transactions']] expected_tree = merklize(txs) # Missing leaves, etc if len(sbc['merkle_tree']['leaves']) != len(expected_tree) and len( sbc['transactions']) > 0: self.log.error('Merkle Tree Len mismatch') return False for i in range(len(expected_tree)): if expected_tree[i] != sbc['merkle_tree']['leaves'][i]: self.log.error( f'Subblock Contender[{sbc["subblock"]}] from {sbc["signer"][:8]} has an Merkle tree proof.' ) self.log.error(expected_tree[i]) self.log.error(txs[i]) return False self.log.info( f'Subblock[{sbc["subblock"]}] from {sbc["signer"][:8]} is valid.') return True
def create_proof(self): now = int(time.time()) message = [self.pepper, self.ip_string, now] message_bytes = encode(message).encode() h = hashlib.sha3_256() h.update(message_bytes) signature = self.wallet.sign(h.hexdigest()) proof = { 'signature': signature, 'vk': self.wallet.verifying_key, 'timestamp': now, 'ip': self.ip_string } return proof
async def get_variable(request, contract, variable): contract_code = client.raw_driver.get_contract(contract) if contract_code is None: return json({'error': '{} does not exist'.format(contract)}, status=404) key = request.args.get('key') if key is None: args = [] else: args = [key] k = client.raw_driver.make_key(contract, variable, args) response = encode(client.raw_driver.get(k)) if response is None: return json({'value': None}, status=404) else: return json({'value': response}, status=200)
def test_make_tx(self): # nakey = nacl.signing.SigningKey.generate() # # pk = nakey.verify_key.encode().hex() nakey = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p) pk = nakey.get_verifying_key().to_string().hex() tx = { 'sender': pk, 'signature': None, 'payload': { 'contract': 'submission', 'function': 'submit_contract', 'arguments': { 'code': 'test', 'name': 'stu_bucks' } } } message = encode(tx['payload']).encode() sig = nakey.sign_deterministic(message, hashfunc=hashlib.sha256).hex() tx['signature'] = sig made_tx = make_tx(nakey, contract='submission', func='submit_contract', arguments={ 'code': 'test', 'name': 'stu_bucks' }) self.assertEqual(made_tx, tx)
def test_process_message_good_and_bad_sbc_doesnt_pass_to_q(self): ### GOOD SBC tx_1_1 = { 'something': 'who_cares' } tx_1_2 = { 'something_else': 'who_cares' } txs = [encode(tx).encode() for tx in [tx_1_1, tx_1_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc_1 = { 'subblock': 0, 'transactions': [tx_1_1, tx_1_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } ### BAD SBC tx_2_1 = { 'something': 'who_cares2' } tx_2_2 = { 'something_else': 'who_cares2' } txs = [encode(tx).encode() for tx in [tx_2_1, tx_2_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something2' signature = w.sign(expected_tree[0]) expected_tree[1] = 'crap' sbc_2 = { 'subblock': 1, 'transactions': [tx_2_1, tx_2_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() loop = asyncio.get_event_loop() if loop.is_closed(): loop = asyncio.new_event_loop() loop.run_until_complete(s.process_message([sbc_1, sbc_2])) self.assertEqual(s.q, [])
def tx_hash_from_tx(tx): h = hashlib.sha3_256() tx_dict = format_dictionary(tx) encoded_tx = encode(tx_dict).encode() h.update(encoded_tx) return h.hexdigest()
def test_bigint_encode(self): si = MONGO_MIN_INT - 1 bi = MONGO_MAX_INT + 1 self.assertEqual('{"__big_int__":"' + str(bi) + '"}', encode(bi)) self.assertEqual('{"__big_int__":"' + str(si) + '"}', encode(si))
def test_int_to_bytes(self): i = 1000 b = '1000' self.assertEqual(encode(i), b)