From c3cff5c3dc7665bcd1162453164db6d05194aa30 Mon Sep 17 00:00:00 2001 From: Torkel Rogstad Date: Mon, 6 Nov 2023 18:31:43 +0100 Subject: [PATCH] withdrawal bundles: fetch bundle info --- .../tabs/withdrawal_bundle_tab_page.dart | 3 +- lib/rpc/rpc_mainchain.dart | 9 +++- lib/rpc/rpc_sidechain.dart | 54 +++++++++++++++++++ lib/rpc/rpc_withdrawal_bundle.dart | 47 +++++++++++----- 4 files changed, 97 insertions(+), 16 deletions(-) diff --git a/lib/pages/tabs/withdrawal_bundle_tab_page.dart b/lib/pages/tabs/withdrawal_bundle_tab_page.dart index 2d430b1e..47a86c00 100644 --- a/lib/pages/tabs/withdrawal_bundle_tab_page.dart +++ b/lib/pages/tabs/withdrawal_bundle_tab_page.dart @@ -51,6 +51,7 @@ class WithdrawalBundleTabPage extends StatelessWidget { title: 'Current withdrawal bundle', endWidget: SailText.primary12( [ + 'ID: ${viewModel.currentBundle?.hash}', 'Created at block height ${viewModel.currentBundle?.blockHeight}', '${viewModel.votes}/${viewModel.votesRequired} votes', '${viewModel.currentBundle?.bundleSize}/${viewModel.currentBundle?.maxBundleSize} vbytes', @@ -157,7 +158,7 @@ class _WithdrawalViewState extends State { child: SailSVG.icon(SailSVGAsset.iconPending, width: 13), ), copyable: false, - label: 'TODO', + label: widget.withdrawal.status, value: extractTitle(widget.withdrawal), ), ], diff --git a/lib/rpc/rpc_mainchain.dart b/lib/rpc/rpc_mainchain.dart index 7a05b57f..ef74edbf 100644 --- a/lib/rpc/rpc_mainchain.dart +++ b/lib/rpc/rpc_mainchain.dart @@ -78,7 +78,14 @@ class MainchainRPCLive extends MainchainRPC { @override Future getWithdrawalBundleWorkScore(int sidechain, String hash) async { - return await _client?.call('getworkscore', [sidechain, hash]); + try { + final workscore = await _client?.call('getworkscore', [sidechain, hash]); + return workscore; + } on RPCException { + // This exception can be thrown if the bundle hasn't been added to the + // Sidechain DB yet. Avoid erroring here, and instead return 0. + return 0; + } } @override diff --git a/lib/rpc/rpc_sidechain.dart b/lib/rpc/rpc_sidechain.dart index 969a0679..b1454a3c 100644 --- a/lib/rpc/rpc_sidechain.dart +++ b/lib/rpc/rpc_sidechain.dart @@ -232,8 +232,26 @@ class SidechainRPCLive extends SidechainRPC { final decoded = await _client?.call('decoderawtransaction', [rawWithdrawalBundle]); final tx = RawTransaction.fromJson(decoded); + final info = await _client?.call( + 'getwithdrawalbundleinfo', + [tx.hash], + ); + + final withdrawalIDs = info['withdrawals'] as List; + + final withdrawals = await Future.wait( + withdrawalIDs.map( + (id) => _client!.call( + 'getwithdrawal', + [id], + ).then((json) => Withdrawal.fromJson(json)), + ), + ); + return WithdrawalBundle.fromRawTransaction( tx, + BundleInfo.fromJson(info), + withdrawals, ); } @@ -249,6 +267,9 @@ class SidechainRPCLive extends SidechainRPC { mainchainFeesSatoshi: withdrawal['amountmainchainfee'], amountSatoshi: withdrawal['amount'], address: withdrawal['destination'], + hashBlindTx: '', // TODO + refundDestination: '', // TODO + status: '', // TODO ), ) .toList(), @@ -257,6 +278,7 @@ class SidechainRPCLive extends SidechainRPC { } class RPCError { + static const errMisc = -3; static const errNoWithdrawalBundle = -100; static const errWithdrawalNotFound = -101; } @@ -415,3 +437,35 @@ String? ifNonEmpty(String input) { return input; } + +class BundleInfo { + final int amountSatoshi; + final int feesSatoshi; + final int weight; + final int height; + + BundleInfo({ + required this.amountSatoshi, + required this.feesSatoshi, + required this.weight, + required this.height, + }); + + factory BundleInfo.fromJson(Map json) { + return BundleInfo( + amountSatoshi: json['amount'], + feesSatoshi: json['fees'], + weight: json['weight'], + height: json['height'], + ); + } + + Map toJson() { + return { + 'amount': amountSatoshi, + 'fees': feesSatoshi, + 'weight': weight, + 'height': height, + }; + } +} diff --git a/lib/rpc/rpc_withdrawal_bundle.dart b/lib/rpc/rpc_withdrawal_bundle.dart index 7c5f0e68..964418c5 100644 --- a/lib/rpc/rpc_withdrawal_bundle.dart +++ b/lib/rpc/rpc_withdrawal_bundle.dart @@ -1,4 +1,5 @@ import 'package:sidesail/rpc/rpc_rawtx.dart'; +import 'package:sidesail/rpc/rpc_sidechain.dart'; class WithdrawalBundle { WithdrawalBundle({ @@ -10,22 +11,14 @@ class WithdrawalBundle { factory WithdrawalBundle.fromRawTransaction( RawTransaction tx, + BundleInfo info, + List withdrawals, ) => WithdrawalBundle( hash: tx.hash, - bundleSize: tx.size * 4, - blockHeight: 0, // TODO: how to get this - withdrawals: tx.vout - // filter out OP_RETURN - .where((out) => out.scriptPubKey.type != 'nulldata') - .map( - (out) => Withdrawal( - mainchainFeesSatoshi: 0, // TODO: how to get this - amountSatoshi: (out.value * 100 * 1000 * 1000).toInt(), - address: out.scriptPubKey.addresses.first, - ), - ) - .toList(), + bundleSize: info.weight, + blockHeight: info.height, + withdrawals: withdrawals, ); final String hash; @@ -56,9 +49,35 @@ class Withdrawal { required this.mainchainFeesSatoshi, required this.amountSatoshi, required this.address, + required this.hashBlindTx, + required this.refundDestination, + required this.status, }); - final int mainchainFeesSatoshi; // TODO: how to obtain? + final int mainchainFeesSatoshi; final int amountSatoshi; final String address; + final String hashBlindTx; + final String refundDestination; + + // Directly from RPC interface. + final String status; + + factory Withdrawal.fromJson(Map json) => Withdrawal( + address: json['destination'], + refundDestination: json['refunddestination'], + amountSatoshi: json['amount'], + mainchainFeesSatoshi: json['amountmainchainfee'], + status: json['status'], + hashBlindTx: json['hashblindtx'], + ); + + Map toJson() => { + 'destination': address, + 'refunddestination': refundDestination, + 'amount': amountSatoshi, + 'amountmainchainfee': mainchainFeesSatoshi, + 'status': status, + 'hashblindtx': hashBlindTx, + }; }