def _finalizeTx(self, tx): if hasattr(self, "_privateKey"): # set publicKey manualy dict.__setitem__(tx, "senderPublicKey", self.publicKey) tx["nonce"] = self.nonce + 1 tx["senderId"] = self.address if tx["type"] not in [0, 8]: tx["recipientId"] = self.address tx.fee = self._fee tx.feeIncluded = self._fee_included tx["signature"] = crypto.getSignatureFromBytes( crypto.getBytes(tx), self._privateKey) if hasattr(self, "_secondPrivateKey"): tx["signSignature"] = \ crypto.getSignatureFromBytes( crypto.getBytes(tx), self._secondPrivateKey ) tx["id"] = crypto.getIdFromBytes( crypto.getBytes(tx, exclude_multi_sig=False)) return tx
def append(network, *transactions): response = {} for tx in transactions: idx = transactions.index(tx) + 1 try: if not isinstance(tx, dposlib.core.Transaction): tx = dposlib.core.Transaction(tx, ignore_bad_fields=True) signatures = tx.get("signatures", []) if len(signatures) == 0: response["errors"] = response.get("errors", []) + [ "transaction #%d rejected (one signature is mandatory)" % idx ] elif tx.get("nonce", 1) <= tx._nonce: response["errors"] = response.get("errors", []) + [ "transaction #%d rejected (bad nonce)" % idx ] else: checks = [] publicKeys = \ tx["asset"].get("multiSignature", {}).get( "publicKeys", [] ) \ if tx["type"] == 4 else tx._multisignature.get( "publicKeys", [] ) serialized = crypto.getBytes(tx, exclude_sig=True, exclude_second_sig=True, exclude_multi_sig=True) for sig in signatures: pk_idx, sig = int(sig[0:2], 16), sig[2:] checks.append( crypto.verifySignatureFromBytes( serialized, publicKeys[pk_idx], sig)) if False in checks: response["errors"] = response.get("errors", []) + [ "transaction #%d rejected (bad signature)" % idx ] else: id_ = dump(network, tx) response["success"] = response.get("success", []) + [ "transaction #%d successfully posted" % (idx) ] response["ids"] = response.get("ids", []) + [id_] except Exception as error: response["errors"] = response.get("errors", []) + [ "transaction #%d rejected (%r)" % (idx, error) ] return json.dumps(response), 201
def identify(tx): """ Identify a transaction. Args: tx (:class:`dict` or :class:`dposlib.blockchain.Transaction`): transaction to identify Returns: :class:`str`: transaction id used by registries """ return crypto.getIdFromBytes( crypto.getBytes(tx, exclude_sig=True, exclude_multi_sig=True, exclude_second_sig=True))
def remoteSignWithKey(network, ms_publicKey, txid, privateKey): publicKey = hexlify( secp256k1.PublicKey.from_seed(unhexlify(privateKey)).encode() ) wallet = getWallet(network, ms_publicKey).get("data", {}) if txid in wallet: options = {} if wallet[txid]["type"] == 4 else { "exclude_sig": True, "exclude_multi_sig": True, "exclude_second_sig": True } return putSignature( network, ms_publicKey, txid, publicKey, crypto.getSignatureFromBytes( crypto.getBytes(wallet[txid], **options), privateKey ) ) else: raise Exception("%s transaction not found" % txid)
def getSerial(network, ms_publicKey, txid): """ ``GET /multisignature/{network}/{ms_publicKey}/{txid}/serial`` endpoint. Return specific pending transaction serial from a specific public key. """ if network != getattr(rest.cfg, "network", False): rest.use(network) if flask.request.method != "GET": return json.dumps({ "success": False, "API error": "GET request only allowed here" }) tx = load(network, ms_publicKey, txid) if tx: return json.dumps({ "success": True, "data": hexlify(crypto.getBytes(tx)) }), 200 else: return json.dumps({"success": False})
def putSignature(network, ms_publicKey): """ ``PUT /multisignature/{network}/{ms_publicKey}/put`` endpoint. Add signature to a pending transaction:: data = { "info": { "id": pending_transaction_id, "signature": signature, "publicKey": associated_public_key } [ + { "fee": optional_fee_value_to_use } ] } """ if network != getattr(rest.cfg, "network", False): rest.use(network) if flask.request.method == "PUT": data = json.loads(flask.request.data) if "info" not in data: return json.dumps({"error": "no info"}) txid = data["info"]["id"] tx = load(network, ms_publicKey, txid) if not tx: return json.dumps({ "success": False, "API error": "transaction %s not found" % txid }) tx = dposlib.core.Transaction(tx) publicKey = data["info"]["publicKey"] signature = data["info"]["signature"] publicKeys = \ tx["asset"].get("multiSignature", {}).get("publicKeys", []) \ if tx["type"] == 4 else tx._multisignature.get("publicKeys", []) if publicKey not in (publicKeys + [tx._secondPublicKey, tx._publicKey]): return json.dumps({ "success": False, "API error": "public key %s not allowed here" % publicKey }) # sign type 4 # signatures field is full if tx.type == 4 and len(tx.get("signatures", [])) == len(publicKeys): if publicKey == tx._publicKey: # and signature matches type 4 issuer's public key if crypto.verifySignatureFromBytes(crypto.getBytes(tx), publicKey, signature): tx.signature = signature dump(network, tx) if tx._secondPublicKey is None: # if no need to signSign --> broadcast tx and return # network response return broadcast(network, tx) else: return json.dumps({ "success": True, "message": "issuer signature added" }) else: return json.dumps({ "success": False, "API error": "signature does not match issuer key" }) # signSign elif publicKey == tx._secondPublicKey: # if tx already signed by issuer if "signature" in tx: # and signature matches type 4 issuer 's second public key if crypto.verifySignatureFromBytes(crypto.getBytes(tx), publicKey, signature): # signSign, broadcast and return network response tx.signSignature = signature return broadcast(network, tx) else: return json.dumps({ "success": False, "API error": "signature does not match issuer " "second key" }) else: return json.dumps({ "success": False, "API error": "transaction have to be signed first" }) # verify owner signature check = crypto.verifySignatureFromBytes( crypto.getBytes(tx, exclude_sig=True, exclude_multi_sig=True, exclude_second_sig=True), publicKey, signature) # if signature matches if check and publicKey in publicKeys: index = publicKeys.index(publicKey) # set is used here to remove doubles tx["signatures"] = list( set(tx.get("signatures", []) + ["%02x" % index + signature])) if tx["type"] != 4 and \ len(tx.get("signatures", [])) >= tx._multisignature["min"]: return broadcast(network, tx) else: dump(network, tx) return json.dumps({ "success": True, "message": "signature added to transaction", }), 201 else: return json.dumps({ "success": False, "API error": "signature not accepted" }) else: return json.dumps({ "success": False, "API error": "PUT request only allowed here" })