From 0260304fabf8fdf9acbec8b475e8b58c620f52ff Mon Sep 17 00:00:00 2001 From: Holger Nahrstaedt <holgernahrstaedt@gmx.de> Date: Sat, 9 Jun 2018 09:01:29 +0200 Subject: [PATCH] New operation structure for appbase Transactionbuilder * Prepare broadcasting in new appbase format * Force condenser_api by now RPCUtils * Improve detection of conenser_api Streemnoderpc * Improved error message for Assert Exception:v.is_object() beembase.Object * Add new appbase Operation format beemgraphenebase.object * Add handling of new appbase operation format --- beem/transactionbuilder.py | 26 ++++++++++++++++++++------ beemapi/rpcutils.py | 2 +- beemapi/steemnoderpc.py | 2 ++ beembase/objects.py | 6 +++++- beemgraphenebase/objects.py | 13 +++++++++++++ 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/beem/transactionbuilder.py b/beem/transactionbuilder.py index 02505c6c..69ea7504 100644 --- a/beem/transactionbuilder.py +++ b/beem/transactionbuilder.py @@ -78,7 +78,12 @@ class TransactionBuilder(dict): def list_operations(self): """List all ops""" - return [Operation(o) for o in self.ops] + if self.steem.is_connected() and self.steem.rpc.get_use_appbase(): + # appbase disabled by now + appbase = False + else: + appbase = False + return [Operation(o, appbase=appbase) for o in self.ops] def _is_signed(self): """Check if signatures exists""" @@ -230,12 +235,17 @@ class TransactionBuilder(dict): """ ops = list() + if self.steem.is_connected() and self.steem.rpc.get_use_appbase(): + # appbase disabled by now + # broadcasting does not work at the moment + appbase = False + else: + appbase = False for op in self.ops: # otherwise, we simply wrap ops into Operations - ops.extend([Operation(op)]) + ops.extend([Operation(op, appbase=appbase)]) # We no wrap everything into an actual transaction - # ops = transactions.addRequiredFees(self.steem.rpc, ops) expiration = formatTimeFromNow( self.expiration or self.steem.expiration ) @@ -370,9 +380,13 @@ class TransactionBuilder(dict): return ret = self.json() if self.steem.is_connected() and self.steem.rpc.get_use_appbase(): - args = {'trx': self.json(), 'max_block_age': max_block_age} + # Returns an internal Error at the moment + # args = {'trx': self.json(), 'max_block_age': max_block_age} + args = self.json() + broadcast_api = "condenser" else: args = self.json() + broadcast_api = "network_broadcast" if self.steem.nobroadcast: log.warning("Not broadcasting anything!") @@ -385,11 +399,11 @@ class TransactionBuilder(dict): ret = self.steem.steemconnect.broadcast(self["operations"]) elif self.steem.blocking: ret = self.steem.rpc.broadcast_transaction_synchronous( - args, api="network_broadcast") + args, api=broadcast_api) ret.update(**ret.get("trx")) else: self.steem.rpc.broadcast_transaction( - args, api="network_broadcast") + args, api=broadcast_api) except Exception as e: # log.error("Could Not broadcasting anything!") self.clear() diff --git a/beemapi/rpcutils.py b/beemapi/rpcutils.py index cc0dde51..8e35e4c2 100644 --- a/beemapi/rpcutils.py +++ b/beemapi/rpcutils.py @@ -26,7 +26,7 @@ def is_network_appbase_ready(props): def get_query(appbase, request_id, api_name, name, args): query = [] - if not appbase: + if not appbase or api_name == "condenser_api": query = {"method": "call", "params": [api_name, name, list(args)], "jsonrpc": "2.0", diff --git a/beemapi/steemnoderpc.py b/beemapi/steemnoderpc.py index f1b2d5eb..15b12d2a 100644 --- a/beemapi/steemnoderpc.py +++ b/beemapi/steemnoderpc.py @@ -140,6 +140,8 @@ class SteemNodeRPC(GrapheneRPC): doRetry = True elif re.search("out_of_rangeEEEE: unknown key", msg) or re.search("unknown key:unknown key", msg): raise exceptions.UnkownKey(msg) + elif re.search("Assert Exception:v.is_object(): Input data have to treated as object", msg): + raise exceptions.UnhandledRPCError("Use Operation(op, appbase=True) to prevent error: " + msg) elif msg: raise exceptions.UnhandledRPCError(msg) else: diff --git a/beembase/objects.py b/beembase/objects.py index 68acf439..db812309 100644 --- a/beembase/objects.py +++ b/beembase/objects.py @@ -70,6 +70,7 @@ class Amount(object): @python_2_unicode_compatible class Operation(GPHOperation): def __init__(self, *args, **kwargs): + self.appbase = kwargs.pop("appbase", False) super(Operation, self).__init__(*args, **kwargs) def _getklass(self, name): @@ -96,7 +97,10 @@ class Operation(GPHOperation): return py23_bytes(Id(self.opId)) + py23_bytes(self.op) def __str__(self): - return json.dumps([self.name.lower(), self.op.toJson()]) + if self.appbase: + return json.dumps({'type': self.name.lower() + '_operation', 'value': self.op.toJson()}) + else: + return json.dumps([self.name.lower(), self.op.toJson()]) class Memo(GrapheneObject): diff --git a/beemgraphenebase/objects.py b/beemgraphenebase/objects.py index d7f80f47..cb08b642 100644 --- a/beemgraphenebase/objects.py +++ b/beemgraphenebase/objects.py @@ -38,6 +38,19 @@ class Operation(object): except Exception: raise NotImplementedError("Unimplemented Operation %s" % self.name) self.op = klass(op[1]) + self.appbase = False + elif isinstance(op, dict): + name = op["type"][:-10] + self.opId = self.operations().get(name, None) + if self.opId is None: + raise ValueError("Unknown operation") + self.name = name[0].upper() + name[1:] # klassname + try: + klass = self._getklass(self.name) + except Exception: + raise NotImplementedError("Unimplemented Operation %s" % self.name) + self.op = klass(op["value"]) + self.appbase = True else: self.op = op self.name = type(self.op).__name__.lower() # also store name -- GitLab