def main(argv): """ Tool entry point function """ parser = argparse.ArgumentParser(prog=argv[0], description="Create snapshot files for Steem") parser.add_argument("-s", "--server", default="http://127.0.0.1:8090", dest="server", metavar="URL", help="Specify mainnet steemd server") parser.add_argument("-o", "--outfile", default="-", dest="outfile", metavar="FILE", help="Specify output file, - means stdout") args = parser.parse_args(argv[1:]) if args.outfile == "-": outfile = sys.stdout else: outfile = open(args.outfile, "w") backend = SteemRemoteBackend(nodes=[args.server], appbase=True) steemd = SteemInterface(backend) outfile.write("{\n") outfile.write('"metadata":{"snapshot:semver":"%s","snapshot:origin_api":"%s"}' % (__version__, args.server)) outfile.write(',\n"dynamic_global_properties":') dump_dgpo(steemd, outfile) outfile.write(',\n"accounts":') dump_all_accounts(steemd, outfile) outfile.write(',\n"witnesses":') dump_all_witnesses(steemd, outfile) outfile.write("\n}\n") outfile.flush() if args.outfile != "-": outfile.close() return
def repack_operations(conf, keydb, min_block, max_block, from_blocks_ago, to_blocks_ago): """ Uses configuration file data to acquire operations from source node blocks/transactions and repack them in new transactions one to one. """ source_node = conf["transaction_source"]["node"] is_appbase = str2bool(conf["transaction_source"]["appbase"]) backend = SteemRemoteBackend(nodes=[source_node], appbase=is_appbase) steemd = SteemInterface(backend) dgpo = steemd.database_api.get_dynamic_global_properties() if min_block == 0: min_block = dgpo["head_block_number"] if from_blocks_ago != -1: min_block = dgpo["head_block_number"] - from_blocks_ago if to_blocks_ago != -1: max_block = dgpo["head_block_number"] - to_blocks_ago ported_operations = conf["ported_operations"] ported_types = set([op["type"] for op in ported_operations]) """ Positive value of max_block means get from [min_block_number,max_block_number) range and stop """ if max_block > 0: for op in util.iterate_operations_from(steemd, is_appbase, min_block, max_block, ported_types): yield op_for_role(op, conf, keydb, ported_operations) return """ Otherwise get blocks from min_block_number to current head and again until you have to wait for another block to be produced (chase-then-listen mode) """ old_head_block = min_block while True: dgpo = steemd.database_api.get_dynamic_global_properties() new_head_block = dgpo["head_block_number"] while old_head_block == new_head_block: time.sleep( 1 ) # Theoretically 3 seconds, but most probably we won't have to wait that long. dgpo = steemd.database_api.get_dynamic_global_properties() new_head_block = dgpo["head_block_number"] for op in util.iterate_operations_from(steemd, is_appbase, old_head_block, new_head_block, ported_types): yield op_for_role(op, conf, keydb, ported_operations) old_head_block = new_head_block return
def repack_operations(conf, keydb, min_block, max_block): """ Uses configuration file data to acquire operations from source node blocks/transactions and repack them in new transactions one to one. """ source_node = conf["transaction_source"]["node"] is_appbase = str2bool(conf["transaction_source"]["appbase"]) backend = SteemRemoteBackend(nodes=[source_node], appbase=is_appbase) steemd = SteemInterface(backend) min_block = int(conf["min_block_number"]) if min_block == 0 else min_block max_block = int(conf["max_block_number"]) if max_block == 0 else max_block ported_operations = set(conf["ported_operations"]) tx_signer = conf["transaction_signer"] """ Positive value of max_block means get from [min_block_number,max_block_number) range and stop """ if max_block > 0: for op in util.iterate_operations_from(steemd, is_appbase, min_block, max_block, ported_operations): yield { "operations": [op], "wif_sigs": [keydb.get_privkey(tx_signer)] } return """ Otherwise get blocks from min_block_number to current head and again until you have to wait for another block to be produced (chase-then-listen mode) """ old_head_block = min_block while True: dgpo = steemd.database_api.get_dynamic_global_properties() new_head_block = dgpo["head_block_number"] while old_head_block == new_head_block: time.sleep( 1 ) # Theoretically 3 seconds, but most probably we won't have to wait that long. dgpo = steemd.database_api.get_dynamic_global_properties() new_head_block = dgpo["head_block_number"] for op in util.iterate_operations_from(steemd, is_appbase, old_head_block, new_head_block, ported_operations): yield { "operations": [op], "wif_sigs": [keydb.get_privkey(tx_signer)] } old_head_block = new_head_block return
def test_iterate_operations_from(self): backend = SteemRemoteBackend(nodes=["https://api.steemit.com"], appbase=True) steemd = SteemInterface(backend) result = util.iterate_operations_from(steemd, True, 1102, 1103, set()) expected_op = { 'type': 'pow_operation', 'value': { 'worker_account': 'steemit11', 'block_id': '0000044df0f062c0504a8e37288a371ada63a1c7', 'nonce': 33097, 'work': { 'worker': 'STM65wH1LZ7BfSHcK69SShnqCAH5xdoSZpGkUjmzHJ5GCuxEK9V5G', 'input': '45a3824498b87e41129f6fef17be276af6ff87d1e859128f28aaa9c08208871d', 'signature': '1f93a52c4f794803b2563845b05b485e3e5f4c075ddac8ea8cffb988a1ffcdd1055590a3d5206a3be83cab1ea548fc52889d43bdbd7b74d62f87fb8e2166145a5d', 'work': '00003e554a58830e7e01669796f40d1ce85c7eb979e376cb49e83319c2688c7e', }, 'props': { 'account_creation_fee': {"amount" : "100000", "precision" : 3, "nai" : "@@000000021"}, 'maximum_block_size': 131072, 'sbd_interest_rate': 1000 } } } # Scan all of the results and match against the expected op. This will # fail if we get anything other than this exact op. for op in result: self.assertEqual(op['type'], expected_op['type']) self.assertEqual(op['value']['worker_account'], expected_op['value']['worker_account']) self.assertEqual(op['value']['block_id'], expected_op['value']['block_id']) self.assertEqual(op['value']['nonce'], expected_op['value']['nonce']) self.assertEqual(op['value']['work']['worker'], expected_op['value']['work']['worker']) self.assertEqual(op['value']['work']['input'], expected_op['value']['work']['input']) self.assertEqual(op['value']['work']['signature'], expected_op['value']['work']['signature']) self.assertEqual(op['value']['work']['work'], expected_op['value']['work']['work']) self.assertEqual(op['value']['props']['account_creation_fee']['amount'], expected_op['value']['props']['account_creation_fee']['amount']) self.assertEqual(op['value']['props']['account_creation_fee']['precision'], expected_op['value']['props']['account_creation_fee']['precision']) self.assertEqual(op['value']['props']['account_creation_fee']['nai'], expected_op['value']['props']['account_creation_fee']['nai']) self.assertEqual(op['value']['props']['maximum_block_size'], expected_op['value']['props']['maximum_block_size']) self.assertEqual(op['value']['props']['sbd_interest_rate'], expected_op['value']['props']['sbd_interest_rate'])
def main(argv): parser = argparse.ArgumentParser( prog=argv[0], description="Submit transactions to Steem") parser.add_argument( "-t", "--testserver", default="http://127.0.0.1:8190", dest="testserver", metavar="URL", help="Specify testnet steemd server with debug enabled") parser.add_argument("--signer", default="sign_transaction", dest="sign_transaction_exe", metavar="FILE", help="Specify path to sign_transaction tool") parser.add_argument("-i", "--input-file", default="-", dest="input_file", metavar="FILE", help="File to read transactions from") parser.add_argument( "-f", "--fail-file", default="-", dest="fail_file", metavar="FILE", help="File to write failures, - for stdout, die to quit on failure") parser.add_argument("-n", "--chain-name", default="", dest="chain_name", metavar="CN", help="Specify chain name") parser.add_argument("-c", "--chain-id", default="", dest="chain_id", metavar="CID", help="Specify chain ID") parser.add_argument("--timeout", default=5.0, type=float, dest="timeout", metavar="SECONDS", help="API timeout") parser.add_argument("--realtime", dest="realtime", action="store_true", help="Wait when asked to produce blocks in the future") args = parser.parse_args(argv[1:]) die_on_fail = False if args.fail_file == "-": fail_file = sys.stdout elif args.fail_file == "die": fail_file = sys.stdout die_on_fail = True else: fail_file = open(args.fail_file, "w") if args.input_file == "-": input_file = sys.stdin else: input_file = open(args.input_file, "r") timeout = args.timeout backend = SteemRemoteBackend(nodes=[args.testserver], appbase=True, min_timeout=timeout, max_timeout=timeout) steemd = SteemInterface(backend) sign_transaction_exe = args.sign_transaction_exe produce_realtime = args.realtime cached_dgpo = CachedDgpo(steemd=steemd) if args.chain_name != "": chain_id = hashlib.sha256(str.encode( args.chain_name.strip())).digest().hex() else: chain_id = None if args.chain_id != "": chain_id = args.chain_id.strip() signer = TransactionSigner(sign_transaction_exe=sign_transaction_exe, chain_id=chain_id) for line in input_file: line = line.strip() cmd, args = json.loads(line) try: if cmd == "wait_blocks": generate_blocks(steemd, args, cached_dgpo=cached_dgpo, produce_realtime=produce_realtime) cached_dgpo.reset() elif cmd == "submit_transaction": tx = args["tx"] dgpo = cached_dgpo.get() tx["ref_block_num"] = dgpo["head_block_number"] & 0xFFFF tx["ref_block_prefix"] = struct.unpack_from( "<I", unhexlify(dgpo["head_block_id"]), 4)[0] head_block_time = datetime.datetime.strptime( dgpo["time"], "%Y-%m-%dT%H:%M:%S") expiration = head_block_time + datetime.timedelta(minutes=1) expiration_str = expiration.strftime("%Y-%m-%dT%H:%M:%S") tx["expiration"] = expiration_str wif_sigs = tx["wif_sigs"] del tx["wif_sigs"] sigs = [] for wif in wif_sigs: if not isinstance(wif_sigs, list): raise RuntimeError("wif_sigs is not list") result = signer.sign_transaction(tx, wif) if "error" in result: print("could not sign transaction", tx, "due to error:", result["error"]) else: sigs.append(result["result"]["sig"]) tx["signatures"] = sigs print("bcast:", json.dumps(tx, separators=(",", ":"))) steemd.network_broadcast_api.broadcast_transaction(trx=tx) except Exception as e: fail_file.write(json.dumps([cmd, args, str(e)]) + "\n") fail_file.flush() if die_on_fail: raise
from simple_steem_client.client import SteemRemoteBackend, SteemInterface import json backend = SteemRemoteBackend(nodes=["http://127.0.0.1:9990/"], appbase=True) steem = SteemInterface(backend) dgpo = steem.database_api.get_dynamic_global_properties() print("dgpo:", json.dumps(dgpo, separators=(",", ":")))
def test_list_all_accounts(self): backend = SteemRemoteBackend(nodes=["http://test.com"], appbase=True) steemd = SteemInterface(backend) self.assertIsNotNone(snapshot.list_all_accounts(steemd))
def main(argv): """ Checks basic node suitability for gatling phase. """ parser = argparse.ArgumentParser(prog=argv[0], description="Generate transactions for Steem testnet") parser.add_argument("-s", "--server", default="http://127.0.0.1:8090", dest="server", metavar="URL", help="Specify steemd server to watch over") args = parser.parse_args(argv[1:]) backend = SteemRemoteBackend(nodes=[args.server], appbase=True, max_timeout=0.0, max_retries=0) steemd = SteemInterface(backend) passfail = [] config = steemd.database_api.get_config(x=None) dgpo = steemd.database_api.get_dynamic_global_properties(x=None) head_block_time = datetime.datetime.strptime(dgpo["time"], "%Y-%m-%dT%H:%M:%S") rtc_now = datetime.datetime.utcnow() diff = rtc_now - head_block_time diff = diff.total_seconds() block_interval = config["STEEM_BLOCK_INTERVAL"] if config["IS_TEST_NET"]: print("[√] testnet: true") passfail.append(PREFLIGHT_GO) else: print("[X] testnet: false") passfail.append(PREFLIGHT_NOGO) if diff < 0: print("[X] head block time: %s seconds into the future" % abs(diff)) passfail.append(PREFLIGHT_NOGO) elif diff - block_interval > 0: print("[X] head block time: %s seconds behind" % diff) passfail.append(PREFLIGHT_NOGO) else: print("[√] head block time: within %s seconds" % block_interval) passfail.append(PREFLIGHT_GO) witness_schedule = steemd.database_api.get_witness_schedule(x=None) witnesses = witness_schedule["current_shuffled_witnesses"] initminer = config["STEEM_INIT_MINER_NAME"] if initminer not in witnesses: print("[√] witnesses: %s not present" % initminer) passfail.append(PREFLIGHT_GO) else: print("[X] witnesses: %s present" % initminer) passfail.append(PREFLIGHT_NOGO) scheduled_witnesses = witness_schedule["num_scheduled_witnesses"] if scheduled_witnesses == config["STEEM_MAX_WITNESSES"]: print("[√] scheduled witnesses: %s" % config["STEEM_MAX_WITNESSES"]) passfail.append(PREFLIGHT_GO) else: print("[X] scheduled witnesses: %s" % scheduled_witnesses) passfail.append(PREFLIGHT_NOGO) majority_version = witness_schedule["majority_version"] if majority_version == '0.0.0': print("[X] majority version: 0.0.0") passfail.append(PREFLIGHT_NOGO) else: print("[√] majority version: %s" % majority_version) passfail.append(PREFLIGHT_GO) exit(PREFLIGHT_NOGO in passfail) # Also tell the caller everything is ok.
def main(argv): parser = argparse.ArgumentParser(prog=argv[0], description="Web Server") parser.add_argument("-c", "--conffile", default="server.conf", dest="conffile", metavar="FILE", help="Specify configuration file") parser.add_argument("--signer", default="sign_transaction", dest="sign_transaction_exe", metavar="FILE", help="Specify path to sign_transaction tool") parser.add_argument("--get-dev-key", default="get_dev_key", dest="get_dev_key_exe", metavar="FILE", help="Specify path to get_dev_key tool") parser.add_argument("-n", "--chain-name", default="", dest="chain_name", metavar="CN", help="Specify chain name") parser.add_argument("-cid", "--chain-id", default="", dest="chain_id", metavar="CID", help="Specify chain ID") parser.add_argument("--timeout", default=5.0, type=float, dest="timeout", metavar="SECONDS", help="API timeout") args = parser.parse_args(argv[1:]) with open(args.conffile, "r") as f: conf = json.load(f) timeout = args.timeout node = conf["transaction_target"]["node"] shared_secret = conf["shared_secret"] account_creator = conf["account_creator"] result_bytes = subprocess.check_output( [args.get_dev_key_exe, shared_secret, "active-" + account_creator]) result_str = result_bytes.decode("utf-8") result_json = json.loads(result_str.strip()) account_creator_wif = result_json[0]["private_key"] backend = SteemRemoteBackend(nodes=[node], appbase=True, min_timeout=timeout, max_timeout=timeout) steemd = SteemInterface(backend) sign_transaction_exe = args.sign_transaction_exe if args.chain_name != "": chain_id = hashlib.sha256(str.encode( args.chain_name.strip())).digest().hex() else: chain_id = None if args.chain_id != "": chain_id = args.chain_id.strip() signer = submit.TransactionSigner( sign_transaction_exe=sign_transaction_exe, chain_id=chain_id) template_dir = '/tmp/tinman-templates' static_dir = '/tmp/tinman-static' app = Flask(__name__, template_folder=template_dir, static_folder=static_dir, static_url_path='/static') app.debug = True # Temporary development secret key (for web forms). app.config['SECRET_KEY'] = '5333d026583fdd09f413d472b29ed39e' @app.route("/account_create", methods=['GET', 'POST']) def account_create(): form = ReusableForm(request.form) print(form.errors) if request.method == 'POST': new_account_name = request.form['new_account_name'] if form.validate(): key_types = ["owner", "active", "posting", "memo"] keys = {} for key_type in key_types: result_bytes = subprocess.check_output([ args.get_dev_key_exe, shared_secret, key_type + "-" + new_account_name ]) result_str = result_bytes.decode("utf-8") result_json = json.loads(result_str.strip()) keys[key_type] = result_json[0] tx = { "operations": [{ "type": "account_create_operation", "value": { "creator": account_creator, "new_account_name": new_account_name, "fee": { "amount": "0", "nai": "@@000000021", "precision": 3 }, "owner": { "account_auths": [["tnman", 1]], "key_auths": [[keys["owner"]["public_key"], 1]], "weight_threshold": 1 }, "active": { "account_auths": [["tnman", 1]], "key_auths": [[keys["active"]["public_key"], 1]], "weight_threshold": 1 }, "posting": { "account_auths": [["tnman", 1]], "key_auths": [[keys["posting"]["public_key"], 1]], "weight_threshold": 1 }, "memo_key": keys["memo"]["public_key"], "json_metadata": "" } }, { "type": "transfer_to_vesting_operation", "value": { "amount": { "amount": "1000000", "nai": "@@000000021", "precision": 3 }, "from": account_creator, "to": new_account_name } }], "signatures": [] } cached_dgpo = submit.CachedDgpo(steemd=steemd) dgpo = cached_dgpo.get() tx["ref_block_num"] = dgpo["head_block_number"] & 0xFFFF tx["ref_block_prefix"] = struct.unpack_from( "<I", unhexlify(dgpo["head_block_id"]), 4)[0] head_block_time = datetime.datetime.strptime( dgpo["time"], "%Y-%m-%dT%H:%M:%S") expiration = head_block_time + datetime.timedelta(minutes=1) expiration_str = expiration.strftime("%Y-%m-%dT%H:%M:%S") tx["expiration"] = expiration_str result = signer.sign_transaction(tx, account_creator_wif) if "error" in result: print("could not sign transaction", tx, "due to error:", result["error"]) else: tx["signatures"].append(result["result"]["sig"]) print("bcast:", json.dumps(tx, separators=(",", ":"))) try: steemd.network_broadcast_api.broadcast_transaction(trx=tx) flash("Account Created: " + new_account_name) for key in keys: flash(key + ": " + keys[key]["private_key"]) except SteemRPCException as e: cause = e.args[0].get("error") if cause: message = cause.get("message") data = cause.get("data") else: message = str(e) print(str(e)) flash("Unable to create account: " + message) else: flash('All the form fields are required.') return render_template('account_create.html', form=form) app.run()
def main(argv): parser = argparse.ArgumentParser(prog=argv[0], description="Submit transactions to Steem") parser.add_argument("-t", "--testserver", default="http://127.0.0.1:8190", dest="testserver", metavar="URL", help="Specify testnet steemd server with debug enabled") parser.add_argument("--signer", default="sign_transaction", dest="sign_transaction_exe", metavar="FILE", help="Specify path to sign_transaction tool") parser.add_argument("-i", "--input-file", default="-", dest="input_file", metavar="FILE", help="File to read transactions from") parser.add_argument("-f", "--fail-file", default="-", dest="fail_file", metavar="FILE", help="File to write failures, - for stdout, die to quit on failure") parser.add_argument("-n", "--chain-name", default="", dest="chain_name", metavar="CN", help="Specify chain name") parser.add_argument("-c", "--chain-id", default="", dest="chain_id", metavar="CID", help="Specify chain ID") parser.add_argument("-tpb", "--transactions-per-block", default="40", dest="transactions_per_block", metavar="INT", help="Transactions per block (default: 40)") parser.add_argument("--timeout", default=5.0, type=float, dest="timeout", metavar="SECONDS", help="API timeout") parser.add_argument("--realtime", dest="realtime", action="store_true", help="Wait when asked to produce blocks in the future") args = parser.parse_args(argv[1:]) die_on_fail = False if args.fail_file == "-": fail_file = sys.stdout elif args.fail_file == "die": fail_file = sys.stdout die_on_fail = True else: fail_file = open(args.fail_file, "w") if args.input_file == "-": input_file = sys.stdin else: input_file = open(args.input_file, "r") timeout = args.timeout backend = SteemRemoteBackend(nodes=[args.testserver], appbase=True, min_timeout=timeout, max_timeout=timeout) steemd = SteemInterface(backend) sign_transaction_exe = args.sign_transaction_exe produce_realtime = args.realtime cached_dgpo = CachedDgpo(steemd=steemd) if args.chain_name != "": chain_id = hashlib.sha256(str.encode(args.chain_name.strip())).digest().hex() else: chain_id = None if args.chain_id != "": chain_id = args.chain_id.strip() transactions_per_block = int(args.transactions_per_block) transactions_count = 0 signer = TransactionSigner(sign_transaction_exe=sign_transaction_exe, chain_id=chain_id) metadata = None for line in input_file: line = line.strip() cmd, args = json.loads(line) try: if cmd == "metadata": metadata = args if args.get("post_backfill"): dgpo = cached_dgpo.get() now = datetime.datetime.utcnow() head_block_time = datetime.datetime.strptime(dgpo["time"], "%Y-%m-%dT%H:%M:%S") join_head = int((now - head_block_time).total_seconds()) // STEEM_BLOCK_INTERVAL if join_head > STEEM_BLOCK_INTERVAL: generate_blocks(steemd, {"count": join_head}, cached_dgpo=cached_dgpo, produce_realtime=produce_realtime) cached_dgpo.reset() else: transactions_per_block = metadata.get("txgen:transactions_per_block", transactions_per_block) semver = metadata.get("txgen:semver", '0.0') major_version, minor_version = semver.split('.') major_version = int(major_version) minor_version = int(minor_version) if major_version == ACTIONS_MAJOR_VERSION_SUPPORTED: print("metadata:", metadata) else: raise RuntimeError("Unsupported actions:", metadata) if minor_version < ACTIONS_MINOR_VERSION_SUPPORTED: print("WARNING: Older actions encountered.", file=sys.stderr) elif cmd == "wait_blocks": if metadata and args.get("count") == 1 and args.get("miss_blocks"): if args["miss_blocks"] < metadata["recommend:miss_blocks"]: args["miss_blocks"] = metadata["recommend:miss_blocks"] generate_blocks(steemd, args, cached_dgpo=cached_dgpo, produce_realtime=produce_realtime) cached_dgpo.reset() elif cmd == "submit_transaction": tx = args["tx"] dgpo = cached_dgpo.get() tx["ref_block_num"] = dgpo["head_block_number"] & 0xFFFF tx["ref_block_prefix"] = struct.unpack_from("<I", unhexlify(dgpo["head_block_id"]), 4)[0] head_block_time = datetime.datetime.strptime(dgpo["time"], "%Y-%m-%dT%H:%M:%S") expiration = head_block_time+datetime.timedelta(minutes=1) expiration_str = expiration.strftime("%Y-%m-%dT%H:%M:%S") tx["expiration"] = expiration_str wif_sigs = tx["wif_sigs"] del tx["wif_sigs"] sigs = [] for wif in wif_sigs: if not isinstance(wif_sigs, list): raise RuntimeError("wif_sigs is not list") result = signer.sign_transaction(tx, wif) if "error" in result: print("could not sign transaction", tx, "due to error:", result["error"]) else: sigs.append(result["result"]["sig"]) tx["signatures"] = sigs print("bcast:", json.dumps(tx, separators=(",", ":"))) steemd.network_broadcast_api.broadcast_transaction(trx=tx) transactions_count += 1 except Exception as e: fail_file.write(json.dumps([cmd, args, str(e)])+"\n") fail_file.flush() if die_on_fail: raise if metadata and transactions_count > 0 and transactions_count % transactions_per_block == 0: generate_blocks(steemd, {"count": 1}, cached_dgpo=cached_dgpo, produce_realtime=produce_realtime) cached_dgpo.reset() if cmd == "wait_blocks" and args.get("count") == 1 and not args.get("miss_blocks"): continue