Cleaner send_transaction flow and more wallet rpc testing

This commit is contained in:
Mariano Sorgente 2020-09-11 17:26:25 +09:00 committed by Gene Hoffman
parent 9ed6949099
commit b791bf1da8
18 changed files with 243 additions and 242 deletions

View File

@ -25,12 +25,14 @@ proofs of space during testing. The next time tests are run, this won't be neces
```bash ```bash
. ./activate . ./activate
pip install -r requirements-dev.txt pip install -r requirements-dev.txt
black src tests && flake8 src --exclude src/wallet/electron/node_modules && mypy src tests black src tests && flake8 src tests && mypy src tests
py.test tests -s -v py.test tests -s -v --durations 0
``` ```
Black is used as an automatic style formatter to make things easier, and flake8 helps ensure consistent style. Black is used as an automatic style formatter to make things easier, and flake8 helps ensure consistent style.
Mypy is very useful for ensuring objects are of the correct type, so try to always add the type of the return value, and the type of local variables. Mypy is very useful for ensuring objects are of the correct type, so try to always add the type of the return value, and the type of local variables.
If you want verbose logging for tests, edit the tests/pytest.ini file.
## Configure VS code ## Configure VS code
1. Install Python extension 1. Install Python extension
2. Set the environment to ./venv/bin/python 2. Set the environment to ./venv/bin/python

View File

