Cleaner send_transaction flow and more wallet rpc testing
This commit is contained in:
parent
9ed6949099
commit
b791bf1da8
|
@ -25,12 +25,14 @@ proofs of space during testing. The next time tests are run, this won't be neces
|
|||
```bash
|
||||
. ./activate
|
||||
pip install -r requirements-dev.txt
|
||||
black src tests && flake8 src --exclude src/wallet/electron/node_modules && mypy src tests
|
||||
py.test tests -s -v
|
||||
black src tests && flake8 src tests && mypy src tests
|
||||
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.
|
||||
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
|
||||
1. Install Python extension
|
||||
2. Set the environment to ./venv/bin/python
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
get_puzzle_hash,
|
||||
get_address,
|
||||
format_message,
|
||||
incomingMessage,
|
||||
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_transactions(wallet.id));
|
||||
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) {
|
||||
store.dispatch(get_colour_name(wallet.id));
|
||||
|
|
|
@ -11,15 +11,16 @@ export const Wallet = (id, name, type, data) => ({
|
|||
balance_frozen: 0,
|
||||
balance_change: 0,
|
||||
transactions: [],
|
||||
puzzle_hash: "",
|
||||
address: "",
|
||||
colour: "",
|
||||
sending_transaction: false,
|
||||
send_transaction_result: ""
|
||||
});
|
||||
|
||||
export const Transaction = (
|
||||
confirmed_at_index,
|
||||
created_at_time,
|
||||
to_puzzle_hash,
|
||||
to_address,
|
||||
amount,
|
||||
fee_amount,
|
||||
incoming,
|
||||
|
@ -32,7 +33,7 @@ export const Transaction = (
|
|||
) => ({
|
||||
confirmed_at_index: confirmed_at_index,
|
||||
created_at_time: created_at_time,
|
||||
to_puzzle_hash: to_puzzle_hash,
|
||||
to_address: to_address,
|
||||
amount: amount,
|
||||
fee_amount: fee_amount,
|
||||
incoming: incoming,
|
||||
|
@ -58,7 +59,6 @@ const initial_state = {
|
|||
connection_count: 0,
|
||||
syncing: false
|
||||
},
|
||||
sending_transaction: false,
|
||||
show_create_backup: false
|
||||
};
|
||||
|
||||
|
@ -87,20 +87,24 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
|
|||
};
|
||||
|
||||
case "CLEAR_SEND":
|
||||
id = action.message.data.wallet_id;
|
||||
wallet = state.wallets[parseInt(id)];
|
||||
wallet.sending_transaction = false;
|
||||
wallet.send_transaction_result = null;
|
||||
return {
|
||||
...state,
|
||||
sending_transaction: false,
|
||||
send_transaction_result: null
|
||||
};
|
||||
case "OUTGOING_MESSAGE":
|
||||
if (
|
||||
action.message.command === "send_transaction" ||
|
||||
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 {
|
||||
...state,
|
||||
sending_transaction: true,
|
||||
send_transaction_result: null
|
||||
};
|
||||
}
|
||||
return state;
|
||||
|
@ -190,15 +194,15 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
|
|||
wallet.transactions = transactions.reverse();
|
||||
return { ...state };
|
||||
}
|
||||
} else if (command === "get_next_puzzle_hash") {
|
||||
} else if (command === "get_next_address") {
|
||||
id = data.wallet_id;
|
||||
var puzzle_hash = data.puzzle_hash;
|
||||
var address = data.address;
|
||||
wallets = state.wallets;
|
||||
wallet = wallets[parseInt(id)];
|
||||
if (!wallet) {
|
||||
return state;
|
||||
}
|
||||
wallet.puzzle_hash = puzzle_hash;
|
||||
wallet.address = address;
|
||||
return { ...state };
|
||||
} else if (command === "get_connections") {
|
||||
if (data.success || data.connections) {
|
||||
|
@ -241,12 +245,12 @@ export const incomingReducer = (state = { ...initial_state }, action) => {
|
|||
wallet.name = name;
|
||||
return { ...state };
|
||||
}
|
||||
if (command === "send_transaction" || command === "cc_spend") {
|
||||
state["sending_transaction"] = false;
|
||||
if (command === "tx_update") {
|
||||
const id = data.id;
|
||||
wallets = state.wallets;
|
||||
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;
|
||||
|
|
|
@ -102,14 +102,18 @@ export const get_balance_for_wallet = id => {
|
|||
return action;
|
||||
};
|
||||
|
||||
export const send_transaction = (wallet_id, amount, fee, puzzle_hash) => {
|
||||
export const send_transaction = (wallet_id, amount, fee, address) => {
|
||||
var action = walletMessage();
|
||||
action.message.command = "send_transaction";
|
||||
action.message.data = {
|
||||
wallet_id: wallet_id,
|
||||
amount: amount,
|
||||
fee: fee,
|
||||
<<<<<<< HEAD
|
||||
puzzle_hash: puzzle_hash
|
||||
=======
|
||||
address: address,
|
||||
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
|
||||
};
|
||||
return action;
|
||||
};
|
||||
|
@ -132,8 +136,29 @@ export const add_key = (mnemonic, type, file_path) => {
|
|||
return action;
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
export const add_new_key_action = mnemonic => {
|
||||
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(
|
||||
dispatch,
|
||||
add_key(mnemonic, "new_wallet", null),
|
||||
|
@ -388,17 +413,25 @@ export const get_transactions = wallet_id => {
|
|||
return action;
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
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();
|
||||
action.message.command = "get_next_puzzle_hash";
|
||||
action.message.command = "get_next_address";
|
||||
action.message.data = { wallet_id: wallet_id };
|
||||
return action;
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
export const farm_block = puzzle_hash => {
|
||||
=======
|
||||
export const farm_block = (address) => {
|
||||
>>>>>>> c125573c... Cleaner send_transaction flow and more wallet rpc testing
|
||||
var action = walletMessage();
|
||||
action.message.command = "farm_block";
|
||||
action.message.data = { puzzle_hash: puzzle_hash };
|
||||
action.message.data = { address: address };
|
||||
return action;
|
||||
};
|
||||
|
||||
|
@ -536,12 +569,12 @@ export const rename_cc_wallet = (wallet_id, name) => {
|
|||
return action;
|
||||
};
|
||||
|
||||
export const cc_spend = (wallet_id, puzzle_hash, amount, fee) => {
|
||||
export const cc_spend = (wallet_id, address, amount, fee) => {
|
||||
var action = walletMessage();
|
||||
action.message.command = "cc_spend";
|
||||
action.message.data = {
|
||||
wallet_id: wallet_id,
|
||||
innerpuzhash: puzzle_hash,
|
||||
inner_address: address,
|
||||
amount: amount,
|
||||
fee: fee
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ import TableCell from "@material-ui/core/TableCell";
|
|||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import {
|
||||
get_puzzle_hash,
|
||||
get_address,
|
||||
cc_spend,
|
||||
farm_block,
|
||||
rename_cc_wallet
|
||||
|
@ -29,6 +29,7 @@ import {
|
|||
import { unix_to_short_date } from "../util/utils";
|
||||
import Accordion from "../components/Accordion";
|
||||
import { openDialog } from "../modules/dialogReducer";
|
||||
import { get_transaction_result } from "../util/transaction_result";
|
||||
const config = require("../config");
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
@ -417,7 +418,7 @@ const SendCard = props => {
|
|||
const cc_unit = get_cc_unit(name);
|
||||
|
||||
const sending_transaction = useSelector(
|
||||
state => state.wallet_state.sending_transaction
|
||||
state => state.wallet_state.wallets[id].sending_transaction
|
||||
);
|
||||
|
||||
const send_transaction_result = useSelector(
|
||||
|
@ -426,21 +427,9 @@ const SendCard = props => {
|
|||
|
||||
const colour = useSelector(state => state.wallet_state.wallets[id].colour);
|
||||
|
||||
let result_message = "";
|
||||
let result_class = classes.resultSuccess;
|
||||
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;
|
||||
}
|
||||
}
|
||||
result = get_transaction_result(send_transaction_result);
|
||||
let result_message = result.message;
|
||||
let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
|
||||
|
||||
function farm() {
|
||||
var address = address_input.value;
|
||||
|
@ -453,7 +442,7 @@ const SendCard = props => {
|
|||
if (sending_transaction) {
|
||||
return;
|
||||
}
|
||||
let puzzle_hash = address_input.value.trim();
|
||||
let address = address_input.value.trim();
|
||||
if (
|
||||
amount_input.value === "" ||
|
||||
Number(amount_input.value) === 0 ||
|
||||
|
@ -472,8 +461,8 @@ const SendCard = props => {
|
|||
const fee = colouredcoin_to_mojo(fee_input.value);
|
||||
|
||||
if (
|
||||
puzzle_hash.includes("chia_addr") ||
|
||||
puzzle_hash.includes("colour_desc")
|
||||
address.includes("chia_addr") ||
|
||||
address.includes("colour_desc")
|
||||
) {
|
||||
dispatch(
|
||||
openDialog(
|
||||
|
@ -482,9 +471,9 @@ const SendCard = props => {
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (puzzle_hash.substring(0, 14) === "colour_addr://") {
|
||||
const colour_id = puzzle_hash.substring(14, 78);
|
||||
puzzle_hash = puzzle_hash.substring(79);
|
||||
if (address.substring(0, 14) === "colour_addr://") {
|
||||
const colour_id = address.substring(14, 78);
|
||||
address = address.substring(79);
|
||||
if (colour_id !== colour) {
|
||||
dispatch(
|
||||
openDialog(
|
||||
|
@ -495,14 +484,14 @@ const SendCard = props => {
|
|||
}
|
||||
}
|
||||
|
||||
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) {
|
||||
puzzle_hash = puzzle_hash.substring(2);
|
||||
if (address.startsWith("0x") || address.startsWith("0X")) {
|
||||
address = address.substring(2);
|
||||
}
|
||||
|
||||
const amount_value = parseFloat(Number(amount));
|
||||
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 = "";
|
||||
amount_input.value = "";
|
||||
}
|
||||
|
@ -669,7 +658,7 @@ const TransactionTable = props => {
|
|||
{transactions.map(tx => (
|
||||
<TableRow
|
||||
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}>
|
||||
{incoming_string(tx.incoming)}
|
||||
|
@ -678,7 +667,7 @@ const TransactionTable = props => {
|
|||
style={{ maxWidth: "150px" }}
|
||||
className={classes.cell_short}
|
||||
>
|
||||
{tx.to_puzzle_hash}
|
||||
{tx.to_address}
|
||||
</TableCell>
|
||||
<TableCell className={classes.cell_short}>
|
||||
{unix_to_short_date(tx.created_at_time)}
|
||||
|
@ -702,18 +691,18 @@ const TransactionTable = props => {
|
|||
|
||||
const AddressCard = props => {
|
||||
var id = props.wallet_id;
|
||||
const puzzle_hash = useSelector(
|
||||
state => state.wallet_state.wallets[id].puzzle_hash
|
||||
const address = useSelector(
|
||||
state => state.wallet_state.wallets[id].address
|
||||
);
|
||||
const classes = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
function newAddress() {
|
||||
dispatch(get_puzzle_hash(id));
|
||||
dispatch(get_address(id));
|
||||
}
|
||||
|
||||
function copy() {
|
||||
navigator.clipboard.writeText(puzzle_hash);
|
||||
navigator.clipboard.writeText(address);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -734,7 +723,7 @@ const AddressCard = props => {
|
|||
disabled
|
||||
fullWidth
|
||||
label="Address"
|
||||
value={puzzle_hash}
|
||||
value={address}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Box>
|
||||
|
|
|
@ -643,34 +643,22 @@ const SendCard = props => {
|
|||
const dispatch = useDispatch();
|
||||
|
||||
const sending_transaction = useSelector(
|
||||
state => state.wallet_state.sending_transaction
|
||||
state => state.wallet_state.wallets[id].sending_transaction
|
||||
);
|
||||
|
||||
const send_transaction_result = useSelector(
|
||||
state => state.wallet_state.wallets[id].send_transaction_result
|
||||
);
|
||||
|
||||
let result_message = "";
|
||||
let result_class = classes.resultSuccess;
|
||||
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;
|
||||
}
|
||||
}
|
||||
result = get_transaction_result(send_transaction_result);
|
||||
let result_message = result.message;
|
||||
let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
|
||||
|
||||
function send() {
|
||||
if (sending_transaction) {
|
||||
return;
|
||||
}
|
||||
let puzzle_hash = address_input.value.trim();
|
||||
let address = address_input.value.trim();
|
||||
if (
|
||||
amount_input.value === "" ||
|
||||
Number(amount_input.value) === 0 ||
|
||||
|
@ -687,14 +675,14 @@ const SendCard = props => {
|
|||
const amount = chia_to_mojo(amount_input.value);
|
||||
const fee = chia_to_mojo(fee_input.value);
|
||||
|
||||
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) {
|
||||
puzzle_hash = puzzle_hash.substring(2);
|
||||
if (address.startsWith("0x") || address.startsWith("0X")) {
|
||||
address = address.substring(2);
|
||||
}
|
||||
|
||||
const amount_value = parseFloat(Number(amount));
|
||||
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 = "";
|
||||
amount_input.value = "";
|
||||
fee_input.value = "";
|
||||
|
@ -898,7 +886,7 @@ const TransactionTable = props => {
|
|||
{transactions.map(tx => (
|
||||
<TableRow
|
||||
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}>
|
||||
{incoming_string(tx.incoming)}
|
||||
|
@ -907,7 +895,7 @@ const TransactionTable = props => {
|
|||
style={{ maxWidth: "150px" }}
|
||||
className={classes.cell_short}
|
||||
>
|
||||
{tx.to_puzzle_hash}
|
||||
{tx.to_address}
|
||||
</TableCell>
|
||||
<TableCell className={classes.cell_short}>
|
||||
{unix_to_short_date(tx.created_at_time)}
|
||||
|
|
|
@ -15,7 +15,7 @@ import TableCell from "@material-ui/core/TableCell";
|
|||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import {
|
||||
get_puzzle_hash,
|
||||
get_address,
|
||||
send_transaction,
|
||||
farm_block
|
||||
} from "../modules/message";
|
||||
|
@ -326,27 +326,16 @@ const SendCard = props => {
|
|||
const dispatch = useDispatch();
|
||||
|
||||
const sending_transaction = useSelector(
|
||||
state => state.wallet_state.sending_transaction
|
||||
state => state.wallet_state.wallets[id].sending_transaction
|
||||
);
|
||||
|
||||
const send_transaction_result = useSelector(
|
||||
state => state.wallet_state.wallets[id].send_transaction_result
|
||||
);
|
||||
let result_message = "";
|
||||
let result_class = classes.resultSuccess;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
result = get_transaction_result(send_transaction_result);
|
||||
let result_message = result.message;
|
||||
let result_class = result.success ? classes.resultSuccess : classes.resultFailure;
|
||||
|
||||
function farm() {
|
||||
var address = address_input.value;
|
||||
|
@ -359,7 +348,7 @@ const SendCard = props => {
|
|||
if (sending_transaction) {
|
||||
return;
|
||||
}
|
||||
let puzzle_hash = address_input.value.trim();
|
||||
let address = address_input.value.trim();
|
||||
if (
|
||||
amount_input.value === "" ||
|
||||
Number(amount_input.value) === 0 ||
|
||||
|
@ -376,24 +365,24 @@ const SendCard = props => {
|
|||
const amount = chia_to_mojo(amount_input.value);
|
||||
const fee = chia_to_mojo(fee_input.value);
|
||||
|
||||
if (puzzle_hash.includes("colour")) {
|
||||
if (address.includes("colour")) {
|
||||
dispatch(
|
||||
openDialog(
|
||||
"Error: Cannot send chia to coloured address. Please enter a chia address."
|
||||
)
|
||||
);
|
||||
return;
|
||||
} else if (puzzle_hash.substring(0, 12) === "chia_addr://") {
|
||||
puzzle_hash = puzzle_hash.substring(12);
|
||||
} else if (address.substring(0, 12) === "chia_addr://") {
|
||||
address = address.substring(12);
|
||||
}
|
||||
if (puzzle_hash.startsWith("0x") || puzzle_hash.startsWith("0X")) {
|
||||
puzzle_hash = puzzle_hash.substring(2);
|
||||
if (address.startsWith("0x") || address.startsWith("0X")) {
|
||||
address = address.substring(2);
|
||||
}
|
||||
|
||||
const amount_value = parseFloat(Number(amount));
|
||||
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 = "";
|
||||
amount_input.value = "";
|
||||
fee_input.value = "";
|
||||
|
@ -565,7 +554,7 @@ const TransactionTable = props => {
|
|||
<TableRow
|
||||
className={classes.row}
|
||||
key={
|
||||
tx.to_puzzle_hash +
|
||||
tx.to_address +
|
||||
tx.created_at_time +
|
||||
tx.amount +
|
||||
(tx.removals.length > 0 ? tx.removals[0].parent_coin_info : "")
|
||||
|
@ -578,7 +567,7 @@ const TransactionTable = props => {
|
|||
style={{ maxWidth: "150px" }}
|
||||
className={classes.cell_short}
|
||||
>
|
||||
{tx.to_puzzle_hash}
|
||||
{tx.to_address}
|
||||
</TableCell>
|
||||
<TableCell className={classes.cell_short}>
|
||||
{unix_to_short_date(tx.created_at_time)}
|
||||
|
@ -602,18 +591,18 @@ const TransactionTable = props => {
|
|||
|
||||
const AddressCard = props => {
|
||||
var id = props.wallet_id;
|
||||
const puzzle_hash = useSelector(
|
||||
state => state.wallet_state.wallets[id].puzzle_hash
|
||||
const address = useSelector(
|
||||
state => state.wallet_state.wallets[id].address
|
||||
);
|
||||
const classes = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
function newAddress() {
|
||||
dispatch(get_puzzle_hash(id));
|
||||
dispatch(get_address(id));
|
||||
}
|
||||
|
||||
function copy() {
|
||||
navigator.clipboard.writeText(puzzle_hash);
|
||||
navigator.clipboard.writeText(address);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -634,7 +623,7 @@ const AddressCard = props => {
|
|||
disabled
|
||||
fullWidth
|
||||
label="Address"
|
||||
value={puzzle_hash}
|
||||
value={address}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Box>
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -23,6 +23,7 @@ import yaml
|
|||
|
||||
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.util.chech32 import encode_puzzle_hash
|
||||
|
||||
|
||||
def make_parser(parser: ArgumentParser):
|
||||
|
@ -54,50 +55,50 @@ def check_keys(new_root):
|
|||
config: Dict = load_config(new_root, "config.yaml")
|
||||
pool_child_pubkeys = [master_sk_to_pool_sk(sk).get_g1() for sk, _ in all_sks]
|
||||
all_targets = []
|
||||
stop_searching_for_farmer = "xch_target_puzzle_hash" not in config["farmer"]
|
||||
stop_searching_for_pool = "xch_target_puzzle_hash" not in config["pool"]
|
||||
stop_searching_for_farmer = "xch_target_address" not in config["farmer"]
|
||||
stop_searching_for_pool = "xch_target_address" not in config["pool"]
|
||||
for i in range(500):
|
||||
if stop_searching_for_farmer and stop_searching_for_pool and i > 0:
|
||||
break
|
||||
for sk, _ in all_sks:
|
||||
all_targets.append(
|
||||
create_puzzlehash_for_pk(
|
||||
encode_puzzle_hash(create_puzzlehash_for_pk(
|
||||
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
|
||||
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
|
||||
|
||||
# Set the destinations
|
||||
if "xch_target_puzzle_hash" not in config["farmer"]:
|
||||
if "xch_target_address" not in config["farmer"]:
|
||||
print(
|
||||
f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}"
|
||||
)
|
||||
config["farmer"]["xch_target_puzzle_hash"] = all_targets[0]
|
||||
elif config["farmer"]["xch_target_puzzle_hash"] not in all_targets:
|
||||
config["farmer"]["xch_target_address"] = all_targets[0]
|
||||
elif config["farmer"]["xch_target_address"] not in all_targets:
|
||||
print(
|
||||
f"WARNING: farmer using a puzzle hash which we don't have the private"
|
||||
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:
|
||||
config["pool"] = {}
|
||||
if "xch_target_puzzle_hash" not in config["pool"]:
|
||||
if "xch_target_address" not in config["pool"]:
|
||||
print(
|
||||
f"Setting the xch destination address for coinbase reward to {all_targets[0]}"
|
||||
)
|
||||
config["pool"]["xch_target_puzzle_hash"] = all_targets[0]
|
||||
elif config["pool"]["xch_target_puzzle_hash"] not in all_targets:
|
||||
config["pool"]["xch_target_address"] = all_targets[0]
|
||||
elif config["pool"]["xch_target_address"] not in all_targets:
|
||||
print(
|
||||
f"WARNING: pool using a puzzle hash which we don't have the private"
|
||||
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
|
||||
pool_pubkeys_hex = set(bytes(pk).hex() for pk in pool_child_pubkeys)
|
||||
|
|
|
@ -15,6 +15,7 @@ from src.util.config import load_config
|
|||
from src.util.default_root import DEFAULT_ROOT_PATH
|
||||
from src.wallet.util.wallet_types import WalletType
|
||||
from src.cmds.units import units
|
||||
from src.util.chech32 import encode_puzzle_hash
|
||||
|
||||
|
||||
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 Generator Hash {block.transactions_generator}\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 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}"
|
||||
)
|
||||
else:
|
||||
|
|
|
@ -16,6 +16,7 @@ from src.types.pool_target import PoolTarget
|
|||
from src.util.api_decorators import api_request
|
||||
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.util.chech32 import decode_puzzle_hash
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -57,14 +58,14 @@ class Farmer:
|
|||
raise RuntimeError(error_str)
|
||||
|
||||
# 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 = [
|
||||
G1Element.from_bytes(bytes.fromhex(pk))
|
||||
for pk in self.config["pool_public_keys"]
|
||||
]
|
||||
|
||||
# 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 = {}
|
||||
for key in self._get_private_keys():
|
||||
self.pool_sks_map[bytes(key.get_g1())] = key
|
||||
|
|
|
@ -560,7 +560,7 @@ class FullNode:
|
|||
if self.mempool_manager.seen(transaction.transaction_id):
|
||||
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(
|
||||
transaction.transaction_id
|
||||
)
|
||||
|
@ -613,10 +613,12 @@ class FullNode:
|
|||
# Ignore if we have already added this transaction
|
||||
if self.mempool_manager.get_spendbundle(tx.transaction.name()) is not None:
|
||||
return
|
||||
self.log.warning(f"Adding transaction to mempool: {transaction.transaction_id}")
|
||||
cost, status, error = await self.mempool_manager.add_spendbundle(
|
||||
tx.transaction
|
||||
)
|
||||
if status == MempoolInclusionStatus.SUCCESS:
|
||||
self.log.warning(f"Added transaction to mempool: {transaction.transaction_id}")
|
||||
fees = tx.transaction.fees()
|
||||
assert fees >= 0
|
||||
assert cost is not None
|
||||
|
@ -1823,6 +1825,7 @@ class FullNode:
|
|||
tx.transaction
|
||||
)
|
||||
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
|
||||
# vector.
|
||||
fees = tx.transaction.fees()
|
||||
|
|
|
@ -45,7 +45,12 @@ class WalletRpcApi:
|
|||
return {
|
||||
"/get_wallet_balance": self.get_wallet_balance,
|
||||
"/send_transaction": self.send_transaction,
|
||||
<<<<<<< HEAD
|
||||
"/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,
|
||||
"/farm_block": self.farm_block,
|
||||
"/get_sync_status": self.get_sync_status,
|
||||
|
@ -155,18 +160,18 @@ class WalletRpcApi:
|
|||
if len(args) < 2:
|
||||
return []
|
||||
|
||||
change = args[0]
|
||||
wallet_id = args[1]
|
||||
data = {
|
||||
"state": change,
|
||||
"state": args[0],
|
||||
}
|
||||
if wallet_id is not None:
|
||||
data["wallet_id"] = wallet_id
|
||||
if args[1] is not None:
|
||||
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")]
|
||||
|
||||
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:
|
||||
return {"success": False}
|
||||
|
@ -178,10 +183,10 @@ class WalletRpcApi:
|
|||
|
||||
if wallet.wallet_info.type == WalletType.STANDARD_WALLET.value:
|
||||
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:
|
||||
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:
|
||||
return {
|
||||
"success": False,
|
||||
|
@ -191,13 +196,12 @@ class WalletRpcApi:
|
|||
response = {
|
||||
"success": True,
|
||||
"wallet_id": wallet_id,
|
||||
"puzzle_hash": puzzle_hash,
|
||||
"address": address,
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
async def send_transaction(self, request):
|
||||
log.debug("rpc_api request: " + str(request))
|
||||
wallet_id = int(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.wallets[wallet_id]
|
||||
try:
|
||||
|
@ -270,7 +274,7 @@ class WalletRpcApi:
|
|||
|
||||
for tx in transactions:
|
||||
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)
|
||||
|
||||
response = {
|
||||
|
@ -462,7 +466,7 @@ class WalletRpcApi:
|
|||
async def cc_spend(self, request):
|
||||
wallet_id = int(request["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)
|
||||
|
||||
try:
|
||||
|
@ -475,7 +479,7 @@ class WalletRpcApi:
|
|||
|
||||
if tx is None:
|
||||
data = {
|
||||
"status": "FAILED",
|
||||
"success": False,
|
||||
"reason": "Failed to generate signed transaction",
|
||||
"id": wallet_id,
|
||||
}
|
||||
|
@ -484,47 +488,18 @@ class WalletRpcApi:
|
|||
await wallet.wallet_state_manager.add_pending_transaction(tx)
|
||||
except Exception as e:
|
||||
data = {
|
||||
"status": "FAILED",
|
||||
"success": False,
|
||||
"reason": f"Failed to push transaction {e}",
|
||||
}
|
||||
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:
|
||||
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
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"transaction": tr,
|
||||
"transaction_id": tr.spend_bundle.name(),
|
||||
}
|
||||
|
||||
async def cc_get_colour(self, request):
|
||||
wallet_id = int(request["wallet_id"])
|
||||
wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id]
|
||||
|
@ -818,13 +793,13 @@ class WalletRpcApi:
|
|||
tx = await wallet.clawback_rl_coin_transaction()
|
||||
except Exception as e:
|
||||
data = {
|
||||
"status": "FAILED",
|
||||
"success": False,
|
||||
"reason": f"Failed to generate signed transaction {e}",
|
||||
}
|
||||
return data
|
||||
if tx is None:
|
||||
data = {
|
||||
"status": "FAILED",
|
||||
"success": False,
|
||||
"reason": "Failed to generate signed transaction",
|
||||
}
|
||||
return data
|
||||
|
@ -832,41 +807,14 @@ class WalletRpcApi:
|
|||
await wallet.push_transaction(tx)
|
||||
except Exception as e:
|
||||
data = {
|
||||
"status": "FAILED",
|
||||
"success": False,
|
||||
"reason": f"Failed to push transaction {e}",
|
||||
}
|
||||
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:
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
status, err = sent_to[0][1], sent_to[0][2]
|
||||
if status == MempoolInclusionStatus.SUCCESS:
|
||||
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.",
|
||||
# Transaction may not have been included in the mempool yet. Use get_transaction to check.
|
||||
return {
|
||||
"success": True,
|
||||
"transaction": tx,
|
||||
"transaction_id": tx.spend_bundle.name(),
|
||||
}
|
||||
|
||||
return data
|
||||
|
|
|
@ -36,6 +36,9 @@ class WalletRpcClient(RpcClient):
|
|||
return TransactionRecord.from_json_dict(response["transaction"])
|
||||
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(
|
||||
self, wallet_id: str, transaction_id: bytes32
|
||||
) -> Optional[TransactionRecord]:
|
||||
|
|
|
@ -32,7 +32,7 @@ harvester:
|
|||
|
||||
pool: {
|
||||
# Replace this with a real puzzle hash
|
||||
# xch_target_puzzle_hash: a4259182b4d8e0af21331fc5be2681f953400b6726fa4095e3b91ae8f005a836
|
||||
# xch_target_address: txch102gkhhzs60grx7cfnpng5n6rjecr89r86l5s8xux2za8k820cxsq64ssdg
|
||||
logging: *logging
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ farmer:
|
|||
pool_public_keys: []
|
||||
|
||||
# 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
|
||||
start_rpc_server: True
|
||||
|
|
|
@ -319,7 +319,7 @@ class WalletStateManager:
|
|||
continue
|
||||
puzzlehash: bytes32 = puzzle.get_tree_hash()
|
||||
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(
|
||||
DerivationRecord(
|
||||
|
@ -376,13 +376,13 @@ class WalletStateManager:
|
|||
"""
|
||||
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.
|
||||
"""
|
||||
if self.state_changed_callback is None:
|
||||
return
|
||||
self.state_changed_callback(state, wallet_id)
|
||||
self.state_changed_callback(state, wallet_id, data_object)
|
||||
|
||||
def tx_pending_changed(self):
|
||||
"""
|
||||
|
@ -698,7 +698,9 @@ class WalletStateManager:
|
|||
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)
|
||||
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]:
|
||||
"""
|
||||
|
@ -1541,13 +1543,3 @@ class WalletStateManager:
|
|||
if callback_str is not None:
|
||||
callback = getattr(wallet, callback_str)
|
||||
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
|
||||
|
|
|
@ -40,8 +40,9 @@ class TestWalletRpc:
|
|||
wallet_node, server_2 = wallets[0]
|
||||
wallet_node_2, server_3 = wallets[1]
|
||||
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_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)
|
||||
|
||||
|
@ -54,6 +55,12 @@ class TestWalletRpc:
|
|||
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)
|
||||
|
||||
|
@ -81,27 +88,29 @@ class TestWalletRpc:
|
|||
addr = encode_puzzle_hash(
|
||||
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
|
||||
transaction_id = tx.name()
|
||||
|
||||
async def tx_in_mempool():
|
||||
tx = await client.get_transaction("1", transaction_id)
|
||||
return tx.is_in_mempool()
|
||||
|
||||
await time_out_assert(5, tx_in_mempool, True)
|
||||
await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds - 1)
|
||||
assert (await client.get_wallet_balance("1"))["wallet_balance"]["unconfirmed_wallet_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 - tx_amount
|
||||
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))
|
||||
|
||||
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:
|
||||
# Checks that the RPC manages to stop the node
|
||||
|
|
|
@ -21,6 +21,7 @@ from src.util.ints import uint16, uint32
|
|||
from src.server.start_service import Service
|
||||
from src.util.make_test_constants import make_test_constants_with_genesis
|
||||
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(
|
||||
|
@ -269,9 +270,9 @@ async def setup_farmer(
|
|||
config = load_config(bt.root_path, "config.yaml", "farmer")
|
||||
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["xch_target_puzzle_hash"] = bt.pool_ph.hex()
|
||||
config_pool["xch_target_address"] = encode_puzzle_hash(bt.pool_ph).hex()
|
||||
if full_node_port:
|
||||
connect_peers = [PeerInfo(self_hostname, full_node_port)]
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue