def encrypt(privkey, passphrase): """ BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey. :param privkey: Private key :type privkey: Base58 :param str passphrase: UTF-8 encoded passphrase for encryption :return: BIP0038 non-ec-multiply encrypted wif key :rtype: Base58 """ privkeyhex = repr(privkey) # hex addr = format(privkey.uncompressed.address, "BTC") a = compat_bytes(addr, 'ascii') salt = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4] if SCRYPT_MODULE == "scrypt": if sys.version >= '3.0.0': key = scrypt.hash(passphrase, salt, 16384, 8, 8) else: key = scrypt.hash(str(passphrase), str(salt), 16384, 8, 8) elif SCRYPT_MODULE == "pylibscrypt": key = scrypt.scrypt(compat_bytes(passphrase, "utf-8"), salt, 16384, 8, 8) else: raise ValueError("No scrypt module loaded") (derived_half1, derived_half2) = (key[:32], key[32:]) aes = AES.new(derived_half2) encrypted_half1 = _encrypt_xor(privkeyhex[:32], derived_half1[:16], aes) encrypted_half2 = _encrypt_xor(privkeyhex[32:], derived_half1[16:], aes) " flag byte is forced 0xc0 because Graphene only uses compressed keys " payload = (b'\x01' + b'\x42' + b'\xc0' + salt + encrypted_half1 + encrypted_half2) " Checksum " checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] privatekey = hexlify(payload + checksum).decode('ascii') return Base58(privatekey)
def __bytes__(self): if not self.data: return compat_bytes(Bool(0)) else: return compat_bytes(Bool(1)) + compat_bytes( self.data) if compat_bytes(self.data) else compat_bytes( Bool(0))
def varint(n): """ Varint encoding """ data = b'' while n >= 0x80: data += compat_bytes([(n & 0x7f) | 0x80]) n >>= 7 data += compat_bytes([n]) return data
def __bytes__(self): if self.data is None: return bytes() b = b"" for name, value in self.data.items(): if isinstance(value, str): b += compat_bytes(value, 'utf-8') else: b += compat_bytes(value) return b
def compressed(self): """ Derive compressed public key """ order = ecdsa.SECP256k1.generator.order() p = ecdsa.VerifyingKey.from_string(compat_bytes(self), curve=ecdsa.SECP256k1).pubkey.point x_str = ecdsa.util.number_to_string(p.x(), order) # y_str = ecdsa.util.number_to_string(p.y(), order) compressed = hexlify( compat_bytes(compat_chr(2 + (p.y() & 1)), 'ascii') + x_str).decode('ascii') return (compressed)
def verify(self, pubkeys=[], chain=None): if not chain: raise ValueError("Chain needs to be provided!") chain_params = self.getChainParams(chain) self.deriveDigest(chain) signatures = self.data["signatures"].data pubKeysFound = [] for signature in signatures: sig = compat_bytes(signature)[1:] if sys.version >= '3.0': recoverParameter = (compat_bytes(signature)[0] ) - 4 - 27 # recover parameter only else: recoverParameter = ord((compat_bytes(signature)[0])) - 4 - 27 if USE_SECP256K1: ALL_FLAGS = secp256k1.lib.SECP256K1_CONTEXT_VERIFY | \ secp256k1.lib.SECP256K1_CONTEXT_SIGN # Placeholder pub = secp256k1.PublicKey(flags=ALL_FLAGS) # Recover raw signature sig = pub.ecdsa_recoverable_deserialize(sig, recoverParameter) # Recover PublicKey verifyPub = secp256k1.PublicKey( pub.ecdsa_recover(compat_bytes(self.message), sig)) # Convert recoverable sig to normal sig normalSig = verifyPub.ecdsa_recoverable_convert(sig) # Verify verifyPub.ecdsa_verify(compat_bytes(self.message), normalSig) phex = hexlify( verifyPub.serialize(compressed=True)).decode('ascii') pubKeysFound.append(phex) else: p = self.recover_public_key(self.digest, sig, recoverParameter) # Will throw an exception of not valid p.verify_digest(sig, self.digest, sigdecode=ecdsa.util.sigdecode_string) phex = hexlify(self.compressedPubkey(p)).decode('ascii') pubKeysFound.append(phex) for pubkey in pubkeys: if not isinstance(pubkey, PublicKey): raise Exception("Pubkeys must be array of 'PublicKey'") k = pubkey.unCompressed()[2:] if k not in pubKeysFound and repr(pubkey) not in pubKeysFound: k = PublicKey(PublicKey(k).compressed()) f = format(k, chain_params["prefix"]) raise Exception("Signature for %s missing!" % f) return pubKeysFound
def decrypt(encrypted_privkey, passphrase): """BIP0038 non-ec-multiply decryption. Returns WIF privkey. :param Base58 encrypted_privkey: Private key :param str passphrase: UTF-8 encoded passphrase for decryption :return: BIP0038 non-ec-multiply decrypted key :rtype: Base58 :raises SaltException: if checksum verification failed (e.g. wrong password) """ d = unhexlify(base58decode(encrypted_privkey)) d = d[2:] # remove trailing 0x01 and 0x42 flagbyte = d[0:1] # get flag byte d = d[1:] # get payload assert flagbyte == b'\xc0', "Flagbyte has to be 0xc0" salt = d[0:4] d = d[4:-4] if SCRYPT_MODULE == "scrypt": if sys.version >= '3.0.0': key = scrypt.hash(passphrase, salt, 16384, 8, 8) else: key = scrypt.hash(str(passphrase), str(salt), 16384, 8, 8) elif SCRYPT_MODULE == "pylibscrypt": key = scrypt.scrypt(compat_bytes(passphrase, "utf-8"), salt, 16384, 8, 8) else: raise ValueError("No scrypt module loaded") derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] encryptedhalf1 = d[0:16] encryptedhalf2 = d[16:32] aes = AES.new(derivedhalf2) decryptedhalf2 = aes.decrypt(encryptedhalf2) decryptedhalf1 = aes.decrypt(encryptedhalf1) privraw = decryptedhalf1 + decryptedhalf2 privraw = ('%064x' % (int(hexlify(privraw), 16) ^ int(hexlify(derivedhalf1), 16))) wif = Base58(privraw) """ Verify Salt """ privkey = PrivateKey(format(wif, "wif")) addr = format(privkey.uncompressed.address, "BTC") a = compat_bytes(addr, 'ascii') saltverify = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4] if saltverify != salt: raise SaltException( 'checksum verification failed! Password may be incorrect.') return wif
def test_Comment(self): op = operations.Comment( **{ "parent_author": "foobara", "parent_permlink": "foobarb", "author": "foobarc", "permlink": "foobard", "title": "foobare", "body": "foobarf", "json_metadata": { "foo": "bar" } }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c80457010107666f6f6261726107666f6f626172620" "7666f6f6261726307666f6f6261726407666f6f6261726507666f6f62" "6172660e7b22666f6f223a2022626172227d00011f34a882f3b06894c" "29f52e06b8a28187b84b817c0e40f124859970b32511a778736d682f2" "4d3a6e6da124b340668d25bbcf85ffa23ca622b307ffe10cf182bb82") self.assertEqual(compare[:-130], tx_wire[:-130])
def compareConstructedTX(self): # def test_online(self): # self.maxDiff = None op = operations.CommentOptions( **{ "author": "Jared Rice Sr.", "permlink": "dpaypy", "max_accepted_payout": "1000000.000 BBD", "percent_dpay_dollars": 10000, "allow_votes": True, "allow_curation_rewards": True, "extensions": [] }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") # todo rpc = self.dpay.commit.wallet compare = rpc.serialize_transaction(tx.json()) self.assertEqual(compare[:-130], tx_wire[:-130])
def test_witness_update(self): op = operations.WitnessUpdate( **{ "owner": "jared", "url": "foooobar", "block_signing_key": "DWB6zLNtyFVToBsBZDsgMhgjpwysYVbsQD6YhP3kRkQhANUB4w7Qp", "props": { "account_creation_fee": "10.000 BEX", "maximum_block_size": 1111111, "bbd_interest_rate": 1000 }, "fee": "10.000 BEX", }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c80457010b057865726f6308666f6f6f6f6261" "720314aa202c9158990b3ec51a1aa49b2ab5d300c97b391df3be" "b34bb74f3c62699e102700000000000003535445454d000047f4" "1000e803102700000000000003535445454d00000001206adca4" "bebc872e8d792caeb3b729e9a5e8af90c07ab3f744fb4d0f19d5" "7b3bec32f5a43f5acdfc065f0227e45e599745c46e41c023d69f" "b9f2405478badadb4c") self.assertEqual(compare[:-130], tx_wire[:-130])
def get_private(self): """ Derive private key from the brain key and the current sequence number """ a = compat_bytes(self.account + self.role + self.password, 'utf8') s = hashlib.sha256(a).digest() return PrivateKey(hexlify(s).decode('ascii'))
def test_custom_json(self): op = operations.CustomJson( **{ "json": [ "reblog", OrderedDict( [ # need an ordered dict to keep order for the test ("account", "jared"), ("author", "chainsquad"), ("permlink", "streemian-com-to-open-its-doors-" "and-offer-a-20-discount") ]) ], "required_auths": [], "required_posting_auths": ["jared"], "id": "follow" }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c8045701120001057865726f6306666f6c6c" "6f777f5b227265626c6f67222c207b226163636f756e74223a" "20227865726f63222c2022617574686f72223a202263686169" "6e7371756164222c20227065726d6c696e6b223a2022737472" "65656d69616e2d636f6d2d746f2d6f70656e2d6974732d646f" "6f72732d616e642d6f666665722d612d32302d646973636f75" "6e74227d5d00011f0cffad16cfd8ea4b84c06d412e93a9fc10" "0bf2fac5f9a40d37d5773deef048217db79cabbf15ef29452d" "e4ed1c5face51d998348188d66eb9fc1ccef79a0c0d4") self.assertEqual(compare[:-130], tx_wire[:-130])
def get_private(self): """ Derive private key from the brain key and the current sequence number """ encoded = "%s %d" % (self.brainkey, self.sequence) a = compat_bytes(encoded, 'ascii') s = hashlib.sha256(hashlib.sha512(a).digest()).digest() return PrivateKey(hexlify(s).decode('ascii'))
def base58encode(hexstring): byteseq = compat_bytes(hexstring, 'ascii') byteseq = unhexlify(byteseq) byteseq = compat_bytes(byteseq) n = 0 leading_zeroes_count = 0 for c in byteseq: n = n * 256 + c if n == 0: leading_zeroes_count += 1 res = bytearray() while n >= 58: div, mod = divmod(n, 58) res.insert(0, BASE58_ALPHABET[mod]) n = div else: res.insert(0, BASE58_ALPHABET[n]) return (BASE58_ALPHABET[0:1] * leading_zeroes_count + res).decode('ascii')
def encode_memo(priv, pub, nonce, message, **kwargs): """ Encode a message with a shared secret between Alice and Bob :param PrivateKey priv: Private Key (of Alice) :param PublicKey pub: Public Key (of Bob) :param int nonce: Random nonce :param str message: Memo message :return: Encrypted message :rtype: hex """ from dpaybase import transactions shared_secret = get_shared_secret(priv, pub) aes, check = init_aes(shared_secret, nonce) raw = compat_bytes(message, 'utf8') " Padding " BS = 16 if len(raw) % BS: raw = _pad(raw, BS) " Encryption " cipher = hexlify(aes.encrypt(raw)).decode('ascii') prefix = kwargs.pop("prefix", default_prefix) s = OrderedDict([ ("from", format(priv.pubkey, prefix)), ("to", format(pub, prefix)), ("nonce", nonce), ("check", check), ("encrypted", cipher), ("from_priv", repr(priv)), ("to_pub", repr(pub)), ("shared_secret", shared_secret), ]) tx = Memo(**s) return "#" + base58encode(hexlify(compat_bytes(tx)).decode("ascii"))
def deriveDigest(self, chain): chain_params = self.getChainParams(chain) # Chain ID self.chainid = chain_params["chain_id"] # Do not serialize signatures sigs = self.data["signatures"] self.data["signatures"] = [] # Get message to sign # bytes(self) will give the wire formatted data according to # GrapheneObject and the data given in __init__() self.message = unhexlify(self.chainid) + compat_bytes(self) self.digest = hashlib.sha256(self.message).digest() # restore signatures self.data["signatures"] = sigs
def test_order_cancel(self): op = operations.LimitOrderCancel(**{ "owner": "", "orderid": 2141244, }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c804570106003cac20000001206c9888d0c2c3" "1dba1302566f524dfac01a15760b93a8726241a7ae6ba00edfd" "e5b83edaf94a4bd35c2957ded6023576dcbe936338fb9d340e2" "1b5dad6f0028f6") self.assertEqual(compare[:-130], tx_wire[:-130])
def decode_memo(priv, message): """ Decode a message with a shared secret between Alice and Bob :param PrivateKey priv: Private Key (of Bob) :param base58encoded message: Encrypted Memo message :return: Decrypted message :rtype: str :raise ValueError: if message cannot be decoded as valid UTF-8 string """ " decode structure " raw = base58decode(message[1:]) from_key = PublicKey(raw[:66]) raw = raw[66:] to_key = PublicKey(raw[:66]) raw = raw[66:] nonce = str(struct.unpack_from("<Q", unhexlify(raw[:16]))[0]) raw = raw[16:] check = struct.unpack_from("<I", unhexlify(raw[:8]))[0] raw = raw[8:] cipher = raw if repr(to_key) == repr(priv.pubkey): shared_secret = get_shared_secret(priv, from_key) elif repr(from_key) == repr(priv.pubkey): shared_secret = get_shared_secret(priv, to_key) else: raise ValueError("Incorrect PrivateKey") " Init encryption " aes, checksum = init_aes(shared_secret, nonce) " Check " assert check == checksum, "Checksum failure" " Encryption " # remove the varint prefix (FIXME, long messages!) message = cipher[2:] message = aes.decrypt(unhexlify(compat_bytes(message, 'ascii'))) try: return _unpad(message.decode('utf8'), 16) except: # noqa FIXME(sneak) raise ValueError(message)
def test_witness_vote(self): op = operations.AccountWitnessVote(**{ "account": "jared", "witness": "chainsquad", "approve": True, }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c80457010c057865726f630a636" "861696e73717561640100011f16b43411e11f4739" "4c1624a3c4d3cf4daba700b8690f494e6add7ad9b" "ac735ce7775d823aa66c160878cb3348e6857c531" "114d229be0202dc0857f8f03a00369") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_convert(self): op = operations.Convert(**{ "owner": "jared", "requestid": 2342343235, "amount": "100.000 BBD" }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c804570108057865726f6343529d8ba0860100000" "00000035342440000000000011f3d22eb66e5cddcc90f5d6ca0bd7a" "43e0ab811ecd480022af8a847c45eac720b342188d55643d8cb1711" "f516e9879be2fa7dfa329b518f19df4afaaf4f41f7715") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_Cancel_transfer_from_savings(self): op = operations.CancelTransferFromSavings(**{ "from": "tesuser", "request_id": 9001, }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ( "f68585abf4dce7c8045701220774657375736572292300000001200942474f672" "3937b88e19fb8cade26cc97f68cb626362d0764d134fe837df5262200b5e71bec" "13a0673995a584a47674897e959d8c1f83389505895fb64ceda5") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_withdraw_vesting(self): op = operations.WithdrawVesting(**{ "account": "foo", "vesting_shares": "100 VESTS", }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ( "f68585abf4dce7c80457010403666f6f00e1f5050000000006564553545300000" "00120772da57b15b62780ee3d8afedd8d46ffafb8c62788eab5ce01435df99e1d" "36de549f260444866ff4e228cac445548060e018a872e7ee99ace324af9844f4c" "50a") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_Transfer_to_vesting(self): op = operations.TransferToVesting(**{ "from": "foo", "to": "baar", "amount": "111.110 BEX", }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c80457010303666f6f046261617206b201000000" "000003535445454d00000001203a34cd45fb4a2585514614be2c1" "ba2365257ce5470d20c6c6abda39204eeba0b7e057d889ca8b1b1" "406f1441520a25d32df2ab9fdb532c3377dc66d0fe41bb3d") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_set_route(self): op = operations.SetWithdrawVestingRoute( **{ "from_account": "jared", "to_account": "jared", "percent": 1000, "auto_vest": False }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c804570114057865726f63057865726f63e803" "0000011f12d2b8f93f9528f31979e0e1f59a6d45346a88c02ab2" "c4115b10c9e273fc1e99621af0c2188598c84762b7e99ca63f6b" "6be6fca318dd85b0d7a4f09f95579290") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_change_recovery_account(self): op = operations.ChangeRecoveryAccount( **{ "account_to_recover": "barrie", "extensions": [], "new_recovery_account": "boombastic" }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ('f68585abf4dce7c80457011a066261727269650a626f6f6d6261' '737469630000011f5513c021e89be2c4d8a725dc9b89334ffcde' '6a9535487f4b6d42f93de1722c251fd9d4ec414335dc41ea081a' 'a7a4d27b179b1a07d3415f7e0a6190852b86ecde') self.assertEqual(compare[:-130], tx_wire[:-130])
def test_Transfer(self): op = operations.Transfer(**{ "from": "foo", "to": "baar", "amount": "111.110 BEX", "memo": "Fooo" }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c80457010203666f6f046261617206b201000000" "000003535445454d000004466f6f6f00012025416c234dd5ff15d8" "b45486833443c128002bcafa57269cada3ad213ef88adb5831f63a" "58d8b81bbdd92d494da01eeb13ee1786d02ce075228b25d7132f8f" "3e") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_feed_publish(self): op = operations.FeedPublish( **{ "publisher": "jared", "exchange_rate": { "base": "1.000 BBD", "quote": "4.123 BEX" } }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c804570107057865726f63e803000000000" "00003534244000000001b1000000000000003535445454d00" "000001203847a02aa76964cacfb41565c23286cc64b18f6bb" "9260832823839b3b90dff18738e1b686ad22f79c42fca73e6" "1bf633505a2a66cac65555b0ac535ca5ee5a61") self.assertEqual(compare[:-130], tx_wire[:-130])
def test_Transfer_to_savings(self): op = operations.TransferToSavings( **{ "from": "testuser", "to": "testuser", "amount": "1.000 BEX", "memo": "testmemo", }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) tx_wire = hexlify(compat_bytes(tx)).decode("ascii") compare = ( "f68585abf4dce7c804570120087465737475736572087465737475736572e8030" "0000000000003535445454d000008746573746d656d6f00011f4df74457bf8824" "c02da6a722a7c604676c97aad1a51ebcfb7086b0b7c1f19f9257388a06b3c24ae" "51d97c9eee5e0ecb7b6c32a29af6f56697f0c7516e70a75ce") self.assertEqual(compare[:-130], tx_wire[:-130])
def unicodify(self): r = [] for s in self.data: o = ord(s) if o <= 7: r.append("u%04x" % o) elif o == 8: r.append("b") elif o == 9: r.append("\t") elif o == 10: r.append("\n") elif o == 11: r.append("u%04x" % o) elif o == 12: r.append("f") elif o == 13: r.append("\r") elif 13 < o < 32: r.append("u%04x" % o) else: r.append(s) return compat_bytes("".join(r), "utf-8")
def test_comment_options(self): op = operations.CommentOptions( **{ "author": "jared", "permlink": "dpaypy", "max_accepted_payout": "1000000.000 BBD", "percent_dpay_dollars": 10000, "allow_votes": True, "allow_curation_rewards": True, "beneficiaries": [{ "weight": 2000, "account": "good-karma" }, { "weight": 5000, "account": "null" }], }) ops = [operations.Operation(op)] tx = SignedTransaction(ref_block_num=ref_block_num, ref_block_prefix=ref_block_prefix, expiration=expiration, operations=ops) tx = tx.sign([wif], chain=self.dpay.chain_params) txWire = hexlify(compat_bytes(tx)).decode("ascii") compare = ("f68585abf4dce7c804570113057865726f6306706973746f6e" "00ca9a3b000000000353424400000000102701010100020a67" "6f6f642d6b61726d61d007046e756c6c881300011f59634e65" "55fec7c01cb7d4921601c37c250c6746022cc35eaefdd90405" "d7771b2f65b44e97b7f3159a6d52cb20640502d2503437215f" "0907b2e2213940f34f2c") self.assertEqual(compare[:-130], txWire[:-130])