Skip to content

Commit

Permalink
Merge branch 'pr/2788'
Browse files Browse the repository at this point in the history
  • Loading branch information
Beerosagos committed Oct 17, 2024
2 parents 750aae2 + 83a57a8 commit cbf7514
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased
- Android: enable export logs feature
- Label UTXOs that were created as change, as such, in coin control

# 4.45.0
- Bundle BitBox02 firmware version v9.21.0
Expand Down
26 changes: 16 additions & 10 deletions backend/coins/btc/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,15 +717,7 @@ func (account *Account) Transactions() (accounts.OrderedTransactions, error) {
if account.fatalError.Load() {
return nil, errp.New("can't call Transactions() after a fatal error")
}
return account.transactions.Transactions(
func(scriptHashHex blockchain.ScriptHashHex) bool {
for _, subacc := range account.subaccounts {
if subacc.changeAddresses.LookupByScriptHashHex(scriptHashHex) != nil {
return true
}
}
return false
})
return account.transactions.Transactions(account.IsChange)
}

// GetUnusedReceiveAddresses returns a number of unused addresses. Returns nil if the account is not initialized.
Expand Down Expand Up @@ -861,6 +853,7 @@ type SpendableOutput struct {
*transactions.SpendableOutput
OutPoint wire.OutPoint
Address *addresses.AccountAddress
IsChange bool
}

// SpendableOutputs returns the utxo set, sorted by the value descending.
Expand All @@ -873,12 +866,14 @@ func (account *Account) SpendableOutputs() []*SpendableOutput {
panic(err)
}
for outPoint, txOut := range utxos {
scriptHashHex := blockchain.NewScriptHashHex(txOut.TxOut.PkScript)
result = append(
result,
&SpendableOutput{
OutPoint: outPoint,
SpendableOutput: txOut,
Address: account.getAddress(blockchain.NewScriptHashHex(txOut.TxOut.PkScript)),
Address: account.getAddress(scriptHashHex),
IsChange: account.IsChange(scriptHashHex),
})
}
return sortByAddresses(result)
Expand Down Expand Up @@ -907,6 +902,17 @@ func (account *Account) VerifyExtendedPublicKey(signingConfigIndex int) (bool, e
return false, nil
}

// IsChange returns true if there is an address corresponding to the provided scriptHashHex in our
// accounts change address chain. It returns false if no address can be found.
func (account *Account) IsChange(scriptHashHex blockchain.ScriptHashHex) bool {
for _, subacc := range account.subaccounts {
if subacc.changeAddresses.LookupByScriptHashHex(scriptHashHex) != nil {
return true
}
}
return false
}

// SignBTCAddress returns an unused address and makes the user sign a message to prove ownership.
// Input params:
//
Expand Down
36 changes: 28 additions & 8 deletions backend/coins/btc/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package btc_test
package btc