@ -1,5 +1,5 @@
import { import {
get_puzzle_hash, get_address,
format_message, format_message,
incomingMessage, incomingMessage,
get_balance_for_wallet, get_balance_for_wallet,
@ -201,7 +201,7 @@ export const handle_message = (store, payload) => {
store.dispatch(get_balance_for_wallet(wallet.id)); store.dispatch(get_balance_for_wallet(wallet.id));
store.dispatch(get_transactions(wallet.id)); store.dispatch(get_transactions(wallet.id));
if (wallet.type === COLOURED_COIN || wallet.type === STANDARD_WALLET) { if (wallet.type === COLOURED_COIN || wallet.type === STANDARD_WALLET) {
store.dispatch(get_puzzle_hash(wallet.id)); store.dispatch(get_address(wallet.id));
} }
if (wallet.type === COLOURED_COIN) { if (wallet.type === COLOURED_COIN) {
store.dispatch(get_colour_name(wallet.id)); store.dispatch(get_colour_name(wallet.id));

View File

@ -11,15 +11,16 @@ export const Wallet = (id, name, type, data) => ({
balance_frozen: 0, balance_frozen: 0,
balance_change: 0, balance_change: 0,
transactions: [], transactions: [],
puzzle_hash: "", address: "",
colour: "", colour: "",
sending_transaction: false,
send_transaction_result: "" send_transaction_result: ""
}); });
export const Transaction = ( export const Transaction = (
confirmed_at_index, confirmed_at_index,
created_at_time, created_at_time,
to_puzzle_hash, to_address,
amount, amount,
fee_amount, fee_amount,
incoming, incoming,
@ -32,7 +33,7 @@ export const Transaction = (
) => ({ ) => ({
confirmed_at_index: confirmed_at_index, confirmed_at_index: confirmed_at_index,
created_at_time: created_at_time, created_at_time: created_at_time,
to_puzzle_hash: to_puzzle_hash, to_address: to_address,
amount: amount, amount: amount,
fee_amount: fee_amount, fee_amount: fee_amount,
incoming: incoming, incoming: incoming,
@ -58,7 +59,6 @@ const initial_state = {
connection_count: 0, connection_count: 0,
syncing: false syncing: false
}, },
sending_transaction: false,
show_create_backup: false show_create_backup: false
}; };
@ -87,20 +87,24 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
}; };
case "CLEAR_SEND": case "CLEAR_SEND":
id = action.message.data.wallet_id;
wallet = state.wallets[parseInt(id)];
wallet.sending_transaction = false;
wallet.send_transaction_result = null;
return { return {
...state, ...state,
sending_transaction: false,
send_transaction_result: null
}; };
case "OUTGOING_MESSAGE": case "OUTGOING_MESSAGE":
if ( if (
action.message.command === "send_transaction" || action.message.command === "send_transaction" ||
action.message.command === "cc_spend" action.message.command === "cc_spend"
) { ) {
id = action.message.data.wallet_id;
wallet = state.wallets[parseInt(id)];
wallet.sending_transaction = false;
wallet.send_transaction_result = null;
return { return {
...state, ...state,
sending_transaction: true,
send_transaction_result: null
}; };
} }
return state; return state;
@ -190,15 +194,15 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
wallet.transactions = transactions.reverse(); wallet.transactions = transactions.reverse();
return { ...state }; return { ...state };
} }
} else if (command === "get_next_puzzle_hash") { } else if (command === "get_next_address") {
id = data.wallet_id; id = data.wallet_id;
var puzzle_hash = data.puzzle_hash; var address = data.address;
wallets = state.wallets; wallets = state.wallets;
wallet = wallets[parseInt(id)]; wallet = wallets[parseInt(id)];
if (!wallet) { if (!wallet) {
return state; return state;
} }
wallet.puzzle_hash = puzzle_hash; wallet.address = address;
return { ...state }; return { ...state };
} else if (command === "get_connections") { } else if (command === "get_connections") {
if (data.success || data.connections) { if (data.success || data.connections) {
@ -241,12 +245,12 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
wallet.name = name; wallet.name = name;
return { ...state }; return { ...state };
} }
if (command === "send_transaction" || command === "cc_spend") { if (command === "tx_update") {
state["sending_transaction"] = false;
const id = data.id; const id = data.id;
wallets = state.wallets; wallets = state.wallets;
wallet = wallets[parseInt(id)]; wallet = wallets[parseInt(id)];
wallet.send_transaction_result = message.data; wallet.sending_transaction = false;
wallet.send_transaction_result = message.data.additional_data;
return { ...state }; return { ...state };
} }
return state; return state;

View File

@ -102,14 +102,18 @@ export const get_balance_for_wallet = id => {
return action; return action;
}; };
export const send_transaction = (wallet_id, amount, fee, puzzle_hash) => { export const send_transaction = (wallet_id, amount, fee, address) => {
var action = walletMessage(); var action = walletMessage();
action.message.command = "send_transaction"; action.message.command = "send_transaction";
action.message.data = { action.message.data = {
wallet_id: wallet_id, wallet_id: wallet_id,
amount: amount, amount: amount,
fee: fee, fee: fee,
<<<<<<< HEAD
puzzle_hash: puzzle_hash puzzle_hash: puzzle_hash
=======
address: address,
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
}; };
return action; return action;
}; };
@ -132,8 +136,29 @@ export const add_key = (mnemonic, type, file_path) => {
return action; return action;
}; };
<<<<<<< HEAD
export const add_new_key_action = mnemonic => { export const add_new_key_action = mnemonic => {
return dispatch => { return dispatch => {
=======
export const send_transaction_and_wait = (wallet_id, amount, fee, address) => {
return (dispatch) => {
try {
response = await async_api(dispatch, send_transaction(wallet_id, amount, fee, address), False);
if (!response.data.success) {
// Do something bad
return;
}
// Do something good
} catch (err) {
// Do something bad
return;
}
}
}
export const add_new_key_action = (mnemonic) => {
return (dispatch) => {
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
return async_api( return async_api(
dispatch, dispatch,
add_key(mnemonic, "new_wallet", null), add_key(mnemonic, "new_wallet", null),
@ -388,17 +413,25 @@ export const get_transactions = wallet_id => {
return action; return action;
}; };
<<<<<<< HEAD
export const get_puzzle_hash = wallet_id => { export const get_puzzle_hash = wallet_id => {
=======
export const get_address = (wallet_id) => {
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
var action = walletMessage(); var action = walletMessage();
action.message.command = "get_next_puzzle_hash"; action.message.command = "get_next_address";
action.message.data = { wallet_id: wallet_id }; action.message.data = { wallet_id: wallet_id };
return action; return action;
}; };
<<<<<<< HEAD
export const farm_block = puzzle_hash => { export const farm_block = puzzle_hash => {
=======
export const farm_block = (address) => {
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
var action = walletMessage(); var action = walletMessage();
action.message.command = "farm_block"; action.message.command = "farm_block";
action.message.data = { puzzle_hash: puzzle_hash }; action.message.data = { address: address };
return action; return action;
}; };
@ -536,12 +569,12 @@ export const rename_cc_wallet = (wallet_id, name) => {
return action; return action;
}; };
export const cc_spend = (wallet_id, puzzle_hash, amount, fee) => { export const cc_spend = (wallet_id, address, amount, fee) => {
var action = walletMessage(); var action = walletMessage();
action.message.command = "cc_spend"; action.message.command = "cc_spend";
action.message.data = { action.message.data = {
wallet_id: wallet_id, wallet_id: wallet_id,
innerpuzhash: puzzle_hash, inner_address: address,
amount: amount, amount: amount,
fee: fee fee: fee
}; };

View File

@ -16,7 +16,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead"; import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import { import {
get_puzzle_hash, get_address,
cc_spend, cc_spend,
farm_block, farm_block,
rename_cc_wallet rename_cc_wallet
@ -29,6 +29,7 @@ import {
import { unix_to_short_date } from "../util/utils"; import { unix_to_short_date } from "../util/utils";
import Accordion from "../components/Accordion"; import Accordion from "../components/Accordion";
import { openDialog } from "../modules/dialogReducer"; import { openDialog } from "../modules/dialogReducer";
import { get_transaction_result } from "../util/transaction_result";
const config = require("../config"); const config = require("../config");
const drawerWidth = 240; const drawerWidth = 240;
@ -417,7 +418,7 @@ const SendCard = props => {
const cc_unit = get_cc_unit(name); const cc_unit = get_cc_unit(name);
const sending_transaction = useSelector( const sending_transaction = useSelector(
state => state.wallet_state.sending_transaction state => state.wallet_state.wallets[id].sending_transaction
); );
const send_transaction_result = useSelector( const send_transaction_result = useSelector(
@ -426,21 +427,9 @@ const SendCard = props => {
const colour = useSelector(state => state.wallet_state.wallets[id].colour); const colour = useSelector(state => state.wallet_state.wallets[id].colour);
let result_message = ""; result = get_transaction_result(send_transaction_result);
let result_class = classes.resultSuccess; let result_message = result.message;
if (send_transaction_result) { let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
if (send_transaction_result.status === "SUCCESS") {
result_message =
"Transaction has successfully been sent to a full node and included in the mempool.";
} else if (send_transaction_result.status === "PENDING") {
result_message =
"Transaction has sent to a full node and is pending inclusion into the mempool. " +
send_transaction_result.reason;
} else {
result_message = "Transaction failed. " + send_transaction_result.reason;
result_class = classes.resultFailure;
}
}
function farm() { function farm() {
var address = address_input.value; var address = address_input.value;
@ -453,7 +442,7 @@ const SendCard = props => {
if (sending_transaction) { if (sending_transaction) {
return; return;
} }
let puzzle_hash = address_input.value.trim(); let address = address_input.value.trim();
if ( if (
amount_input.value === "" || amount_input.value === "" ||
Number(amount_input.value) === 0 || Number(amount_input.value) === 0 ||
@ -472,8 +461,8 @@ const SendCard = props => {
const fee = colouredcoin_to_mojo(fee_input.value); const fee = colouredcoin_to_mojo(fee_input.value);
if ( if (
puzzle_hash.includes("chia_addr") || address.includes("chia_addr") ||
puzzle_hash.includes("colour_desc") address.includes("colour_desc")
) { ) {
dispatch( dispatch(
openDialog( openDialog(
@ -482,9 +471,9 @@ const SendCard = props => {
); );
return; return;
} }
if (puzzle_hash.substring(0, 14) === "colour_addr://") { if (address.substring(0, 14) === "colour_addr://") {
const colour_id = puzzle_hash.substring(14, 78); const colour_id = address.substring(14, 78);
puzzle_hash = puzzle_hash.substring(79); address = address.substring(79);
if (colour_id !== colour) { if (colour_id !== colour) {
dispatch( dispatch(
openDialog( openDialog(
@ -495,14 +484,14 @@ const SendCard = props => {
} }
} }
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) { if (address.startsWith("0x") || address.startsWith("0X")) {
puzzle_hash = puzzle_hash.substring(2); address = address.substring(2);
} }
const amount_value = parseFloat(Number(amount)); const amount_value = parseFloat(Number(amount));
const fee_value = parseFloat(Number(fee)); const fee_value = parseFloat(Number(fee));
dispatch(cc_spend(id, puzzle_hash, amount_value, fee_value)); dispatch(cc_spend(id, address, amount_value, fee_value));
address_input.value = ""; address_input.value = "";
amount_input.value = ""; amount_input.value = "";
} }
@ -669,7 +658,7 @@ const TransactionTable = props => {
{transactions.map(tx => ( {transactions.map(tx => (
<TableRow <TableRow
className={classes.row} className={classes.row}
key={tx.to_puzzle_hash + tx.created_at_time + tx.amount} key={tx.to_address + tx.created_at_time + tx.amount}
> >
<TableCell className={classes.cell_short}> <TableCell className={classes.cell_short}>
{incoming_string(tx.incoming)} {incoming_string(tx.incoming)}
@ -678,7 +667,7 @@ const TransactionTable = props => {
style={{ maxWidth: "150px" }} style={{ maxWidth: "150px" }}
className={classes.cell_short} className={classes.cell_short}
> >
{tx.to_puzzle_hash} {tx.to_address}
</TableCell> </TableCell>
<TableCell className={classes.cell_short}> <TableCell className={classes.cell_short}>
{unix_to_short_date(tx.created_at_time)} {unix_to_short_date(tx.created_at_time)}
@ -702,18 +691,18 @@ const TransactionTable = props => {
const AddressCard = props => { const AddressCard = props => {
var id = props.wallet_id; var id = props.wallet_id;
const puzzle_hash = useSelector( const address = useSelector(
state => state.wallet_state.wallets[id].puzzle_hash state => state.wallet_state.wallets[id].address
); );
const classes = useStyles(); const classes = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();
function newAddress() { function newAddress() {
dispatch(get_puzzle_hash(id)); dispatch(get_address(id));
} }
function copy() { function copy() {
navigator.clipboard.writeText(puzzle_hash); navigator.clipboard.writeText(address);
} }
return ( return (
@ -734,7 +723,7 @@ const AddressCard = props => {
disabled disabled
fullWidth fullWidth
label="Address" label="Address"
value={puzzle_hash} value={address}
variant="outlined" variant="outlined"
/> />
</Box> </Box>

View File

@ -643,34 +643,22 @@ const SendCard = props => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const sending_transaction = useSelector( const sending_transaction = useSelector(
state => state.wallet_state.sending_transaction state => state.wallet_state.wallets[id].sending_transaction
); );
const send_transaction_result = useSelector( const send_transaction_result = useSelector(
state => state.wallet_state.wallets[id].send_transaction_result state => state.wallet_state.wallets[id].send_transaction_result
); );
let result_message = ""; result = get_transaction_result(send_transaction_result);
let result_class = classes.resultSuccess; let result_message = result.message;
if (send_transaction_result) { let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
if (send_transaction_result.status === "SUCCESS") {
result_message =
"Transaction has successfully been sent to a full node and included in the mempool.";
} else if (send_transaction_result.status === "PENDING") {
result_message =
"Transaction has sent to a full node and is pending inclusion into the mempool. " +
send_transaction_result.reason;
} else {
result_message = "Transaction failed. " + send_transaction_result.reason;
result_class = classes.resultFailure;
}
}
function send() { function send() {
if (sending_transaction) { if (sending_transaction) {
return; return;
} }
let puzzle_hash = address_input.value.trim(); let address = address_input.value.trim();
if ( if (
amount_input.value === "" || amount_input.value === "" ||
Number(amount_input.value) === 0 || Number(amount_input.value) === 0 ||
@ -687,14 +675,14 @@ const SendCard = props => {
const amount = chia_to_mojo(amount_input.value); const amount = chia_to_mojo(amount_input.value);
const fee = chia_to_mojo(fee_input.value); const fee = chia_to_mojo(fee_input.value);
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) { if (address.startsWith("0x") || address.startsWith("0X")) {
puzzle_hash = puzzle_hash.substring(2); address = address.substring(2);
} }
const amount_value = parseFloat(Number(amount)); const amount_value = parseFloat(Number(amount));
const fee_value = parseFloat(Number(fee)); const fee_value = parseFloat(Number(fee));
dispatch(send_transaction(id, amount_value, fee_value, puzzle_hash)); dispatch(send_transaction(id, amount_value, fee_value, address));
address_input.value = ""; address_input.value = "";
amount_input.value = ""; amount_input.value = "";
fee_input.value = ""; fee_input.value = "";
@ -898,7 +886,7 @@ const TransactionTable = props => {
{transactions.map(tx => ( {transactions.map(tx => (
<TableRow <TableRow
className={classes.row} className={classes.row}
key={tx.to_puzzle_hash + tx.created_at_time + tx.amount} key={tx.to_address + tx.created_at_time + tx.amount}
> >
<TableCell className={classes.cell_short}> <TableCell className={classes.cell_short}>
{incoming_string(tx.incoming)} {incoming_string(tx.incoming)}
@ -907,7 +895,7 @@ const TransactionTable = props => {
style={{ maxWidth: "150px" }} style={{ maxWidth: "150px" }}
className={classes.cell_short} className={classes.cell_short}
> >
{tx.to_puzzle_hash} {tx.to_address}
</TableCell> </TableCell>
<TableCell className={classes.cell_short}> <TableCell className={classes.cell_short}>
{unix_to_short_date(tx.created_at_time)} {unix_to_short_date(tx.created_at_time)}

View File

@ -15,7 +15,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead"; import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import { import {
get_puzzle_hash, get_address,
send_transaction, send_transaction,
farm_block farm_block
} from "../modules/message"; } from "../modules/message";
@ -326,27 +326,16 @@ const SendCard = props => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const sending_transaction = useSelector( const sending_transaction = useSelector(
state => state.wallet_state.sending_transaction state => state.wallet_state.wallets[id].sending_transaction
); );
const send_transaction_result = useSelector( const send_transaction_result = useSelector(
state => state.wallet_state.wallets[id].send_transaction_result state => state.wallet_state.wallets[id].send_transaction_result
); );
let result_message = "";
let result_class = classes.resultSuccess; result = get_transaction_result(send_transaction_result);
if (send_transaction_result) { let result_message = result.message;
if (send_transaction_result.status === "SUCCESS") { let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
result_message =
"Transaction has successfully been sent to a full node and included in the mempool.";
} else if (send_transaction_result.status === "PENDING") {
result_message =
"Transaction has sent to a full node and is pending inclusion into the mempool. " +
send_transaction_result.reason;
} else {
result_message = "Transaction failed. " + send_transaction_result.reason;
result_class = classes.resultFailure;
}
}
function farm() { function farm() {
var address = address_input.value; var address = address_input.value;
@ -359,7 +348,7 @@ const SendCard = props => {
if (sending_transaction) { if (sending_transaction) {
return; return;
} }
let puzzle_hash = address_input.value.trim(); let address = address_input.value.trim();
if ( if (
amount_input.value === "" || amount_input.value === "" ||
Number(amount_input.value) === 0 || Number(amount_input.value) === 0 ||
@ -376,24 +365,24 @@ const SendCard = props => {
const amount = chia_to_mojo(amount_input.value); const amount = chia_to_mojo(amount_input.value);
const fee = chia_to_mojo(fee_input.value); const fee = chia_to_mojo(fee_input.value);
if (puzzle_hash.includes("colour")) { if (address.includes("colour")) {
dispatch( dispatch(
openDialog( openDialog(
"Error: Cannot send chia to coloured address. Please enter a chia address." "Error: Cannot send chia to coloured address. Please enter a chia address."
) )
); );
return; return;
} else if (puzzle_hash.substring(0, 12) === "chia_addr://") { } else if (address.substring(0, 12) === "chia_addr://") {
puzzle_hash = puzzle_hash.substring(12); address = address.substring(12);
} }
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) { if (address.startsWith("0x") || address.startsWith("0X")) {
puzzle_hash = puzzle_hash.substring(2); address = address.substring(2);
} }
const amount_value = parseFloat(Number(amount)); const amount_value = parseFloat(Number(amount));
const fee_value = parseFloat(Number(fee)); const fee_value = parseFloat(Number(fee));
dispatch(send_transaction(id, amount_value, fee_value, puzzle_hash)); dispatch(send_transaction(id, amount_value, fee_value, address));
address_input.value = ""; address_input.value = "";
amount_input.value = ""; amount_input.value = "";
fee_input.value = ""; fee_input.value = "";
@ -565,7 +554,7 @@ const TransactionTable = props => {
<TableRow <TableRow
className={classes.row} className={classes.row}
key={ key={
tx.to_puzzle_hash + tx.to_address +
tx.created_at_time + tx.created_at_time +
tx.amount + tx.amount +
(tx.removals.length > 0 ? tx.removals[0].parent_coin_info : "") (tx.removals.length > 0 ? tx.removals[0].parent_coin_info : "")
@ -578,7 +567,7 @@ const TransactionTable = props => {
style={{ maxWidth: "150px" }} style={{ maxWidth: "150px" }}
className={classes.cell_short} className={classes.cell_short}
> >
{tx.to_puzzle_hash} {tx.to_address}
</TableCell> </TableCell>
<TableCell className={classes.cell_short}> <TableCell className={classes.cell_short}>
{unix_to_short_date(tx.created_at_time)} {unix_to_short_date(tx.created_at_time)}
@ -602,18 +591,18 @@ const TransactionTable = props => {
const AddressCard = props => { const AddressCard = props => {
var id = props.wallet_id; var id = props.wallet_id;
const puzzle_hash = useSelector( const address = useSelector(
state => state.wallet_state.wallets[id].puzzle_hash state => state.wallet_state.wallets[id].address
); );
const classes = useStyles(); const classes = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();
function newAddress() { function newAddress() {
dispatch(get_puzzle_hash(id)); dispatch(get_address(id));
} }
function copy() { function copy() {
navigator.clipboard.writeText(puzzle_hash); navigator.clipboard.writeText(address);
} }
return ( return (
@ -634,7 +623,7 @@ const AddressCard = props => {
disabled disabled
fullWidth fullWidth
label="Address" label="Address"
value={puzzle_hash} value={address}
variant="outlined" variant="outlined"
/> />
</Box> </Box>

View File

@ -0,0 +1,37 @@
const mempool_inclusion_status = {
"SUCCESS": 1, // Transaction added to mempool
"PENDING": 2, // Transaction not yet added to mempool
"FAILED": 3, // Transaction was invalid and dropped
}
function get_transaction_result(transaction) {
let success = true;
let message = "The transaction result was received";
for (let full_node_response of transaction.transaction.sent_to) {
console.log("full node response", full_node_response);
}
// if (send_transaction_result) {
// if (send_transaction_result.status === "SUCCESS") {
// result_message =
// "Transaction has successfully been sent to a full node and included in the mempool.";
// } else if (send_transaction_result.status === "PENDING") {
// result_message =
// "Transaction has sent to a full node and is pending inclusion into the mempool. " +
// send_transaction_result.reason;
// } else {
// result_message = "Transaction failed. " + send_transaction_result.reason;
// result_class = classes.resultFailure;
// }
// }
return {
message,
success
}
}
module.exports = {
mempool_inclusion_status,
get_transaction_result,
}

View File

@ -23,6 +23,7 @@ import yaml
from src.ssl.create_ssl import generate_selfsigned_cert from src.ssl.create_ssl import generate_selfsigned_cert
from src.wallet.derive_keys import master_sk_to_wallet_sk, master_sk_to_pool_sk from src.wallet.derive_keys import master_sk_to_wallet_sk, master_sk_to_pool_sk
from src.util.chech32 import encode_puzzle_hash
def make_parser(parser: ArgumentParser): def make_parser(parser: ArgumentParser):
@ -54,50 +55,50 @@ def check_keys(new_root):
config: Dict = load_config(new_root, "config.yaml") config: Dict = load_config(new_root, "config.yaml")
pool_child_pubkeys = [master_sk_to_pool_sk(sk).get_g1() for sk, _ in all_sks] pool_child_pubkeys = [master_sk_to_pool_sk(sk).get_g1() for sk, _ in all_sks]
all_targets = [] all_targets = []
stop_searching_for_farmer = "xch_target_puzzle_hash" not in config["farmer"] stop_searching_for_farmer = "xch_target_address" not in config["farmer"]
stop_searching_for_pool = "xch_target_puzzle_hash" not in config["pool"] stop_searching_for_pool = "xch_target_address" not in config["pool"]
for i in range(500): for i in range(500):
if stop_searching_for_farmer and stop_searching_for_pool and i > 0: if stop_searching_for_farmer and stop_searching_for_pool and i > 0:
break break
for sk, _ in all_sks: for sk, _ in all_sks:
all_targets.append( all_targets.append(
create_puzzlehash_for_pk( encode_puzzle_hash(create_puzzlehash_for_pk(
master_sk_to_wallet_sk(sk, uint32(i)).get_g1() master_sk_to_wallet_sk(sk, uint32(i)).get_g1()
).hex() ))
) )
if all_targets[-1] == config["farmer"].get("xch_target_puzzle_hash"): if all_targets[-1] == config["farmer"].get("xch_target_address"):
stop_searching_for_farmer = True stop_searching_for_farmer = True
if all_targets[-1] == config["pool"].get("xch_target_puzzle_hash"): if all_targets[-1] == config["pool"].get("xch_target_address"):
stop_searching_for_pool = True stop_searching_for_pool = True
# Set the destinations # Set the destinations
if "xch_target_puzzle_hash" not in config["farmer"]: if "xch_target_address" not in config["farmer"]:
print( print(
f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}" f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}"
) )
config["farmer"]["xch_target_puzzle_hash"] = all_targets[0] config["farmer"]["xch_target_address"] = all_targets[0]
elif config["farmer"]["xch_target_puzzle_hash"] not in all_targets: elif config["farmer"]["xch_target_address"] not in all_targets:
print( print(
f"WARNING: farmer using a puzzle hash which we don't have the private" f"WARNING: farmer using a puzzle hash which we don't have the private"
f" keys for. Overriding " f" keys for. Overriding "
f"{config['farmer']['xch_target_puzzle_hash']} with {all_targets[0]}" f"{config['farmer']['xch_target_address']} with {all_targets[0]}"
) )
config["farmer"]["xch_target_puzzle_hash"] = all_targets[0] config["farmer"]["xch_target_address"] = all_targets[0]
if "pool" not in config: if "pool" not in config:
config["pool"] = {} config["pool"] = {}
if "xch_target_puzzle_hash" not in config["pool"]: if "xch_target_address" not in config["pool"]:
print( print(
f"Setting the xch destination address for coinbase reward to {all_targets[0]}" f"Setting the xch destination address for coinbase reward to {all_targets[0]}"
) )
config["pool"]["xch_target_puzzle_hash"] = all_targets[0] config["pool"]["xch_target_address"] = all_targets[0]
elif config["pool"]["xch_target_puzzle_hash"] not in all_targets: elif config["pool"]["xch_target_address"] not in all_targets:
print( print(
f"WARNING: pool using a puzzle hash which we don't have the private" f"WARNING: pool using a puzzle hash which we don't have the private"
f" keys for. Overriding " f" keys for. Overriding "
f"{config['pool']['xch_target_puzzle_hash']} with {all_targets[0]}" f"{config['pool']['xch_target_address']} with {all_targets[0]}"
) )
config["pool"]["xch_target_puzzle_hash"] = all_targets[0] config["pool"]["xch_target_address"] = all_targets[0]
# Set the pool pks in the farmer # Set the pool pks in the farmer
pool_pubkeys_hex = set(bytes(pk).hex() for pk in pool_child_pubkeys) pool_pubkeys_hex = set(bytes(pk).hex() for pk in pool_child_pubkeys)

View File

@ -15,6 +15,7 @@ from src.util.config import load_config
from src.util.default_root import DEFAULT_ROOT_PATH from src.util.default_root import DEFAULT_ROOT_PATH
from src.wallet.util.wallet_types import WalletType from src.wallet.util.wallet_types import WalletType
from src.cmds.units import units from src.cmds.units import units
from src.util.chech32 import encode_puzzle_hash
def make_parser(parser): def make_parser(parser):
@ -304,9 +305,9 @@ async def show_async(args, parser):
f"Tx Filter Hash {b'block.transactions_filter'.hex()}\n" f"Tx Filter Hash {b'block.transactions_filter'.hex()}\n"
f"Tx Generator Hash {block.transactions_generator}\n" f"Tx Generator Hash {block.transactions_generator}\n"
f"Coinbase Amount {block.get_coinbase().amount/1000000000000}\n" f"Coinbase Amount {block.get_coinbase().amount/1000000000000}\n"
f"Coinbase Puzzle Hash 0x{block.get_coinbase().puzzle_hash}\n" f"Coinbase Address {encode_puzzle_hash(block.get_coinbase().puzzle_hash)}\n"
f"Fees Amount {block.get_fees_coin().amount/1000000000000}\n" f"Fees Amount {block.get_fees_coin().amount/1000000000000}\n"
f"Fees Puzzle Hash 0x{block.get_fees_coin().puzzle_hash}\n" f"Fees Address {encode_puzzle_hash(block.get_fees_coin().puzzle_hash)}\n"
f"Aggregated Signature {aggregated_signature}" f"Aggregated Signature {aggregated_signature}"
) )
else: else:

View File

@ -16,6 +16,7 @@ from src.types.pool_target import PoolTarget
from src.util.api_decorators import api_request from src.util.api_decorators import api_request
from src.util.ints import uint32, uint64, uint128, uint8 from src.util.ints import uint32, uint64, uint128, uint8
from src.wallet.derive_keys import master_sk_to_farmer_sk, master_sk_to_pool_sk from src.wallet.derive_keys import master_sk_to_farmer_sk, master_sk_to_pool_sk
from src.util.chech32 import decode_puzzle_hash
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -57,14 +58,14 @@ class Farmer:
raise RuntimeError(error_str) raise RuntimeError(error_str)
# This is the farmer configuration # This is the farmer configuration
self.wallet_target = bytes.fromhex(self.config["xch_target_puzzle_hash"]) self.wallet_target = decode_puzzle_hash(bytes.fromhex(self.config["xch_target_address"]))
self.pool_public_keys = [ self.pool_public_keys = [
G1Element.from_bytes(bytes.fromhex(pk)) G1Element.from_bytes(bytes.fromhex(pk))
for pk in self.config["pool_public_keys"] for pk in self.config["pool_public_keys"]
] ]
# This is the pool configuration, which should be moved out to the pool once it exists # This is the pool configuration, which should be moved out to the pool once it exists
self.pool_target = bytes.fromhex(pool_config["xch_target_puzzle_hash"]) self.pool_target = decode_puzzle_hash(bytes.fromhex(pool_config["xch_target_address"]))
self.pool_sks_map: Dict = {} self.pool_sks_map: Dict = {}
for key in self._get_private_keys(): for key in self._get_private_keys():
self.pool_sks_map[bytes(key.get_g1())] = key self.pool_sks_map[bytes(key.get_g1())] = key

View File

@ -560,7 +560,7 @@ class FullNode:
if self.mempool_manager.seen(transaction.transaction_id): if self.mempool_manager.seen(transaction.transaction_id):
return return
elif self.mempool_manager.is_fee_enough(transaction.fees, transaction.cost): if self.mempool_manager.is_fee_enough(transaction.fees, transaction.cost):
requestTX = full_node_protocol.RequestTransaction( requestTX = full_node_protocol.RequestTransaction(
transaction.transaction_id transaction.transaction_id
) )
@ -613,10 +613,12 @@ class FullNode:
# Ignore if we have already added this transaction # Ignore if we have already added this transaction
if self.mempool_manager.get_spendbundle(tx.transaction.name()) is not None: if self.mempool_manager.get_spendbundle(tx.transaction.name()) is not None:
return return
self.log.warning(f"Adding transaction to mempool: {transaction.transaction_id}")
cost, status, error = await self.mempool_manager.add_spendbundle( cost, status, error = await self.mempool_manager.add_spendbundle(
tx.transaction tx.transaction
) )
if status == MempoolInclusionStatus.SUCCESS: if status == MempoolInclusionStatus.SUCCESS:
self.log.warning(f"Added transaction to mempool: {transaction.transaction_id}")
fees = tx.transaction.fees() fees = tx.transaction.fees()
assert fees >= 0 assert fees >= 0
assert cost is not None assert cost is not None
@ -1823,6 +1825,7 @@ class FullNode:
tx.transaction tx.transaction
) )
if status == MempoolInclusionStatus.SUCCESS: if status == MempoolInclusionStatus.SUCCESS:
self.log.info(f"Added transaction to mempool: {tx.transaction.name()}")
# Only broadcast successful transactions, not pending ones. Otherwise it's a DOS # Only broadcast successful transactions, not pending ones. Otherwise it's a DOS
# vector. # vector.
fees = tx.transaction.fees() fees = tx.transaction.fees()

View File

@ -45,7 +45,12 @@ class WalletRpcApi:
return { return {
"/get_wallet_balance": self.get_wallet_balance, "/get_wallet_balance": self.get_wallet_balance,
"/send_transaction": self.send_transaction, "/send_transaction": self.send_transaction,
<<<<<<< HEAD
"/get_next_puzzle_hash": self.get_next_puzzle_hash, "/get_next_puzzle_hash": self.get_next_puzzle_hash,
=======
"/get_next_address": self.get_next_address,
"/get_transaction": self.get_transaction,
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
"/get_transactions": self.get_transactions, "/get_transactions": self.get_transactions,
"/farm_block": self.farm_block, "/farm_block": self.farm_block,
"/get_sync_status": self.get_sync_status, "/get_sync_status": self.get_sync_status,
@ -155,18 +160,18 @@ class WalletRpcApi:
if len(args) < 2: if len(args) < 2:
return [] return []
change = args[0]
wallet_id = args[1]
data = { data = {
"state": change, "state": args[0],
} }
if wallet_id is not None: if args[1] is not None:
data["wallet_id"] = wallet_id data["wallet_id"] = args[1]
if args[2] is not None:
data["additional_data"] = args[2]
return [create_payload("state_changed", data, "chia_wallet", "wallet_ui")] return [create_payload("state_changed", data, "chia_wallet", "wallet_ui")]
async def get_next_puzzle_hash(self, request: Dict) -> Dict: async def get_next_address(self, request: Dict) -> Dict:
""" """
Returns a new puzzlehash Returns a new address
""" """
if self.service is None: if self.service is None:
return {"success": False} return {"success": False}
@ -178,10 +183,10 @@ class WalletRpcApi:
if wallet.wallet_info.type == WalletType.STANDARD_WALLET.value: if wallet.wallet_info.type == WalletType.STANDARD_WALLET.value:
raw_puzzle_hash = await wallet.get_new_puzzlehash() raw_puzzle_hash = await wallet.get_new_puzzlehash()
puzzle_hash = encode_puzzle_hash(raw_puzzle_hash) address = encode_puzzle_hash(raw_puzzle_hash)
elif wallet.wallet_info.type == WalletType.COLOURED_COIN.value: elif wallet.wallet_info.type == WalletType.COLOURED_COIN.value:
raw_puzzle_hash = await wallet.get_new_inner_hash() raw_puzzle_hash = await wallet.get_new_inner_hash()
puzzle_hash = encode_puzzle_hash(raw_puzzle_hash) address = encode_puzzle_hash(raw_puzzle_hash)
else: else:
return { return {
"success": False, "success": False,
@ -191,13 +196,12 @@ class WalletRpcApi:
response = { response = {
"success": True, "success": True,
"wallet_id": wallet_id, "wallet_id": wallet_id,
"puzzle_hash": puzzle_hash, "address": address,
} }
return response return response
async def send_transaction(self, request): async def send_transaction(self, request):
log.debug("rpc_api request: " + str(request))
wallet_id = int(request["wallet_id"]) wallet_id = int(request["wallet_id"])
wallet = self.service.wallet_state_manager.wallets[wallet_id] wallet = self.service.wallet_state_manager.wallets[wallet_id]
try: try:
@ -270,7 +274,7 @@ class WalletRpcApi:
for tx in transactions: for tx in transactions:
formatted = tx.to_json_dict() formatted = tx.to_json_dict()
formatted["to_puzzle_hash"] = encode_puzzle_hash(tx.to_puzzle_hash) formatted["to_address"] = encode_puzzle_hash(tx.to_address)
formatted_transactions.append(formatted) formatted_transactions.append(formatted)
response = { response = {
@ -462,7 +466,7 @@ class WalletRpcApi:
async def cc_spend(self, request): async def cc_spend(self, request):
wallet_id = int(request["wallet_id"]) wallet_id = int(request["wallet_id"])
wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id] wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id]
encoded_puzzle_hash = request["innerpuzhash"] encoded_puzzle_hash = request["inner_address"]
puzzle_hash = decode_puzzle_hash(encoded_puzzle_hash) puzzle_hash = decode_puzzle_hash(encoded_puzzle_hash)
try: try:
@ -475,7 +479,7 @@ class WalletRpcApi:
if tx is None: if tx is None:
data = { data = {
"status": "FAILED", "success": False,
"reason": "Failed to generate signed transaction", "reason": "Failed to generate signed transaction",
"id": wallet_id, "id": wallet_id,
} }
@ -484,46 +488,17 @@ class WalletRpcApi:
await wallet.wallet_state_manager.add_pending_transaction(tx) await wallet.wallet_state_manager.add_pending_transaction(tx)
except Exception as e: except Exception as e:
data = { data = {
"status": "FAILED", "success": False,
"reason": f"Failed to push transaction {e}", "reason": f"Failed to push transaction {e}",
"id": wallet_id,
} }
return data return data
sent = False return {
start = time.time() "success": True,
while time.time() - start < TIMEOUT: "transaction": tr,
sent_to: List[ "transaction_id": tr.spend_bundle.name(),
Tuple[str, MempoolInclusionStatus, Optional[str]] }
] = await self.service.wallet_state_manager.get_transaction_status(
tx.name()
)
if len(sent_to) == 0:
await asyncio.sleep(0.1)
continue
status, err = sent_to[0][1], sent_to[0][2]
if status == MempoolInclusionStatus.SUCCESS:
data = {"status": "SUCCESS", "id": wallet_id}
sent = True
break
elif status == MempoolInclusionStatus.PENDING:
assert err is not None
data = {"status": "PENDING", "reason": err, "id": wallet_id}
sent = True
break
elif status == MempoolInclusionStatus.FAILED:
assert err is not None
data = {"status": "FAILED", "reason": err, "id": wallet_id}
sent = True
break
if not sent:
data = {
"status": "FAILED",
"reason": "Timed out. Transaction may or may not have been sent.",
"id": wallet_id,
}
return data
async def cc_get_colour(self, request): async def cc_get_colour(self, request):
wallet_id = int(request["wallet_id"]) wallet_id = int(request["wallet_id"])
@ -818,13 +793,13 @@ class WalletRpcApi:
tx = await wallet.clawback_rl_coin_transaction() tx = await wallet.clawback_rl_coin_transaction()
except Exception as e: except Exception as e:
data = { data = {
"status": "FAILED", "success": False,
"reason": f"Failed to generate signed transaction {e}", "reason": f"Failed to generate signed transaction {e}",
} }
return data return data
if tx is None: if tx is None:
data = { data = {
"status": "FAILED", "success": False,
"reason": "Failed to generate signed transaction", "reason": "Failed to generate signed transaction",
} }
return data return data
@ -832,41 +807,14 @@ class WalletRpcApi:
await wallet.push_transaction(tx) await wallet.push_transaction(tx)
except Exception as e: except Exception as e:
data = { data = {
"status": "FAILED", "success": False,
"reason": f"Failed to push transaction {e}", "reason": f"Failed to push transaction {e}",
} }
return data return data
sent = False
start = time.time()
while time.time() - start < TIMEOUT:
sent_to: List[
Tuple[str, MempoolInclusionStatus, Optional[str]]
] = await self.service.wallet_state_manager.get_transaction_status(
tx.name()
)
if len(sent_to) == 0: # Transaction may not have been included in the mempool yet. Use get_transaction to check.
await asyncio.sleep(1) return {
continue "success": True,
status, err = sent_to[0][1], sent_to[0][2] "transaction": tx,
if status == MempoolInclusionStatus.SUCCESS: "transaction_id": tx.spend_bundle.name(),
data = {"status": "SUCCESS"} }
sent = True
break
elif status == MempoolInclusionStatus.PENDING:
assert err is not None
data = {"status": "PENDING", "reason": err}
sent = True
break
elif status == MempoolInclusionStatus.FAILED:
assert err is not None
data = {"status": "FAILED", "reason": err}
sent = True
break
if not sent:
data = {
"status": "FAILED",
"reason": "Timed out. Transaction may or may not have been sent.",
}
return data

View File

@ -36,6 +36,9 @@ class WalletRpcClient(RpcClient):
return TransactionRecord.from_json_dict(response["transaction"]) return TransactionRecord.from_json_dict(response["transaction"])
raise Exception(response["reason"]) raise Exception(response["reason"])
async def get_next_address(self, wallet_id: str) -> Dict:
return await self.fetch("get_next_address", {"wallet_id": wallet_id})
async def get_transaction( async def get_transaction(
self, wallet_id: str, transaction_id: bytes32 self, wallet_id: str, transaction_id: bytes32
) -> Optional[TransactionRecord]: ) -> Optional[TransactionRecord]:

View File

@ -32,7 +32,7 @@ harvester:
pool: { pool: {
# Replace this with a real puzzle hash # Replace this with a real puzzle hash
# xch_target_puzzle_hash: a4259182b4d8e0af21331fc5be2681f953400b6726fa4095e3b91ae8f005a836 # xch_target_address: txch102gkhhzs60grx7cfnpng5n6rjecr89r86l5s8xux2za8k820cxsq64ssdg
logging: *logging logging: *logging
} }
@ -50,7 +50,7 @@ farmer:
pool_public_keys: [] pool_public_keys: []
# Replace this with a real puzzle hash # Replace this with a real puzzle hash
# xch_target_puzzle_hash: a4259182b4d8e0af21331fc5be2681f953400b6726fa4095e3b91ae8f005a836 # xch_target_address: txch102gkhhzs60grx7cfnpng5n6rjecr89r86l5s8xux2za8k820cxsq64ssdg
# If True, starts an RPC server at the following port # If True, starts an RPC server at the following port
start_rpc_server: True start_rpc_server: True

View File

@ -319,7 +319,7 @@ class WalletStateManager:
continue continue
puzzlehash: bytes32 = puzzle.get_tree_hash() puzzlehash: bytes32 = puzzle.get_tree_hash()
self.log.info( self.log.info(
f"Puzzle at index {index} wid {wallet_id} puzzle hash {puzzlehash.hex()}" f"Puzzle at index {index} with {wallet_id} puzzle hash {puzzlehash.hex()}"
) )
derivation_paths.append( derivation_paths.append(
DerivationRecord( DerivationRecord(
@ -376,13 +376,13 @@ class WalletStateManager:
""" """
self.pending_tx_callback = callback self.pending_tx_callback = callback
def state_changed(self, state: str, wallet_id: int = None): def state_changed(self, state: str, wallet_id: int = None, data_object = {}):
""" """
Calls the callback if it's present. Calls the callback if it's present.
""" """
if self.state_changed_callback is None: if self.state_changed_callback is None:
return return
self.state_changed_callback(state, wallet_id) self.state_changed_callback(state, wallet_id, data_object)
def tx_pending_changed(self): def tx_pending_changed(self):
""" """
@ -698,7 +698,9 @@ class WalletStateManager:
Full node received our transaction, no need to keep it in queue anymore Full node received our transaction, no need to keep it in queue anymore
""" """
await self.tx_store.increment_sent(spendbundle_id, name, send_status, error) await self.tx_store.increment_sent(spendbundle_id, name, send_status, error)
self.state_changed("tx_sent") tx: Optional[TransactionRecord] = self.get_transaction(spendbundle_id)
if tx is not None:
self.state_changed("tx_update", tx.wallet_id, {"transaction": tx})
async def get_send_queue(self) -> List[TransactionRecord]: async def get_send_queue(self) -> List[TransactionRecord]:
""" """
@ -1541,13 +1543,3 @@ class WalletStateManager:
if callback_str is not None: if callback_str is not None:
callback = getattr(wallet, callback_str) callback = getattr(wallet, callback_str)
await callback(height, header_hash, program, action.id) await callback(height, header_hash, program, action.id)
async def get_transaction_status(
self, tx_id: bytes32
) -> List[Tuple[str, MempoolInclusionStatus, Optional[str]]]:
tr: Optional[TransactionRecord] = await self.get_transaction(tx_id)
ret_list = []
if tr is not None:
for (name, ss, err) in tr.sent_to:
ret_list.append((name, MempoolInclusionStatus(ss), err))
return ret_list

View File

@ -40,8 +40,9 @@ class TestWalletRpc:
wallet_node, server_2 = wallets[0] wallet_node, server_2 = wallets[0]
wallet_node_2, server_3 = wallets[1] wallet_node_2, server_3 = wallets[1]
wallet = wallet_node.wallet_state_manager.main_wallet wallet = wallet_node.wallet_state_manager.main_wallet
wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
ph = await wallet.get_new_puzzlehash() ph = await wallet.get_new_puzzlehash()
ph_2 = await wallet.get_new_puzzlehash() ph_2 = await wallet_2.get_new_puzzlehash()
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None) await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
@ -54,6 +55,12 @@ class TestWalletRpc:
for i in range(1, num_blocks - 1) for i in range(1, num_blocks - 1)
] ]
) )
initial_funds_eventually = sum(
[
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
for i in range(1, num_blocks + 1)
]
)
wallet_rpc_api = WalletRpcApi(wallet_node) wallet_rpc_api = WalletRpcApi(wallet_node)
@ -81,27 +88,29 @@ class TestWalletRpc:
addr = encode_puzzle_hash( addr = encode_puzzle_hash(
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash() await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
) )
tx = await client.send_transaction("1", 1, addr) tx_amount = 15600000
tx = await client.send_transaction("1", tx_amount, addr)
assert tx is not None assert tx is not None
transaction_id = tx.name() transaction_id = tx.name()
async def tx_in_mempool(): async def tx_in_mempool():
tx = await client.get_transaction("1", transaction_id) tx = await client.get_transaction("1", transaction_id)
return tx.is_in_mempool() return tx.is_in_mempool()
await time_out_assert(5, tx_in_mempool, True) await time_out_assert(5, tx_in_mempool, True)
await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds - 1) await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds - tx_amount)
assert (await client.get_wallet_balance("1"))["wallet_balance"]["unconfirmed_wallet_balance"] == initial_funds - 1 assert (await client.get_wallet_balance("1"))["wallet_balance"]["unconfirmed_wallet_balance"] == initial_funds - tx_amount
assert (await client.get_wallet_balance("1"))["wallet_balance"]["confirmed_wallet_balance"] == initial_funds assert (await client.get_wallet_balance("1"))["wallet_balance"]["confirmed_wallet_balance"] == initial_funds
for i in range(0, num_blocks * 5): for i in range(0, 5):
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph_2)) await full_node_1.farm_new_block(FarmNewBlockProtocol(ph_2))
assert (await client.get_wallet_balance("1"))["wallet_balance"]["confirmed_wallet_balance"] == initial_funds - 1 async def eventual_balance():
return (await client.get_wallet_balance("1"))["wallet_balance"]["confirmed_wallet_balance"]
await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount)
await client.get_next_address()
print(await client.get_wallet_balance("1"))
except Exception: except Exception:
# Checks that the RPC manages to stop the node # Checks that the RPC manages to stop the node

View File

@ -21,6 +21,7 @@ from src.util.ints import uint16, uint32
from src.server.start_service import Service from src.server.start_service import Service
from src.util.make_test_constants import make_test_constants_with_genesis from src.util.make_test_constants import make_test_constants_with_genesis
from tests.time_out_assert import time_out_assert from tests.time_out_assert import time_out_assert
from src.util.chech32 import encode_puzzle_hash
test_constants, bt = make_test_constants_with_genesis( test_constants, bt = make_test_constants_with_genesis(
@ -269,9 +270,9 @@ async def setup_farmer(
config = load_config(bt.root_path, "config.yaml", "farmer") config = load_config(bt.root_path, "config.yaml", "farmer")
config_pool = load_config(bt.root_path, "config.yaml", "pool") config_pool = load_config(bt.root_path, "config.yaml", "pool")
config["xch_target_puzzle_hash"] = bt.farmer_ph.hex() config["xch_target_address"] = encode_puzzle_hash(bt.farmer_ph).hex()
config["pool_public_keys"] = [bytes(pk).hex() for pk in bt.pool_pubkeys] config["pool_public_keys"] = [bytes(pk).hex() for pk in bt.pool_pubkeys]
config_pool["xch_target_puzzle_hash"] = bt.pool_ph.hex() config_pool["xch_target_address"] = encode_puzzle_hash(bt.pool_ph).hex()
if full_node_port: if full_node_port:
connect_peers = [PeerInfo(self_hostname, full_node_port)] connect_peers = [PeerInfo(self_hostname, full_node_port)]
else: else: