Chore: Automatic Testing and Documentation for Liquid (#1286)
* pin to newer version * kick * rename script and check prerequisites * fail early and Dockerfile * reduce threads again * fix packages (not yet in DOCKERFILE) * debug-log failed rpc-calls * make funds available and fix address * fix test * fix test ... now explicitely ask to not confirm * complete send test * test single and multisig elem wallets * testing also nested singlesig * updates * complete and fix multisig-tests * fix tests * ensure conn.json * elements log in cirrus * increase wait time for elements mining * remove elm-log-stdout again * start documenting * increase timeout for last send * log exception * doc update * small changes * refactor Mining Testcode * move images to dedicated folder Co-authored-by: benk10 <ben.kaufman10@gmail.com>
|
|
@ -12,14 +12,14 @@ prep_stuff_template: &PREP_STUFF_TEMPLATE
|
|||
- cat pytest.ini | grep "addopts = " | cut -d'=' -f2 | sed 's/--/+/g' | tr '+' '\n' | grep bitcoin | cut -d' ' -f2
|
||||
- cat tests/bitcoin_gitrev_pinned 2> /dev/null || true
|
||||
- cat /etc/os-release | grep VERSION
|
||||
populate_script: ./tests/install_bitcoind.sh binary
|
||||
populate_script: ./tests/install_noded.sh binary
|
||||
elementsd_installation_cache:
|
||||
folder: ./tests/elements
|
||||
fingerprint_script:
|
||||
- cat pytest.ini | grep "addopts = " | cut -d'=' -f2 | sed 's/--/+/g' | tr '+' '\n' | grep elements | cut -d' ' -f2
|
||||
- cat tests/elements_gitrev_pinned 2> /dev/null || true
|
||||
- cat /etc/os-release | grep VERSION
|
||||
populate_script: ./tests/install_bitcoind.sh --debug --elements compile
|
||||
populate_script: ./tests/install_noded.sh --debug --elements compile
|
||||
verify_script:
|
||||
- echo " --> Version of python, virtualenv and pip3"
|
||||
- python3 --version && virtualenv --version && pip3 --version
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ before_script:
|
|||
- apt update
|
||||
- apt install -y libusb-1.0-0-dev libudev-dev # usb-support in hidapi
|
||||
# This doesn't get cached in gitlab but we don't need it anyway for now:
|
||||
# - ./tests/install_bitcoind.sh --debug --elements compile
|
||||
# - ./tests/install_noded.sh --debug --elements compile
|
||||
- pip3 install --upgrade virtualenv
|
||||
- virtualenv --python=python3 .env
|
||||
- source .env/bin/activate
|
||||
|
|
|
|||
16
README.md
|
|
@ -122,24 +122,24 @@ If you're stuck while installing/configuring Specter or you're looking for more
|
|||
|
||||
### Adding a new device
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### Creating a new wallet
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### Wallet interface
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### Configuration
|
||||
|
||||

|
||||

|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"spec_node_configured.js",
|
||||
"spec_wallet_send.js",
|
||||
"spec_wallet_utxo.js",
|
||||
"spec_elm_wallet_send.js"
|
||||
"spec_elm_single_segwit_wallet.js",
|
||||
"spec_elm_multi_segwit_wallet.js"
|
||||
],
|
||||
"baseUrl": "http://localhost:25444"
|
||||
}
|
||||
|
|
|
|||
224
cypress/integration/spec_elm_multi_segwit_wallet.js
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
describe('Operating with an elements multisig wallet', () => {
|
||||
it('Creates an two elements multisig hot wallets (segwit/nested) both 2/3', () => {
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
cy.get('#node-switch-icon').click()
|
||||
cy.get('#elements_node-select-node-form > .item > div').click()
|
||||
|
||||
// Delete Wallet if existing
|
||||
cy.deleteWallet("Elm Multi Segwit Wallet")
|
||||
cy.deleteWallet("Elm Multi Nested Wallet")
|
||||
|
||||
// Create the Hot Element Wallets
|
||||
cy.addHotDevice("Hot Elements Device 2","elements")
|
||||
cy.addHotDevice("Hot Elements Device 3","elements")
|
||||
cy.addHotDevice("Hot Elements Device 4","elements")
|
||||
|
||||
// Create Segwit multisig wallet
|
||||
cy.get('#btn_new_wallet').click()
|
||||
cy.get('[href="./multisig/"]').click()
|
||||
cy.get('#hot_elements_device_2').click()
|
||||
cy.get('#hot_elements_device_3').click()
|
||||
cy.get('#hot_elements_device_4').click()
|
||||
cy.get('#submit-device').click()
|
||||
cy.get('#wallet_name').type("Elm Multi Segwit Wallet")
|
||||
cy.get(':nth-child(9) > .inline').clear()
|
||||
// 2 of 2
|
||||
cy.get(':nth-child(9) > .inline').type("2")
|
||||
// submit
|
||||
cy.get('#keysform > .centered').click()
|
||||
// Cancel-button (no pdf download)
|
||||
cy.get('#page_overlay_popup_cancel_button').click()
|
||||
//Get some funds
|
||||
cy.mine2wallet("elm")
|
||||
|
||||
|
||||
// Create Nested multisig wallet
|
||||
cy.get('#btn_new_wallet').click()
|
||||
cy.get('[href="./multisig/"]').click()
|
||||
cy.get('#hot_elements_device_2').click()
|
||||
cy.get('#hot_elements_device_3').click()
|
||||
cy.get('#hot_elements_device_4').click()
|
||||
cy.get('#submit-device').click()
|
||||
cy.get(':nth-child(1) > #type_nested_segwit_btn') // Nested!!
|
||||
cy.get('#wallet_name').type("Elm Multi Nested Wallet")
|
||||
cy.get(':nth-child(9) > .inline').clear()
|
||||
// 2 of 2
|
||||
cy.get(':nth-child(9) > .inline').type("2")
|
||||
// submit
|
||||
cy.get('#keysform > .centered').click()
|
||||
// Cancel-button (no pdf download)
|
||||
cy.get('#page_overlay_popup_cancel_button').click()
|
||||
//Get some funds
|
||||
cy.mine2wallet("elm")
|
||||
})
|
||||
|
||||
it('Spending to a Confidential address from segwit', () => {
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
// spend the money again
|
||||
cy.contains("Elm Multi Segwit Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("el1qqdsywea5scrn7t9q83fd540pw447h0uae30pdp82rzgkl7yzvjz6gra9ls8qu6sslw4s0ck48we06zhqd6kwjy2quh69zwxwn", "Burn address","1.5")
|
||||
|
||||
|
||||
cy.get('#hot_elements_device_2_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_2_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#hot_elements_device_3_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_3_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
// cy.get('#broadcast_local_btn').click()
|
||||
// There is a bug as the first device doesn't seem to have signed and so we can't send the tx just right from here
|
||||
// 2 more clicks until to get to the send button
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('.row > :nth-child(1) > .btn').click()
|
||||
cy.get('#send_tx_btn').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
// gets redirected to "transactions"
|
||||
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
cy.get('.row > :nth-child(2) > .btn').click()
|
||||
|
||||
|
||||
})
|
||||
|
||||
it('Spending to a Unconfidential address from segwit', () => {
|
||||
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
// spend the money again
|
||||
cy.contains("Elm Multi Segwit Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("ert1q38la37ulxgc0uwt334he46eua7h8qagqnlm5phcqk7ntgv3x73cqjtr2fa", "unconf Burn address","1.5")
|
||||
|
||||
|
||||
cy.get('#hot_elements_device_2_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_2_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#hot_elements_device_3_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_3_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
// cy.get('#broadcast_local_btn').click()
|
||||
// There is a bug as the first device doesn't seem to have signed and so we can't send the tx just right from here
|
||||
// 2 more clicks until to get to the send button
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('.row > :nth-child(1) > .btn').click()
|
||||
cy.get('#send_tx_btn').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
// gets redirected to "transactions"
|
||||
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
// Strange bug, not needed here
|
||||
// cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
// cy.get('.row > :nth-child(2) > .btn').click()
|
||||
|
||||
})
|
||||
|
||||
it('Spending to a Confidential address from nested', () => {
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
// spend the money again
|
||||
cy.contains("Elm Multi Nested Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("el1qqdsywea5scrn7t9q83fd540pw447h0uae30pdp82rzgkl7yzvjz6gra9ls8qu6sslw4s0ck48we06zhqd6kwjy2quh69zwxwn", "Burn address","1.5")
|
||||
|
||||
|
||||
cy.get('#hot_elements_device_2_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_2_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#hot_elements_device_3_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_3_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
// cy.get('#broadcast_local_btn').click()
|
||||
// There is a bug as the first device doesn't seem to have signed and so we can't send the tx just right from here
|
||||
// 2 more clicks until to get to the send button
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('.row > :nth-child(1) > .btn').click()
|
||||
cy.get('#send_tx_btn').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
// gets redirected to "transactions"
|
||||
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
cy.get('.row > :nth-child(2) > .btn').click()
|
||||
|
||||
|
||||
})
|
||||
|
||||
it('Spending to a Unconfidential address from nested', () => {
|
||||
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
// spend the money again
|
||||
cy.contains("Elm Multi Nested Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("ert1q38la37ulxgc0uwt334he46eua7h8qagqnlm5phcqk7ntgv3x73cqjtr2fa", "unconf Burn address","1.5")
|
||||
|
||||
|
||||
cy.get('#hot_elements_device_2_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_2_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#hot_elements_device_3_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_3_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
// cy.get('#broadcast_local_btn').click()
|
||||
// There is a bug as the first device doesn't seem to have signed and so we can't send the tx just right from here
|
||||
// 2 more clicks until to get to the send button
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('.row > :nth-child(1) > .btn').click()
|
||||
cy.get('#send_tx_btn').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
// gets redirected to "transactions"
|
||||
cy.get('#fullbalance_amount', { timeout: 10000})
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
// Strange bug, not needed here
|
||||
// cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
// cy.get('.row > :nth-child(2) > .btn').click()
|
||||
|
||||
})
|
||||
})
|
||||
114
cypress/integration/spec_elm_single_segwit_wallet.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
describe('Operating with an elements singlesig wallet', () => {
|
||||
it('Creates a single sig elements hot wallet', () => {
|
||||
cy.viewport(1300,660)
|
||||
cy.visit('/')
|
||||
cy.get('#node-switch-icon').click()
|
||||
cy.get('#elements_node-select-node-form > .item > div').click()
|
||||
|
||||
// Delete Wallet if existing
|
||||
cy.deleteWallet("Elm Single Segwit Hot Wallet")
|
||||
cy.deleteWallet("Elm Single Nested Hot Wallet")
|
||||
|
||||
cy.addHotDevice("Hot Elements Device 1","elements")
|
||||
|
||||
// Segwit Wallet
|
||||
cy.addHotWallet("Elm Single Segwit Hot Wallet","elements", "segwit")
|
||||
|
||||
// Nested Segwit Wallet
|
||||
cy.addHotWallet("Elm Single Nested Hot Wallet","elements", "nested_segwit")
|
||||
})
|
||||
|
||||
it('send confidential transaction from segwit', () => {
|
||||
cy.viewport(1300,660)
|
||||
cy.visit('/')
|
||||
cy.contains("Elm Single Segwit Hot Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("el1qqdsywea5scrn7t9q83fd540pw447h0uae30pdp82rzgkl7yzvjz6gra9ls8qu6sslw4s0ck48we06zhqd6kwjy2quh69zwxwn", "Burn address","1.5")
|
||||
cy.get('#hot_elements_device_1_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_1_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
cy.get('.row > :nth-child(2) > .btn').click()
|
||||
})
|
||||
|
||||
it('send unconfidential transaction from segwit', () => {
|
||||
cy.viewport(1300,660)
|
||||
cy.visit('/')
|
||||
cy.contains("Elm Single Segwit Hot Wallet").click()
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("ert1q38la37ulxgc0uwt334he46eua7h8qagqnlm5phcqk7ntgv3x73cqjtr2fa", "Burn address","1.5")
|
||||
cy.get('#hot_elements_device_1_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_1_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('send confidential transaction from nested segwit', () => {
|
||||
cy.viewport(1300,660)
|
||||
cy.visit('/')
|
||||
cy.contains("Elm Single Nested Hot Wallet").click()
|
||||
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("el1qqdsywea5scrn7t9q83fd540pw447h0uae30pdp82rzgkl7yzvjz6gra9ls8qu6sslw4s0ck48we06zhqd6kwjy2quh69zwxwn", "Burn address","1.5")
|
||||
cy.get('#hot_elements_device_1_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_1_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
|
||||
// Workaround: Transaction does not disappear
|
||||
cy.get('#btn_send').click()
|
||||
// The "delete" button in the first psbt
|
||||
cy.get('.row > :nth-child(2) > .btn').click()
|
||||
})
|
||||
|
||||
it('send unconfidential transaction from nested segwit', () => {
|
||||
cy.viewport(1300,660)
|
||||
cy.visit('/')
|
||||
cy.contains("Elm Single Nested Hot Wallet").click()
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
expect(oldBalance).to.be.gte(1.5)
|
||||
cy.createPsbt("ert1q38la37ulxgc0uwt334he46eua7h8qagqnlm5phcqk7ntgv3x73cqjtr2fa", "Burn address","1.5")
|
||||
cy.get('#hot_elements_device_1_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_1_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const newBalance = parseFloat($div.text())
|
||||
expect(newBalance).to.be.lte(oldBalance - 1.5)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
describe('Send transactions from elements wallets', () => {
|
||||
it('Creates a single sig elements hot wallet on specter and send transaction', () => {
|
||||
cy.viewport(1200,660)
|
||||
cy.visit('/')
|
||||
cy.get('#node-switch-icon').click()
|
||||
cy.get('#elements_node-select-node-form > .item > div').click()
|
||||
// empty so far
|
||||
cy.addHotDevice("Hot Elements Device 1","elements")
|
||||
//cy.addHotWallet("Test Elements Hot Wallet","elements")
|
||||
cy.addHotWallet("Test Elements Hot Wallet 1","elements")
|
||||
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#address_0').type("el1qqdsywea5scrn7t9q83fd540pw447h0uae30pdp82rzgkl7yzvjz6gra9ls8qu6sslw4s0ck48we06zhqd6kwjy2quh69zwxwn")
|
||||
cy.get('#label_0').type("Burn address")
|
||||
cy.get('#send_max_0').click()
|
||||
cy.get('#create_psbt_btn').click()
|
||||
// To be done:
|
||||
/* cy.get('body').contains("Paste signed transaction")
|
||||
cy.get('#hot_elements_device_1_tx_sign_btn').click()
|
||||
cy.get('#hot_elements_device_1_hot_sign_btn').click()
|
||||
cy.get('#hot_enter_passphrase__submit').click()
|
||||
cy.get('#broadcast_local_btn').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.equals(0)
|
||||
}) */
|
||||
})
|
||||
})
|
||||
|
|
@ -20,15 +20,10 @@ describe('Node Configured', () => {
|
|||
// Download PDF
|
||||
// unfortunately this results in weird effects in cypress run
|
||||
//cy.get('#pdf-wallet-download > img').click()
|
||||
cy.task("btc:mine")
|
||||
cy.wait(10000)
|
||||
cy.get('#btn_continue').click()
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.gt(0).and.be.lte(50)
|
||||
})
|
||||
|
||||
cy.mine2wallet("btc")
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,15 +22,9 @@ describe('Send transactions from bitcoin hotwallets', () => {
|
|||
// unfortunately this results in weird effects in cypress run
|
||||
//cy.get('#pdf-wallet-download > img').click()
|
||||
cy.get('#btn_continue').click()
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.task("btc:mine")
|
||||
cy.wait(10000)
|
||||
cy.get('#wallets-loading-done-refresh', { timeout: 10000 }).click()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.gt(0).and.be.lte(50)
|
||||
})
|
||||
//get some funds
|
||||
cy.mine2wallet("btc")
|
||||
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#address_0').type("bcrt1qsj30deg0fgzckvlrn5757yk55yajqv6dqx0x7u")
|
||||
cy.get('#label_0').type("Burn address")
|
||||
|
|
@ -70,16 +64,10 @@ describe('Send transactions from bitcoin hotwallets', () => {
|
|||
cy.get('body').contains("New wallet was created successfully!")
|
||||
cy.get('#page_overlay_popup_cancel_button').click()
|
||||
// Send transaction
|
||||
cy.task("btc:mine")
|
||||
cy.wait(10000)
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.get('#wallets-loading-done-refresh', { timeout: 10000 }).click()
|
||||
cy.reload()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.gt(0).and.be.lte(50)
|
||||
})
|
||||
|
||||
//get some funds
|
||||
cy.mine2wallet("btc")
|
||||
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#address_0').type("bcrt1qsj30deg0fgzckvlrn5757yk55yajqv6dqx0x7u")
|
||||
cy.get('#label_0').type("Burn address")
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ Cypress.Commands.add("addDevice", (name) => {
|
|||
Cypress.Commands.add("addHotDevice", (name, node_type) => {
|
||||
// node_type is either elements or bitcoin
|
||||
cy.get('body').then(($body) => {
|
||||
cy.task("delete:elements-hotwallet")
|
||||
//cy.task("delete:elements-hotwallet")
|
||||
if ($body.text().includes(name)) {
|
||||
cy.get('#devices_list > .item > div').click()
|
||||
var refName = "#device_list_item_"+name.toLowerCase().replace(/ /g,"_")
|
||||
cy.get(refName).click()
|
||||
cy.get('#forget_device').click()
|
||||
}
|
||||
cy.get('#side-content').click()
|
||||
|
|
@ -72,7 +73,10 @@ Cypress.Commands.add("addHotDevice", (name, node_type) => {
|
|||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add("addHotWallet", (name, node_type, single_multi) => {
|
||||
Cypress.Commands.add("addHotWallet", (name, node_type, wallet_type, single_multi) => {
|
||||
if (wallet_type == null) {
|
||||
wallet_type = "segwit"
|
||||
}
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.text().includes(name)) {
|
||||
cy.contains(name).click()
|
||||
|
|
@ -87,21 +91,66 @@ Cypress.Commands.add("addHotWallet", (name, node_type, single_multi) => {
|
|||
cy.get('[href="./simple/"]').click()
|
||||
cy.get('#hot_elements_device_1').click()
|
||||
cy.get('#wallet_name').type(name)
|
||||
if (wallet_type == "nested_segwit") {
|
||||
cy.get(':nth-child(1) > #type_nested_segwit_btn').click()
|
||||
}
|
||||
// Create Wallet button:
|
||||
cy.get('#keysform > .centered').click()
|
||||
cy.get('body').contains("New wallet was created successfully!")
|
||||
// // Download PDF
|
||||
// // unfortunately this results in weird effects in cypress run
|
||||
// //cy.get('#pdf-wallet-download > img').click()
|
||||
cy.get('#btn_continue').click()
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.task("elm:mine")
|
||||
cy.wait(4000)
|
||||
|
||||
//Get some funds
|
||||
cy.mine2wallet("elm")
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add("deleteWallet", (name) => {
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.text().includes(name)) {
|
||||
cy.contains(name).click()
|
||||
cy.get('#btn_settings').click()
|
||||
cy.get('#advanced_settings_tab_btn').click()
|
||||
cy.get('#delete_wallet').click()
|
||||
// That does not seem to delete the wallet-file in elements, though
|
||||
// So let's do that as well
|
||||
cy.task("delete:elements-hotwallet")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add("mine2wallet", (chain) => {
|
||||
// Fund it and check the balance
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.get('#fullbalance_amount').then(($div) => {
|
||||
const oldBalance = parseFloat($div.text())
|
||||
if (chain=="elm") {
|
||||
cy.task("elm:mine")
|
||||
} else if (chain=="btc") {
|
||||
cy.task("btc:mine")
|
||||
} else {
|
||||
throw new Error("Unknown chain: " + chain)
|
||||
}
|
||||
cy.wait(10000)
|
||||
cy.reload()
|
||||
cy.get('#fullbalance_amount')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.gt(0).and.be.lte(50)
|
||||
})
|
||||
const n = parseFloat($div.text())
|
||||
expect(n).to.be.gt(oldBalance)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
// Quick and easy way to fill out the send form and create a psbt
|
||||
Cypress.Commands.add("createPsbt", (address, label="a_label", amount=0.01) => {
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#address_0').type(address)
|
||||
cy.get('#label_0').type(label)
|
||||
//cy.get('#send_max_0').click()
|
||||
cy.get('#amount_0').type(amount)
|
||||
cy.get('#create_psbt_btn').click()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from ubuntu:focal
|
|||
# 3. cypress dependencies
|
||||
RUN apt update && DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
|
||||
libusb-1.0-0-dev libudev-dev python3 python3-virtualenv \
|
||||
build-essential libtool autotools-dev automake pkg-config bsdmainutils libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev bc \
|
||||
build-essential libtool autotools-dev automake autoconf pkg-config bsdmainutils libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev bc \
|
||||
nodejs npm libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
|
||||
|
||||
# Stuff needed for Elements (compilation)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ While installing, make sure you know the locations of where that stuff is instal
|
|||
|
||||
Now open and check the "Environment-variables" and check that the following lines are in there:
|
||||
|
||||

|
||||

|
||||
|
||||
## Runner
|
||||
|
||||
|
|
|
|||
106
docs/elements.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Elements/Liquid Support
|
||||
Since `v1.5.0`, Specter-Desktop has basic Elements/Liquid Support. You can run/connect your own elements/liquid-node, you can create Liquid-Hotwallets and even combine them to multisig-wallets. Multisig with three hotwallets is indeed not that useful, but it's a start. We're planning to also support different assets (and might even have that already) and also support for Jade and specter-DIY.
|
||||
|
||||
This document is a description on how to get started with elements/liquid. We'll first go into the details of setting up the node, mostly referring to external documents. Note that you have to checkout elements from source in order to get it running. The latest release `elements-0.18-1.12` is __not__ enough.
|
||||
|
||||
We'll first describe how to Compile elements, how to setup a liquid-node conveniently.
|
||||
|
||||
After that, we'll explain how to connect your Specter Desktop to that node, create wallets and receive some coins (via sideshift.ai). Signing transactions is nowhere different than in any other Hotwallet.
|
||||
|
||||
# Elements Compilation
|
||||
|
||||
Currently you have to checkout and compile elements yourself. You'll need to checkout the master-branch. If you want to be very sure that the collaboration works, you should checkout the exact commit which specter uses when doing automatic testing. You can see that commit in this [file](../tests/elements_gitrev_pinned) (currently `1ba24fe9b3cc3ad1166ed93a0969602d0c7898ff`).
|
||||
|
||||
You can checkout elements wherever you want as long as the `elementsd` and `elements-cli` will be available on the path or in the `tests/elements/src` folder. We assume here, you'll do the latter. If you have a ubuntu/debian-based linux, please check the easier way below before manually checking out:
|
||||
|
||||
```sh
|
||||
cd tests
|
||||
git clone https://github.com/ElementsProject/elements.git
|
||||
cd elements
|
||||
git checkout 1ba24fe9b3cc3ad1166ed93a0969602d0c7898ff # Use the commit from the file above
|
||||
```
|
||||
|
||||
The rest is very system-specific and we're referring here to the documentation in liquid:
|
||||
* [free-](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-freebsd.md)/[net-](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-netbsd.md)/[open-](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-openbsd.md)BSD
|
||||
* [OsX](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-osx.md)
|
||||
* [Unix/Linux](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-unix.md)
|
||||
* [Windows](https://github.com/ElementsProject/elements/blob/elements-0.18.1.12/doc/build-windows.md)
|
||||
|
||||
If you're running a Debian/Ubuntu-based Linux-System, you can most probably use the script which we're using internally to setup our test-system. This will include the clone/checkout above. So simply start, from the root-folder of the project:
|
||||
|
||||
```sh
|
||||
./tests/install_noded.sh --elements compile
|
||||
```
|
||||
|
||||
Make sure that this is successfull by checking these two files to be existent:
|
||||
|
||||
```sh
|
||||
ls tests/elements/src/elements-cli tests/elements/src/elementsd
|
||||
tests/elements/src/elements-cli tests/elements/src/elementsd
|
||||
```
|
||||
|
||||
# Liquid Node
|
||||
In order to validate Peg-Ins, you'll need RPC-access to your Bitcoin-Core node. I did this with a fullnode, it might also work with a pruned node (not tested, though).
|
||||
|
||||
First, we need to create the `elements.conf` file which is located in the `datadir`. If you don't specify the datadir at startup, the standard-directory is `<homefolder>/.elements/elements.conf`. Here is an example:
|
||||
|
||||
```
|
||||
chain=liquidv1
|
||||
mainchainrpchost=localhost
|
||||
mainchainrpcport=8332
|
||||
mainchainrpcuser=your-username
|
||||
mainchainrpcpassword=your-user-password
|
||||
|
||||
rpcuser=liquiduser
|
||||
rpcpassword=liquidpassword
|
||||
```
|
||||
|
||||
We assume here, that you're running the liquid node on the same machine than the core-node, therefore `localhost`. Get the values for `mainchainrpcuser` and `mainchainrpcpassword` from your `bitcoin.conf`. You can choose `rpcuser` and `rpcpassword` as you like. You'll later need that in specter, to configure access to the elements-node, similiar than to the core-node.
|
||||
|
||||
After that, let's start the `elements-node`. We'll start it simply via the commandline in an extra-terminal. Transforming that to a proper service is beyond the scope of this tutorial.
|
||||
|
||||
```
|
||||
tests/elements/src/elements/elementsd
|
||||
```
|
||||
|
||||
A successfull startup will result in validating the blocks. Currently the blockheight for liquid is at about 1417550. So if it's running as expected, you should see blocks validating, lots of messages like this:
|
||||
|
||||
```
|
||||
2021-07-26T15:31:09Z UpdateTip: new best=cbf3ce54912825928d51c8e49eb86a310b53d98c61da560bd9e95ee62e019cd0 height=1502 version=0x20000000 tx=1512 date='2018-09-28T10:38:59Z' progress=0.002000 cache=0.0MiB(13txo)
|
||||
```
|
||||
|
||||
It took about 12 hours for a full-sync in my case on a Intel Quadcore Gen 6 3.50GHz.
|
||||
|
||||
# Liquid Configuration in Specter
|
||||
|
||||
You're probably familiar with this part. On the upper-left, click on the `two arrows -> connect a new node -> Connect existing node`. Here is a screenshots with the values fitting to the configuration above:
|
||||
|
||||

|
||||
|
||||
After clicking on `save`, the node will get selected. You see something like this in the upper left:
|
||||
|
||||

|
||||
|
||||
As you can your wallets disappeared but your devices did not. The shown wallets are now specific to the Node which has been selected. The node can be switched via the clicking on the two arrows.
|
||||
|
||||

|
||||
|
||||
# Hotwallet-Creation
|
||||
|
||||
The process of creating a Liquid Hotwallet is very similiar to creating a Bitcoin-Core Hotwallet. First you need to create a Hotwallet-Device `Add new device -> Elements Core (hot wallet) -> Continue -> Enter Name -> Continue` (Don't forget to note the seed).
|
||||
After that, you can directly create a single key wallet: `Create single key wallet -> Enter Name -> Create Wallet`. You can download the usual Backup Pdf.
|
||||
|
||||
So if you now get a receive-address, you have to choose between a Confidential and a Unconfidential address.
|
||||
|
||||

|
||||
|
||||
# Fund the wallet
|
||||
|
||||
There are many ways you can fund your wallet. Let's assume you have Bitcoin and want to receive LiquidBtc (LBTC). At [https://sideswap.io/peg-in-out/](https://sideswap.io/peg-in-out/) you can Peg-In some Btc as a service. At [https://sideshift.ai/](https://sideshift.ai/) you can [https://sideshift.ai/btc/liquid](swap) BTC agains LBTC (and [vice versa](https://sideshift.ai/liquid/btc)).
|
||||
|
||||
As an example, let'S choose sideshift.ai to swap some BTC to LBTC.
|
||||
|
||||
   
|
||||
|
||||

|
||||
|
||||
|
Before Width: | Height: | Size: 433 KiB After Width: | Height: | Size: 433 KiB |
|
Before Width: | Height: | Size: 648 KiB After Width: | Height: | Size: 648 KiB |
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 506 KiB |
|
Before Width: | Height: | Size: 470 KiB After Width: | Height: | Size: 470 KiB |
|
Before Width: | Height: | Size: 485 KiB After Width: | Height: | Size: 485 KiB |
|
Before Width: | Height: | Size: 437 KiB After Width: | Height: | Size: 437 KiB |
|
Before Width: | Height: | Size: 446 KiB After Width: | Height: | Size: 446 KiB |
|
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 381 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
BIN
docs/images/elements/liquidconfig.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
docs/images/elements/nav.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/images/elements/nodechoose.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/images/elements/receive.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
docs/images/elements/sideshift1.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/images/elements/sideshift2.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
docs/images/elements/sideshift3.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/images/elements/sideshift4.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/images/elements/txs.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
10
docs/tor.md
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
When using Specter Desktop, there might be certain cases where you would want to make calls over the Tor network. The simplest way to setup Tor integration with Specter Desktop is to click on the Get Started button of the welcome page aand follow the setup wizard, which will install and configure Tor for you. You can also access it but going to Settings -> Tor tab, and clicking on Setup Tor.
|
||||
|
||||
<img width="956" alt="Screen Shot 2021-04-24 at 10 42 08" src="../screenshots/get-started-setup.png">
|
||||
<img width="956" alt="Screen Shot 2021-04-24 at 10 42 08" src="./images/tor/get-started-setup.png">
|
||||
|
||||
<img width="1043" alt="Screen Shot 2021-04-24 at 10 43 42" src="../screenshots/tor-config-setup.png">
|
||||
<img width="1043" alt="Screen Shot 2021-04-24 at 10 43 42" src="./images/tor/tor-config-setup.png">
|
||||
|
||||
These will take you through the one click setup process, just click "Setup Tor" and Specter will take care of installing, configuring and running the Tor daemon.
|
||||
|
||||
<img width="732" alt="Screen Shot 2021-04-24 at 10 42 17" src="../screenshots/setup-tor-daemon.png">
|
||||
<img width="732" alt="Screen Shot 2021-04-24 at 10 42 17" src="./images/tor/setup-tor-daemon.png">
|
||||
|
||||
## Running Specter Desktop over a Tor hidden service
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ Make sure authentication is enabled to avoid access to your Specter by random st
|
|||
|
||||
After setting up authentication, running the hidden service to remotely access specter is as easy as going to the Settings -> Tor tab, scrolling to the bottom and clicking the "Start" button under the "Tor Hidden Service" section.
|
||||
|
||||
<img width="755" alt="Screen Shot 2021-04-24 at 10 58 30" src="../screenshots/tor-hidden-service.png">
|
||||
<img width="755" alt="Screen Shot 2021-04-24 at 10 58 30" src="./images/tor/tor-hidden-service.png">
|
||||
|
||||
## Manual Tor configurations
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ If you're using Specter Desktop on a remote machine and would like to connect to
|
|||
3. Enter your TOR URL
|
||||
4. Switch on "Connect over TOR"
|
||||
|
||||

|
||||

|
||||
|
||||
After saving, Specter will shutdown. Start it again and you should be able to connect to your remote Specter server.
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 189 KiB |
|
|
@ -42,6 +42,12 @@ logger = logging.getLogger(__name__)
|
|||
"--data-dir",
|
||||
help="Specify a (maybe not yet existing) datadir. Works only with --nodocker. (Default is /tmp/bitcoind_plain_datadir)",
|
||||
)
|
||||
@click.option(
|
||||
"--log-stdout",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Will spit out logs on stdout if set",
|
||||
)
|
||||
@click.option(
|
||||
"--mining/--no-mining",
|
||||
default=True,
|
||||
|
|
@ -79,6 +85,7 @@ def bitcoind(
|
|||
nodocker,
|
||||
docker_tag,
|
||||
data_dir,
|
||||
log_stdout,
|
||||
mining,
|
||||
mining_period,
|
||||
reset,
|
||||
|
|
@ -96,6 +103,7 @@ def bitcoind(
|
|||
nodocker,
|
||||
docker_tag,
|
||||
data_dir,
|
||||
log_stdout,
|
||||
mining,
|
||||
mining_period,
|
||||
reset,
|
||||
|
|
@ -114,6 +122,12 @@ def bitcoind(
|
|||
"--data-dir",
|
||||
help="Specify a (maybe not yet existing) datadir. Works only with --nodocker. (Default is /tmp/bitcoind_plain_datadir)",
|
||||
)
|
||||
@click.option(
|
||||
"--log-stdout",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Will spit out logs on stdout if set",
|
||||
)
|
||||
@click.option(
|
||||
"--mining/--no-mining",
|
||||
default=True,
|
||||
|
|
@ -149,6 +163,7 @@ def bitcoind(
|
|||
def elementsd(
|
||||
quiet,
|
||||
data_dir,
|
||||
log_stdout,
|
||||
mining,
|
||||
mining_period,
|
||||
reset,
|
||||
|
|
@ -166,6 +181,7 @@ def elementsd(
|
|||
True, # nodocker
|
||||
None, # docker_tag
|
||||
data_dir,
|
||||
log_stdout,
|
||||
mining,
|
||||
mining_period,
|
||||
reset,
|
||||
|
|
@ -181,6 +197,7 @@ def noded(
|
|||
nodocker,
|
||||
docker_tag,
|
||||
data_dir,
|
||||
log_stdout,
|
||||
mining,
|
||||
mining_period,
|
||||
reset,
|
||||
|
|
@ -250,12 +267,14 @@ def noded(
|
|||
cleanup_at_exit=True,
|
||||
cleanup_hard=cleanuphard,
|
||||
datadir=data_dir,
|
||||
log_stdout=log_stdout,
|
||||
)
|
||||
elif node_impl == "elements":
|
||||
my_node.start_elementsd(
|
||||
cleanup_at_exit=True,
|
||||
cleanup_hard=cleanuphard,
|
||||
datadir=data_dir,
|
||||
log_stdout=log_stdout,
|
||||
)
|
||||
except docker.errors.ImageNotFound:
|
||||
echo(f"Image with tag {docker_tag} does not exist!")
|
||||
|
|
@ -267,6 +286,8 @@ def noded(
|
|||
if str(e).startswith("There is already a node running!"):
|
||||
echo(f"{e} please reset via:")
|
||||
echo(f"python3 -m cryptoadvance.specter {node_impl}d --reset")
|
||||
else:
|
||||
raise e
|
||||
if not nodocker:
|
||||
tags_of_image = [
|
||||
image.split(":")[-1] for image in my_node.btcd_container.image.tags
|
||||
|
|
|
|||
|
|
@ -161,6 +161,11 @@ class Device:
|
|||
"single key" if wallet_type == "simple" else "multisig"
|
||||
)
|
||||
|
||||
@property
|
||||
def ref4name(self):
|
||||
"""Device have names and sometimes you want a referenable string from that name. Is there a better name for that than ref4name ?"""
|
||||
return self.name.lower().replace(" ", "_")
|
||||
|
||||
def __eq__(self, other):
|
||||
if other is None:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import json
|
||||
import logging
|
||||
import pathlib
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
||||
from ..helpers import alias, load_jsons
|
||||
|
|
@ -36,8 +37,7 @@ class DeviceManager:
|
|||
if data_folder.startswith("~"):
|
||||
data_folder = os.path.expanduser(data_folder)
|
||||
# creating folders if they don't exist
|
||||
if not os.path.isdir(data_folder):
|
||||
os.mkdir(data_folder)
|
||||
pathlib.Path(data_folder).mkdir(parents=True, exist_ok=True)
|
||||
devices = {}
|
||||
devices_files = load_jsons(self.data_folder, key="name")
|
||||
for device_alias in devices_files:
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class BitcoindPlainController(NodePlainController):
|
|||
cleanup_at_exit=False,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
timeout=60,
|
||||
):
|
||||
|
|
@ -46,6 +47,7 @@ class BitcoindPlainController(NodePlainController):
|
|||
cleanup_at_exit,
|
||||
cleanup_hard,
|
||||
datadir,
|
||||
log_stdout,
|
||||
extra_args,
|
||||
timeout,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class BitcoindDockerController(NodeController):
|
|||
cleanup_at_exit=False,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
timeout=60,
|
||||
):
|
||||
|
|
@ -38,6 +39,7 @@ class BitcoindDockerController(NodeController):
|
|||
cleanup_at_exit,
|
||||
cleanup_hard,
|
||||
datadir,
|
||||
log_stdout,
|
||||
extra_args,
|
||||
timeout,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class ElementsPlainController(NodePlainController):
|
|||
cleanup_at_exit=False,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
timeout=60,
|
||||
):
|
||||
|
|
@ -43,6 +44,7 @@ class ElementsPlainController(NodePlainController):
|
|||
cleanup_at_exit,
|
||||
cleanup_hard,
|
||||
datadir,
|
||||
log_stdout,
|
||||
extra_args,
|
||||
timeout,
|
||||
)
|
||||
|
|
@ -56,6 +58,7 @@ class ElementsPlainController(NodePlainController):
|
|||
rpcconn,
|
||||
run_docker=True,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
node_path="elementsd",
|
||||
network="regtest", # Doesn't make sense here. For now, only "elreg" is supported
|
||||
extra_args=[],
|
||||
|
|
@ -75,10 +78,12 @@ class ElementsPlainController(NodePlainController):
|
|||
)
|
||||
btcd_cmd += " -rpcallowip=0.0.0.0/0 -rpcallowip=172.17.0.0/16 "
|
||||
if not run_docker:
|
||||
btcd_cmd += " -noprinttoconsole"
|
||||
if not log_stdout:
|
||||
btcd_cmd += " -noprinttoconsole"
|
||||
if datadir == None:
|
||||
datadir = tempfile.mkdtemp(prefix="bitcoind_datadir")
|
||||
btcd_cmd += ' -datadir="{}" '.format(datadir)
|
||||
print(f"extra_args={extra_args})")
|
||||
if extra_args:
|
||||
btcd_cmd += " {}".format(" ".join(extra_args))
|
||||
logger.debug("constructed elementsd-command: %s", btcd_cmd)
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ class NodeController:
|
|||
cleanup_at_exit=False,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
timeout=60,
|
||||
):
|
||||
|
|
@ -146,6 +147,7 @@ class NodeController:
|
|||
cleanup_at_exit,
|
||||
cleanup_hard=cleanup_hard,
|
||||
datadir=datadir,
|
||||
log_stdout=log_stdout,
|
||||
extra_args=extra_args,
|
||||
)
|
||||
try:
|
||||
|
|
@ -204,7 +206,12 @@ class NodeController:
|
|||
return self.rpcconn.get_rpc()
|
||||
|
||||
def _start_node(
|
||||
self, cleanup_at_exit, cleanup_hard=False, datadir=None, extra_args=[]
|
||||
self,
|
||||
cleanup_at_exit,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
):
|
||||
raise Exception(f"This should not be used in the baseclass! self: {self}")
|
||||
|
||||
|
|
@ -226,7 +233,7 @@ class NodeController:
|
|||
address = "el1qqf6tv4n8qp55qc04v4xts5snd9v5uurkry4vskef6lmecahj6c42jt9lnj0432287rs67z9vzq2zvuer036s5mahptwxgyd8k"
|
||||
self.get_rpc().generatetoaddress(block_count, address)
|
||||
|
||||
def testcoin_faucet(self, address, amount=20):
|
||||
def testcoin_faucet(self, address, amount=20, confirm_payment=True):
|
||||
"""an easy way to get some testcoins"""
|
||||
rpc = self.get_rpc()
|
||||
try:
|
||||
|
|
@ -256,6 +263,9 @@ class NodeController:
|
|||
if btc_balance > amount:
|
||||
break
|
||||
default_rpc.sendtoaddress(address, amount)
|
||||
if confirm_payment:
|
||||
# confirm it
|
||||
rpc.generatetoaddress(1, default_address)
|
||||
|
||||
@staticmethod
|
||||
def check_node(rpcconn, raise_exception=False):
|
||||
|
|
@ -324,6 +334,7 @@ class NodeController:
|
|||
rpcconn,
|
||||
run_docker=True,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
node_path="bitcoind",
|
||||
network="regtest",
|
||||
extra_args=[],
|
||||
|
|
@ -341,7 +352,8 @@ class NodeController:
|
|||
)
|
||||
btcd_cmd += " -rpcallowip=0.0.0.0/0 -rpcallowip=172.17.0.0/16 "
|
||||
if not run_docker:
|
||||
btcd_cmd += " -noprinttoconsole"
|
||||
if not log_stdout:
|
||||
btcd_cmd += " -noprinttoconsole"
|
||||
if datadir == None:
|
||||
datadir = tempfile.mkdtemp(prefix="bitcoind_datadir")
|
||||
btcd_cmd += ' -datadir="{}" '.format(datadir)
|
||||
|
|
@ -379,7 +391,12 @@ class NodePlainController(NodeController):
|
|||
raise e
|
||||
|
||||
def _start_node(
|
||||
self, cleanup_at_exit=True, cleanup_hard=False, datadir=None, extra_args=[]
|
||||
self,
|
||||
cleanup_at_exit=True,
|
||||
cleanup_hard=False,
|
||||
datadir=None,
|
||||
log_stdout=False,
|
||||
extra_args=[],
|
||||
):
|
||||
if datadir == None:
|
||||
datadir = tempfile.mkdtemp(
|
||||
|
|
@ -391,6 +408,7 @@ class NodePlainController(NodeController):
|
|||
self.rpcconn,
|
||||
run_docker=False,
|
||||
datadir=datadir,
|
||||
log_stdout=log_stdout,
|
||||
node_path=self.node_path,
|
||||
network=self.network,
|
||||
extra_args=extra_args,
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ class BitcoinRPC:
|
|||
)
|
||||
self.r = r
|
||||
if r.status_code != 200:
|
||||
logger.debug(f"last call FAILED: {r.text} (raising RpcError)")
|
||||
raise RpcError(
|
||||
"Server responded with error code %d: %s" % (r.status_code, r.text), r
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
- device_alias: Active device alias.
|
||||
#}
|
||||
{% macro sidebar_device_list_item(device, device_alias) -%}
|
||||
<a href="{{ url_for('devices_endpoint.device', device_alias=device.alias) }}" class="item {% if device_alias == device.alias %}active{% endif %}">
|
||||
<a href="{{ url_for('devices_endpoint.device', device_alias=device.alias) }}" class="item {% if device_alias == device.alias %}active{% endif %}" id="device_list_item_{{ device.ref4name }}">
|
||||
<img src="{{ url_for('static', filename='img/devices/' ~ device.icon) }}" width="22px">
|
||||
<div>
|
||||
{{ device.name }}<br>
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
<label>
|
||||
<input type="radio" name="type" value="{{'sh-wsh' if wallet_type == 'multisig' else 'sh-wpkh'}}"
|
||||
class="hidden" onchange="updateType(this.value);">
|
||||
<div class="btn radio left">{{ _("Nested Segwit") }}</div>
|
||||
<div class="btn radio left" id="type_nested_segwit_btn">{{ _("Nested Segwit") }}</div>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="type" value="{{'wsh' if wallet_type == 'multisig' else 'wpkh'}}" checked
|
||||
class="hidden" onchange="updateType(this.value);">
|
||||
<div class="btn radio right">{{ _("Segwit") }}</div>
|
||||
class="hidden type_nested_segwit" onchange="updateType(this.value);">
|
||||
<div class="btn radio right" id="type_nested_segwit_btn">{{ _("Segwit") }}</div>
|
||||
</label>
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
|
|
@ -611,6 +611,7 @@ class Wallet:
|
|||
self.full_utxo = sorted(utxo, key=lambda utxo: utxo["time"], reverse=True)
|
||||
except Exception as e:
|
||||
self.full_utxo = []
|
||||
logger.exception(e)
|
||||
raise SpecterError(f"Failed to load utxos, {e}")
|
||||
|
||||
def getdata(self):
|
||||
|
|
|
|||
1
tests/elements_gitrev_pinned
Normal file
|
|
@ -0,0 +1 @@
|
|||
1ba24fe9b3cc3ad1166ed93a0969602d0c7898ff
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
# fail early
|
||||
set -o pipefail
|
||||
|
||||
# chenage to the directory the script is located in
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )/."
|
||||
|
|
@ -63,7 +65,7 @@ function maybe_update {
|
|||
else
|
||||
echo " --> Pinned: $PINNED! Checkout needed!"
|
||||
git fetch
|
||||
git checkout $PINNED || exit 1
|
||||
git checkout $PINNED
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
|
@ -113,9 +115,9 @@ function build_node_impl {
|
|||
# optimizing for speed would use the maximum threads available:
|
||||
#make -j$(nproc)
|
||||
# but we're optimizing for mem-allocation. 1 thread is quite slow, let's try 4 (we have 4GB and need to find the sweet-spot)
|
||||
make -j3
|
||||
make -j2
|
||||
cd ../.. #travis is sourcing this script
|
||||
echo " --> Finished build bitcoind"
|
||||
echo " --> Finished build $node_impl"
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -129,8 +131,24 @@ function sub_help {
|
|||
|
||||
}
|
||||
|
||||
function check_compile_prerequisites {
|
||||
REQUIRED_PKGS="build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 autoconf"
|
||||
REQUIRED_PKGS="$REQUIRED_PKGS libevent-dev libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev bc nodejs npm libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb"
|
||||
for REQUIRED_PKG in $REQUIRED_PKGS; do
|
||||
PKG_OK=$(dpkg-query -W --showformat='${Status}\n' $REQUIRED_PKG|grep "install ok installed")
|
||||
echo Checking for $REQUIRED_PKG: $PKG_OK
|
||||
if [ "" = "$PKG_OK" ]; then
|
||||
echo "No $REQUIRED_PKG. Setting up $REQUIRED_PKG."
|
||||
echo "WARNING: THIS SHOULD NOT BE NECESSARY, PLEASE FIX!"
|
||||
apt-get --yes install $REQUIRED_PKG
|
||||
fi
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
function sub_compile {
|
||||
START=$(date +%s.%N)
|
||||
check_compile_prerequisites
|
||||
node_impl=$1
|
||||
echo " --> install_node.sh Start $(date) (compiling for $node_impl)"
|
||||
echo " checkout ..."
|
||||
|
|
@ -147,7 +165,7 @@ function sub_compile {
|
|||
}
|
||||
|
||||
function sub_binary {
|
||||
echo " --> install_bitcoind.sh Start $(date) (binary)"
|
||||
echo " --> install_noded.sh Start $(date) (binary)"
|
||||
START=$(date +%s.%N)
|
||||
cd tests
|
||||
# todo: Parametrize this
|
||||
|
|
@ -165,7 +183,7 @@ function sub_binary {
|
|||
echo " --> Finished installing bitcoind binary"
|
||||
END=$(date +%s.%N)
|
||||
DIFF=$(echo "$END - $START" | bc)
|
||||
echo " --> install_bitcoind.sh End $(date) took $DIFF"
|
||||
echo " --> install_noded.sh End $(date) took $DIFF"
|
||||
}
|
||||
|
||||
function parse_and_execute() {
|
||||
|
|
@ -58,9 +58,26 @@ def test_rr_psbt_get(client, caplog):
|
|||
assert data["result"] == []
|
||||
|
||||
|
||||
def test_rr_psbt_post(client, caplog):
|
||||
def test_rr_psbt_post(specter_regtest_configured, client, caplog):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
""" testing the registration """
|
||||
|
||||
headers = {
|
||||
"Authorization": "Basic "
|
||||
+ base64.b64encode(bytes("someuser" + ":" + "somepassword", "ascii")).decode(
|
||||
"ascii"
|
||||
),
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
|
||||
result = client.get(
|
||||
"/api/v1alpha/wallets/a_simple_wallet/",
|
||||
follow_redirects=True,
|
||||
headers=headers,
|
||||
)
|
||||
# Why the heck does this fail?
|
||||
# assert json.loads(result.data)["a_simple_wallet"]["info"]["balance"] > 0
|
||||
|
||||
result = client.post(
|
||||
"/api/v1alpha/wallets/some_wallet/psbt",
|
||||
data=dict(address="someaddress", amount=0.5),
|
||||
|
|
@ -71,20 +88,13 @@ def test_rr_psbt_post(client, caplog):
|
|||
"The server could not verify that you are authorized to access the URL requested."
|
||||
)
|
||||
|
||||
headers = {
|
||||
"Authorization": "Basic "
|
||||
+ base64.b64encode(bytes("someuser" + ":" + "somepassword", "ascii")).decode(
|
||||
"ascii"
|
||||
),
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
result = client.post(
|
||||
"/api/v1alpha/wallets/a_simple_wallet/psbt",
|
||||
data="""
|
||||
{
|
||||
"recipients" : [
|
||||
{
|
||||
"address": "BCRT1qgc6h85z43g3ss2dl5zdrzrp3ef6av4neqcqhh8",
|
||||
"address": "bcrt1qgc6h85z43g3ss2dl5zdrzrp3ef6av4neqcqhh8",
|
||||
"amount": 0.1,
|
||||
"unit": "btc",
|
||||
"label": "someLabel"
|
||||
|
|
|
|||
|
|
@ -101,7 +101,9 @@ def test_WalletImporter_integration(specter_regtest_configured, bitcoin_regtest)
|
|||
dm: DeviceManager = someuser.device_manager
|
||||
wallet = wallet_importer.create_wallet(someuser.wallet_manager)
|
||||
# fund it with some coins
|
||||
bitcoin_regtest.testcoin_faucet(address=wallet.getnewaddress())
|
||||
bitcoin_regtest.testcoin_faucet(
|
||||
address=wallet.getnewaddress(), confirm_payment=False
|
||||
)
|
||||
# Realize that the wallet has funds:
|
||||
wallet.update()
|
||||
wallet = someuser.wallet_manager.get_by_alias("another_simple_wallet")
|
||||
|
|
|
|||
|
|
@ -133,14 +133,25 @@ function start_node {
|
|||
if [ "$node_impl" = "bitcoind" ]; then
|
||||
echo "--> Purging $BTCD_REGTEST_DATA_DIR"
|
||||
rm -rf $BTCD_REGTEST_DATA_DIR
|
||||
node_impl_abbrev=btcd
|
||||
else
|
||||
echo "--> Purging $ELMD_REGTEST_DATA_DIR"
|
||||
rm -rf $ELMD_REGTEST_DATA_DIR
|
||||
node_impl_abbrev=elmd
|
||||
fi
|
||||
fi
|
||||
if [ "$CLEANUPHARD" = "true" ]; then
|
||||
addopts="--cleanuphard"
|
||||
fi
|
||||
if [ "$node_impl" = "bitcoind" ]; then
|
||||
if [ "$BTCLOGSTDOUT" = "true" ]; then
|
||||
addopts="--log-stdout"
|
||||
fi
|
||||
else
|
||||
if [ "$ELMLOGSTDOUT" = "true" ]; then
|
||||
addopts="--log-stdout"
|
||||
fi
|
||||
fi
|
||||
if [ "$DOCKER" != "true" ]; then
|
||||
if [ "$node_impl" != "elementsd" ]; then # no docker for elementsd yet
|
||||
addopts="$addopts --nodocker"
|
||||
|
|
@ -154,9 +165,11 @@ function start_node {
|
|||
elementsd_pid=$!
|
||||
fi
|
||||
|
||||
while ! [ -f ./btcd-conn.json ] ; do
|
||||
echo "--> Waiting for Starting ${node_impl_abbrev}-conn.json to be created ..."
|
||||
while ! [ -f ./${node_impl_abbrev}-conn.json ] ; do
|
||||
sleep 0.5
|
||||
done
|
||||
echo "--> ${node_impl_abbrev}-conn.json created ..."
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -378,6 +391,10 @@ function parse_and_execute() {
|
|||
DEBUG=--debug
|
||||
shift
|
||||
;;
|
||||
--elm-log-stdout)
|
||||
ELMLOGSTDOUT=true
|
||||
shift
|
||||
;;
|
||||
--docker)
|
||||
DOCKER=true
|
||||
shift
|
||||
|
|
|
|||