Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wallet address generator binary #1261

Merged
merged 7 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 52 additions & 49 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,57 @@ edition = "2021"

[workspace]
members = [
"accounting", # Accounting and balances abstractions.
"api-server/api-server-common", # API server, for light-wallets and block explorers: common between web-server and scanner.
"api-server/storage-test-suite",# Test suite for the abstract storage layer of the API server to ensure consistent behavior.
"api-server/scanner-daemon", # API server, for light-wallets and block explorers: blockchain scanner daemon.
"api-server/scanner-lib", # API server, for light-wallets and block explorers: blockchain scanner library.
"api-server/web-server", # API server, for light-wallets and block explorers: web-server.
"blockprod", # Block production with whatever consensus algorithm.
"chainstate", # Code on chainstate of blocks and transactions.
"chainstate/test-suite", # Tests for the chainstate, separated to make use of the chainstate test framework.
"common", # Everything else, until it's moved to another crate.
"consensus", # Consensus related logic.
"crypto", # Cryptographic primitives and their interfaces.
"dns_server", # DNS-server.
"logging", # Logging engine and its interfaces.
"mempool", # Mempool interface and implementation.
"mempool/types", # Common mempool types.
"merkletree", # Merkle tree implementation with merkle proofs.
"mocks", # Mock implementations of our traits (used for testing)
"node-daemon", # Node terminal binary.
"node-gui", # Node GUI binary.
"node-lib", # Node lib; the common library between daemon, tui and gui node executables.
"p2p", # P2p communication interfaces and protocols.
"p2p/backend-test-suite", # P2p backend agnostic tests.
"p2p/types", # P2p support types with minimal dependencies.
"pos_accounting", # PoS accounting and balances abstractions.
"rpc", # Rpc abstraction and implementation.
"script", # Bitcoin script and its interfaces.
"serialization", # Full featured serialization interfaces and implementations.
"serialization/core", # Serialization core tools.
"serialization/tagged", # Serialization for direct/tagged encoding style.
"serialization/tagged/derive", # direct/tagged encoding style derive macros.
"storage", # storage abstraction layer and its implementation.
"storage/backend-test-suite", # Tests for validating storage backend implementations.
"storage/core", # Core backend-agnostic storage abstraction.
"storage/inmemory", # In-memory storage backend implementation.
"storage/lmdb", # LMDB-based persistent storage backend implementation.
"storage/sqlite", # SQLite-based persistent storage backend implementation.
"subsystem", # Utilities for working with concurrent subsystems.
"test", # Integration tests.
"test-rpc-functions", # RPC functions specifically for tests.
"test-utils", # Various utilities for tests.
"utils", # Various utilities.
"utxo", # Utxo and related utilities (cache, undo, etc.).
"wallet", # Wallet primitives.
"wallet/wallet-cli", # Wallet CLI/REPL binary.
"wallet/wallet-cli-lib", # Wallet CLI/REPL lib.
"wallet/wallet-controller", # Common code for wallet UI applications.
"wallet/wallet-node-client", # Wallet-to-node communication tools.
"wasm-crypto", # WASM bindings for the crypto crate.
"accounting", # Accounting and balances abstractions.
"api-server/api-server-common", # API server, for light-wallets and block explorers: common between web-server and scanner.
"api-server/storage-test-suite", # Test suite for the abstract storage layer of the API server to ensure consistent behavior.
"api-server/scanner-daemon", # API server, for light-wallets and block explorers: blockchain scanner daemon.
"api-server/scanner-lib", # API server, for light-wallets and block explorers: blockchain scanner library.
"api-server/web-server", # API server, for light-wallets and block explorers: web-server.
"blockprod", # Block production with whatever consensus algorithm.
"chainstate", # Code on chainstate of blocks and transactions.
"chainstate/test-suite", # Tests for the chainstate, separated to make use of the chainstate test framework.
"common", # Everything else, until it's moved to another crate.
"consensus", # Consensus related logic.
"crypto", # Cryptographic primitives and their interfaces.
"dns_server", # DNS-server.
"logging", # Logging engine and its interfaces.
"mempool", # Mempool interface and implementation.
"mempool/types", # Common mempool types.
"merkletree", # Merkle tree implementation with merkle proofs.
"mocks", # Mock implementations of our traits (used for testing)
"node-daemon", # Node terminal binary.
"node-gui", # Node GUI binary.
"node-lib", # Node lib; the common library between daemon, tui and gui node executables.
"p2p", # P2p communication interfaces and protocols.
"p2p/backend-test-suite", # P2p backend agnostic tests.
"p2p/types", # P2p support types with minimal dependencies.
"pos_accounting", # PoS accounting and balances abstractions.
"rpc", # Rpc abstraction and implementation.
"script", # Bitcoin script and its interfaces.
"serialization", # Full featured serialization interfaces and implementations.
"serialization/core", # Serialization core tools.
"serialization/tagged", # Serialization for direct/tagged encoding style.
"serialization/tagged/derive", # direct/tagged encoding style derive macros.
"storage", # storage abstraction layer and its implementation.
"storage/backend-test-suite", # Tests for validating storage backend implementations.
"storage/core", # Core backend-agnostic storage abstraction.
"storage/inmemory", # In-memory storage backend implementation.
"storage/lmdb", # LMDB-based persistent storage backend implementation.
"storage/sqlite", # SQLite-based persistent storage backend implementation.
"subsystem", # Utilities for working with concurrent subsystems.
"test", # Integration tests.
"test-rpc-functions", # RPC functions specifically for tests.
"test-utils", # Various utilities for tests.
"utils", # Various utilities.
"utxo", # Utxo and related utilities (cache, undo, etc.).
"wallet", # Wallet primitives.
"wallet/wallet-cli", # Wallet CLI/REPL binary.
"wallet/wallet-cli-lib", # Wallet CLI/REPL lib.
"wallet/wallet-controller", # Common code for wallet UI applications.
"wallet/wallet-node-client", # Wallet-to-node communication tools.
"wallet/wallet-address-generator", # Wallet address generator binary.
"wallet/wallet-address-generator-lib",# Wallet address generator lib.
"wasm-crypto", # WASM bindings for the crypto crate.
]