import (
"crypto/sha256"
Expand All @@ -24,7 +24,6 @@ import (

"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts"
accountsTypes "github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts/types"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/blockchain"
blockchainMock "github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/blockchain/mocks"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
Expand All @@ -49,7 +48,7 @@ func mockKeystore() *keystoremock.KeystoreMock {
}
}

func mockAccount(t *testing.T, accountConfig *config.Account) *btc.Account {
func mockAccount(t *testing.T, accountConfig *config.Account) *Account {
t.Helper()
code := coin.CodeTBTC
unit := "TBTC"
Expand All @@ -58,7 +57,7 @@ func mockAccount(t *testing.T, accountConfig *config.Account) *btc.Account {
dbFolder := test.TstTempDir("btc-dbfolder")
defer func() { _ = os.RemoveAll(dbFolder) }()

coin := btc.NewCoin(
coin := NewCoin(
code, "Bitcoin Testnet", unit, coin.BtcUnitDefault, net, dbFolder, nil, explorer, socksproxy.NewSocksProxy(false, ""))

blockchainMock := &blockchainMock.BlockchainMock{}
Expand Down Expand Up @@ -89,7 +88,7 @@ func mockAccount(t *testing.T, accountConfig *config.Account) *btc.Account {
accountConfig = defaultConfig
}

return btc.NewAccount(
return NewAccount(
&accounts.AccountConfig{
Config: accountConfig,
DBFolder: dbFolder,
Expand Down Expand Up @@ -122,7 +121,7 @@ func TestAccount(t *testing.T) {
require.NoError(t, err)
require.Equal(t, accounts.OrderedTransactions{}, transactions)

require.Equal(t, []*btc.SpendableOutput{}, account.SpendableOutputs())
require.Equal(t, []*SpendableOutput{}, account.SpendableOutputs())
}

func TestInsuredAccountAddresses(t *testing.T) {
Expand Down Expand Up @@ -190,11 +189,32 @@ func TestSignAddress(t *testing.T) {
account := mockAccount(t, nil)
require.NoError(t, account.Initialize())
// pt2r is not an available script type in the mocked account.
_, _, err := btc.SignBTCAddress(account, "Hello there", signing.ScriptTypeP2TR)
_, _, err := SignBTCAddress(account, "Hello there", signing.ScriptTypeP2TR)
require.Error(t, err)
address, signature, err := btc.SignBTCAddress(account, "Hello there", signing.ScriptTypeP2WPKH)
address, signature, err := SignBTCAddress(account, "Hello there", signing.ScriptTypeP2WPKH)
require.NoError(t, err)
require.NotEmpty(t, address)
require.Equal(t, base64.StdEncoding.EncodeToString([]byte("signature")), signature)

}

func TestIsChange(t *testing.T) {
account := mockAccount(t, nil)
require.NoError(t, account.Initialize())
require.True(t, account.Synced())
account.ensureAddresses()
for _, subaccunt := range account.subaccounts {
unusedReceiveAddresses, err := subaccunt.receiveAddresses.GetUnused()
require.NoError(t, err)
unusedChangeAddresses, err := subaccunt.changeAddresses.GetUnused()
require.NoError(t, err)
// check IsChange returns true for all change addresses
for _, changeAddress := range unusedChangeAddresses {
require.True(t, account.IsChange(changeAddress.PubkeyScriptHashHex()))
}
// ensure no false positives
for _, address := range unusedReceiveAddresses {
require.False(t, account.IsChange(address.PubkeyScriptHashHex()))
}
}
}
7 changes: 3 additions & 4 deletions backend/coins/btc/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package btc_test
package btc

import (
"encoding/hex"
Expand All @@ -22,7 +22,6 @@ import (
"testing"

"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts/errors"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/blockchain"
blockchainMock "github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/blockchain/mocks"
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
Expand Down Expand Up @@ -52,13 +51,13 @@ type testSuite struct {
net *chaincfg.Params

dbFolder string
coin *btc.Coin
coin *Coin
}

func (s *testSuite) SetupTest() {
s.dbFolder = test.TstTempDir("btc-dbfolder")

s.coin = btc.NewCoin(s.code, "Some coin", s.unit, coin.BtcUnitDefault, s.net, s.dbFolder, nil,
s.coin = NewCoin(s.code, "Some coin", s.unit, coin.BtcUnitDefault, s.net, s.dbFolder, nil,
explorer, socksproxy.NewSocksProxy(false, ""))
blockchainMock := &blockchainMock.BlockchainMock{}
blockchainMock.MockHeadersSubscribe = func(
Expand Down
1 change: 1 addition & 0 deletions backend/coins/btc/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ func (handlers *Handlers) getUTXOs(*http.Request) (interface{}, error) {
"scriptType": output.Address.Configuration.ScriptType(),
"note": handlers.account.TxNote(output.OutPoint.Hash.String()),
"addressReused": addressReused,
"isChange": output.IsChange,
})
}

Expand Down
1 change: 1 addition & 0 deletions frontends/web/src/api/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ export type TUTXO = {
note: string;
scriptType: ScriptType;
addressReused: boolean;
isChange: boolean;
};

export const getUTXOs = (code: AccountCode): Promise<TUTXO[]> => {
Expand Down
6 changes: 6 additions & 0 deletions frontends/web/src/components/badge/badge.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,9 @@
border-color: rgba(255, 0, 0, 0.33);
color: rgba(255, 0, 0, 1);
}

.info {
background: var(--color-info-background);
border-color: var(--color-info-border);
color: var(--color-default);
}
2 changes: 1 addition & 1 deletion frontends/web/src/components/badge/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { ReactElement, ReactNode } from 'react';
import style from './badge.module.css';

type TBadgeStyles = 'success' | 'warning' | 'danger'; // TODO: not yet implemented 'info'
type TBadgeStyles = 'success' | 'warning' | 'danger' | 'info';

type TProps = {
children?: ReactNode;
Expand Down
1 change: 1 addition & 0 deletions frontends/web/src/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,7 @@
"coincontrol": {
"address": "Address",
"addressReused": "Address re-used",
"change": "Change",
"outpoint": "Outpoint",
"title": "Send from output"
},
Expand Down
20 changes: 17 additions & 3 deletions frontends/web/src/routes/account/send/utxos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,23 @@ export const UTXOs = ({
</span>
<div className="m-left-quarter">
{utxo.addressReused ?
<Badge type="danger">
{t('send.coincontrol.addressReused')}
</Badge> :
<>
<Badge type="danger">
{t('send.coincontrol.addressReused')}
</Badge>
{' '}
</>
:
null
}
{utxo.isChange ?
<>
<Badge type="info">
{t('send.coincontrol.change')}
</Badge>
{' '}
</>
:
null
}
</div>
Expand Down

0 comments on commit cbf7514

Please sign in to comment.