| 117 | |
| 118 | |
| 119 | def check_coin_moves(n, account_id, expected_moves, chainparams): |
| 120 | moves = n.rpc.call('listcoinmoves_plugin')['coin_moves'] |
| 121 | # moves can lag; wait for a few seconds if we don't have correct number. |
| 122 | # then move on: we'll get details below. |
| 123 | expected_count = 0 |
| 124 | for m in enumerate(expected_moves): |
| 125 | if isinstance(m, list): |
| 126 | expected_count += len(m) |
| 127 | else: |
| 128 | expected_count += 1 |
| 129 | |
| 130 | if len(moves) != expected_count: |
| 131 | time.sleep(5) |
| 132 | moves = n.rpc.call('listcoinmoves_plugin')['coin_moves'] |
| 133 | |
| 134 | node_id = n.info['id'] |
| 135 | acct_moves = [m for m in moves if m['account_id'] == account_id] |
| 136 | # Stash moves for errors, if needed |
| 137 | _acct_moves = acct_moves |
| 138 | for mv in acct_moves: |
| 139 | # Generate tags as single array, which is how bookkeeper presents it |
| 140 | mv['tags'] = [mv['primary_tag']] + mv['extra_tags'] |
| 141 | print("{{'type': '{}', 'credit_msat': {}, 'debit_msat': {}, 'tags': '{}' , ['fees_msat'?: '{}']}}," |
| 142 | .format(mv['type'], |
| 143 | Millisatoshi(mv['credit_msat']).millisatoshis, |
| 144 | Millisatoshi(mv['debit_msat']).millisatoshis, |
| 145 | mv['tags'], |
| 146 | mv['fees_msat'] if 'fees_msat' in mv else '')) |
| 147 | if mv['version'] != 2: |
| 148 | raise ValueError(f'version not 2 {mv}') |
| 149 | if mv['node_id'] != node_id: |
| 150 | raise ValueError(f'node_id not: {mv}') |
| 151 | if mv['timestamp'] <= 0: |
| 152 | raise ValueError(f'timestamp invalid: {mv}') |
| 153 | if mv['coin_type'] != chainparams['bip173_prefix']: |
| 154 | raise ValueError(f'coin_type not {chainparams["bip173_prefix"]}: {mv}') |
| 155 | # chain moves should have blockheights |
| 156 | if mv['type'] == 'chain_mvt' and mv['account_id'] != 'external' and 'blockheight' not in mv: |
| 157 | raise ValueError(f'blockheight not set: {mv}') |
| 158 | |
| 159 | for num, m in enumerate(expected_moves): |
| 160 | # They can group things which are in any order. |
| 161 | if isinstance(m, list): |
| 162 | number_moves = len(m) |
| 163 | for acct_move in acct_moves[:number_moves]: |
| 164 | found = None |
| 165 | for i in range(len(m)): |
| 166 | if move_matches(m[i], acct_move): |
| 167 | found = i |
| 168 | break |
| 169 | if found is None: |
| 170 | raise ValueError("Unexpected move {} amongst {}".format(acct_move, m)) |
| 171 | del m[i] |
| 172 | acct_moves = acct_moves[number_moves:] |
| 173 | else: |
| 174 | if not move_matches(m, acct_moves[0]): |
| 175 | raise ValueError("Unexpected move {}: {} != {}".format(num, acct_moves[0], m)) |
| 176 | acct_moves = acct_moves[1:] |