default-members = [
Expand All @@ -83,6 +85,7 @@ default-members = [
"utxo",
"wallet",
"wallet/wallet-cli",
"wallet/wallet-address-generator",
]

[dependencies]
Expand Down
1 change: 1 addition & 0 deletions test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ homepage = "https://github.com/mintlayer/mintlayer-core/issues"
utils = { path = "../utils" }
node-lib = { path = "../node-lib" }
wallet-cli-lib = { path = "../wallet/wallet-cli-lib" }
wallet-address-generator-lib = { path = "../wallet/wallet-address-generator-lib" }

clap = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = ['full'] }
Expand Down
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class UnicodeOnWindowsError(ValueError):
'wallet_nfts.py',
'wallet_delegations.py',
'wallet_high_fee.py',
'wallet_generate_addresses.py',
'mempool_basic_reorg.py',
'mempool_eviction.py',
'mempool_ibd.py',
Expand Down
170 changes: 170 additions & 0 deletions test/functional/wallet_generate_addresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#!/usr/bin/env python3
# Copyright (c) 2023 RBB S.r.l
# Copyright (c) 2017-2021 The Bitcoin Core developers
# opensource@mintlayer.org
# SPDX-License-Identifier: MIT
# Licensed under the MIT License;
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Wallet address generator test

Check that:
* We can create a new wallet,
* get an address
* send coins to the wallet's address
* sync the wallet with the node
* check balance
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input, ATOMS_PER_COIN)
from test_framework.util import assert_in, assert_equal
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController

import asyncio
import sys
import subprocess
import os
import re


class WalletAddressGenerator(BitcoinTestFramework):

def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [[
"--blockprod-min-peers-to-produce-blocks=0",
]]

def setup_network(self):
self.setup_nodes()
self.sync_all(self.nodes[0:1])

def generate_block(self):
node = self.nodes[0]

block_input_data = { "PoW": { "reward_destination": "AnyoneCanSpend" } }
block_input_data = block_input_data_obj.encode(block_input_data).to_hex()[2:]

# create a new block, taking transactions from mempool
block = node.blockprod_generate_block(block_input_data, None)
node.chainstate_submit_block(block)
block_id = node.chainstate_best_block_id()

# Wait for mempool to sync
self.wait_until(lambda: node.mempool_local_best_block_id() == block_id, timeout = 5)

return block_id

def run_generate_addresses(self, args = []):
addr_generator_cli = os.path.join(self.config["environment"]["BUILDDIR"], "test_wallet_address_generator"+self.config["environment"]["EXEEXT"] )
args = ["--network", "regtest"] + args
self.log.info(f"sending args {args}")

result = subprocess.run([addr_generator_cli, *args], stdout=subprocess.PIPE)
output = result.stdout.decode()
self.log.info(output)

lines = output.splitlines()
if lines[3].startswith("Using the seed phrase you provided to generate address"):
seed_phrase = lines[3][lines[3].find(':')+2:]
addresses = [addr[2:] for addr in output.splitlines()[7:-2]]
elif lines[3].startswith("No seed phrase provided"):
seed_phrase = lines[6]
addresses = [addr[2:] for addr in output.splitlines()[11:-2]]
else:
return None, None


return seed_phrase, addresses


def run_test(self):
if 'win32' in sys.platform:
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
asyncio.run(self.async_test())

async def async_test(self):
node = self.nodes[0]
async with WalletCliController(node, self.config, self.log) as wallet:
# new wallet
await wallet.create_wallet()

# check it is on genesis
best_block_height = await wallet.get_best_block_height()
self.log.info(f"best block height = {best_block_height}")
assert_equal(best_block_height, '0')

# new address
pub_key_bytes = await wallet.new_public_key()
assert_equal(len(pub_key_bytes), 33)

# Get chain tip
tip_id = node.chainstate_best_block_id()
self.log.debug(f'Tip: {tip_id}')

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 100 * ATOMS_PER_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

self.log.debug(f"Encoded transaction {tx_id}: {encoded_tx}")

node.mempool_submit_transaction(encoded_tx)
assert node.mempool_contains_tx(tx_id)

block_id = self.generate_block() # Block 1
assert not node.mempool_contains_tx(tx_id)

# sync the wallet
assert_in("Success", await wallet.sync())

# check wallet best block if it is synced
best_block_height = await wallet.get_best_block_height()
assert_equal(best_block_height, '1')

best_block_id = await wallet.get_best_block()
assert_equal(best_block_id, block_id)

assert_in("Coins amount: 100", await wallet.get_balance())

# use the new CLI tool to create a new seed_phrase and some addresses
seed_phrase, addresses = self.run_generate_addresses(["--address-count", "20"])
assert seed_phrase is not None
assert addresses is not None

self.log.info(f"addresses '{addresses}'")
assert_equal(len(addresses), 20)

# send some a coin to each one of the addresses to confirm all of them are valid
for addr in addresses:
assert_in("The transaction was submitted successfully", await wallet.send_to_address(addr, 1))
self.generate_block()

# close this wallet and create a new one with the new seed phrase
await wallet.close_wallet()
assert_in("New wallet created successfully", await wallet.recover_wallet(seed_phrase))
assert_in("Success", await wallet.sync())
assert_in(f"Coins amount: {len(addresses)}", await wallet.get_balance())

# check that if we specify the same seed phrase it will generate the same addresses
new_seed_phrase, new_addresses = self.run_generate_addresses(["--address-count", "20", "--mnemonic", seed_phrase])
assert_equal(seed_phrase, new_seed_phrase)
assert_equal(addresses, new_addresses)


if __name__ == '__main__':
WalletAddressGenerator().main()


31 changes: 31 additions & 0 deletions test/src/bin/test_wallet_address_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2023 RBB S.r.l
// opensource@mintlayer.org
// SPDX-License-Identifier: MIT
// Licensed under the MIT License;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap::Parser;
use wallet_address_generator_lib::CliArgs;

fn main() {
utils::rust_backtrace::enable();

if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}

let args = CliArgs::parse();
wallet_address_generator_lib::run(args).unwrap_or_else(|err| {
eprintln!("{}", err);
std::process::exit(1);
})
}
2 changes: 1 addition & 1 deletion wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// limitations under the License.

pub mod account;
mod key_chain;
pub mod key_chain;
pub mod send_request;
pub mod version;
pub mod wallet;
Expand Down
Loading
Loading