Skip to content

Commit

Permalink
[core] [main] [models] [util] refs #230 - Changes in core interfaces …
Browse files Browse the repository at this point in the history
…for transaction signing

- SignServicesForTxn receives Wallet instead of FullWallet
- LoadTransactionAPI returns BlockchainVisor
- ReadyForTxn receives Wallet instance as first argument
  • Loading branch information
olemis committed Feb 12, 2020
1 parent 5687804 commit 4929c49
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/core/cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type AddressIterator interface {
// TxnSigner defines the contract enforced upon objects able to sin transacions.
type TxnSigner interface {
// ReadyForTxn determines whether this signer instance can be used to sign given transaction
ReadyForTxn(Transaction) (bool, error)
ReadyForTxn(Wallet, Transaction) (bool, error)
// DeriveParentPubKey generate watch-only wallet with parent token to derive child public keys
DeriveParentPubKey(chainCode []byte) (WatchWallet, error)
// SignTransaction partially or in full
Expand Down
4 changes: 2 additions & 2 deletions src/core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type AltcoinPlugin interface {
// LoadPEX instantiates proxy object to interact with nodes nodes of the P2P network
LoadPEX(netType string) (PEX, error)
// LoadTransactionAPI blockchain transaction API entry poiny
LoadTransactionAPI(netType string) (BlockchainTransactionAPI, error)
LoadTransactionAPI(netType string) (BlockchainVisor, error)
// LoadSignService sign service entry point
LoadSignService() (BlockchainSignService, error)
// AddressFromString retrieves address correspoding to readable representation
Expand Down Expand Up @@ -75,5 +75,5 @@ type AltcoinManager interface {
// EnumerateSignServices returns an object to iterate over global signing srategies
EnumerateSignServices() TxnSignerIterator
// SignServicesForTxn returns an object to iterate over strategies supported to sign a given transaction on behalf of a wallet
SignServicesForTxn(FullWallet, Transaction) TxnSignerIterator
SignServicesForTxn(Wallet, Transaction) TxnSignerIterator
}
5 changes: 5 additions & 0 deletions src/core/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,8 @@ type WalletEnv interface {
// GetWalletSet loads wallets in this environment
GetWalletSet() WalletSet
}

// WalletObject represents the contract implemented by objects managed by wallets
type WalletObject interface {
GetWallet() Wallet
}
4 changes: 2 additions & 2 deletions src/main/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ func (m *fibercryptoAltcoinManager) RemoveSignService(signSrv core.TxnSigner) er
}

// SignServicesForTxn returns an object to iterate over signing srategies supported for a given transaction
func (m *fibercryptoAltcoinManager) SignServicesForTxn(wlt core.FullWallet, txn core.Transaction) core.TxnSignerIterator {
func (m *fibercryptoAltcoinManager) SignServicesForTxn(wallet core.Wallet, txn core.Transaction) core.TxnSignerIterator {
return signutil.FilterSignersFromMap(
m.signers,
func(signer core.TxnSigner) bool {
canSign, err := signer.ReadyForTxn(wlt, txn)
canSign, err := signer.ReadyForTxn(wallet, txn)
return err == nil && canSign
})
}
4 changes: 2 additions & 2 deletions src/models/walletsManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type WalletManager struct {
outputsByAddress map[string][]*QOutput
altManager core.AltcoinManager
signer core.BlockchainSignService
transactionAPI core.BlockchainTransactionAPI
transactionAPI core.BlockchainVisor

_ func() `slot:"updateWalletEnvs"`
_ func(wltId, address string) `slot:"updateOutputs"`
Expand Down Expand Up @@ -143,7 +143,7 @@ func (walletM *WalletManager) updateSigner() {

func (walletM *WalletManager) updateTransactionAPI() {
logWalletManager.Info("Updating TransactionAPI")
txnAPIS := make([]core.BlockchainTransactionAPI, 0)
txnAPIS := make([]core.BlockchainVisor, 0)

for _, plug := range walletM.altManager.ListRegisteredPlugins() {
txnAPI, err := plug.LoadTransactionAPI("MainNet")
Expand Down
9 changes: 2 additions & 7 deletions src/util/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,12 @@ func TestUnknownPlugin(t *testing.T) {
}

func TestLookupSignerByUID(t *testing.T) {
type WalletSigner struct {
mocks.Wallet
mocks.TxnSigner
}

emptyUID := core.UID("")
uid := core.UID("walletid")
other := core.UID("otherid")

ws := new(WalletSigner)
ws.TxnSigner.On("GetSignerUID").Return(uid)
ws := new(mocks.FullWallet)
ws.On("GetSignerUID").Return(uid)
var signer core.TxnSigner = ws
err := AttachSignService(signer)
defer RemoveSignService(uid) // nolint gosec
Expand Down
2 changes: 1 addition & 1 deletion src/util/pluginutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func RegisterAltcoin(p core.AltcoinPlugin) {
}

// LookupSignerByUID search for signer matching given ID
func LookupSignerByUID(wlt core.FullWallet, id core.UID) core.TxnSigner {
func LookupSignerByUID(wlt core.Wallet, id core.UID) core.TxnSigner {
wltSigner, isSigner := wlt.(core.TxnSigner)
// Reference to self
if id == core.UID("") {
Expand Down
6 changes: 3 additions & 3 deletions src/util/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ func EnumerateSignServices() core.TxnSignerIterator {
}

// SignServicesForTxn returns an object to iterate over strategies supported to sign a given transaction on behalf of a wallet
func SignServicesForTxn(wlt core.FullWallet, txn core.Transaction) core.TxnSignerIterator {
func SignServicesForTxn(wlt core.Wallet, txn core.Transaction) core.TxnSignerIterator {
return local.LoadAltcoinManager().SignServicesForTxn(wlt, txn)
}

// ReadyForTxn determines whether global signer identified by UID can be used by wallet to sign given transaction
func ReadyForTxn(signerID core.UID, wallet core.FullWallet, txn core.Transaction) (bool, error) {
func ReadyForTxn(signerID core.UID, wallet core.Wallet, txn core.Transaction) (bool, error) {
signer := LookupSignService(signerID)
if signer == nil {
return false, errors.ErrInvalidID
Expand Down Expand Up @@ -112,7 +112,7 @@ func GenericMultiWalletSign(txn core.Transaction, signSpec []core.InputSignDescr
logUtil.WithError(err).Errorf("Unknown signer %s specified for signing inputs %v of wallet %v", string(signPair.signerID), indices, signPair.wallet)
return nil, errors.ErrInvalidID
}
signedTxn, err = signPair.wallet.Sign(signedTxn, signer, pwd, indices)
signedTxn, err = signer.SignTransaction(signedTxn, pwd, indices)
if err != nil {
logUtil.WithError(err).Errorf("Error signing inputs %v of wallet %v with signer %s", indices, signPair.wallet, string(signPair.signerID))
return nil, err
Expand Down
8 changes: 5 additions & 3 deletions src/util/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func TestSignTransaction(t *testing.T) {
}

func TestGenericMultiWalletSign(t *testing.T) {
var pwd core.PasswordReader = func(s string, kvs core.KeyValueStore) (string, error){
var pwd core.PasswordReader = func(s string, kvs core.KeyValueStore) (string, error) {
return s, nil
}

Expand All @@ -253,8 +253,10 @@ func TestGenericMultiWalletSign(t *testing.T) {

badTxn := new(mocks.Transaction)
badTxn.On("GetId").Return("bad_txn_id")
wlt.On("Sign", txn, signer, mock.Anything, inputsIdx).Return(txn, nil)
wlt.On("Sign", badTxn, signer, mock.Anything, inputsIdx).Return(txn, errors.ErrInvalidTxn)

signer.On("SignTransaction", txn, mock.Anything, inputsIdx).Return(txn, nil)
signer.On("SignTransaction", badTxn, mock.Anything, inputsIdx).Return(nil, errors.ErrInvalidTxn)

_txn, err := GenericMultiWalletSign(txn, spec, pwd)
require.Equal(t, txn, _txn)
require.Nil(t, err)
Expand Down
72 changes: 62 additions & 10 deletions src/util/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,81 @@ func (wo *SimpleWalletOutput) GetWallet() core.Wallet {
return wo.Wallet
}

// GetOutput return transaction output.
func (wo *SimpleWalletOutput) GetOutput() core.TransactionOutput {
return wo.UxOut
// GetId provides transaction output ID
func (wo *SimpleWalletOutput) GetId() string {
return wo.UxOut.GetId()
}

// IsSpent determines whether there exists a confirmed transaction with an input spending this output
func (wo *SimpleWalletOutput) IsSpent() bool {
return wo.UxOut.IsSpent()
}

// GetAddress returns the address of the party receiving funds
func (wo *SimpleWalletOutput) GetAddress() core.Address {
return wo.UxOut.GetAddress()
}

// GetCoins looks up coins for asset represented by ticker that have been transferred in this output
func (wo *SimpleWalletOutput) GetCoins(ticker string) (uint64, error) {
return wo.UxOut.GetCoins(ticker)
}

// SupportedAssets enumerates tickers of crypto assets supported by this output
func (wo *SimpleWalletOutput) SupportedAssets() []string {
return wo.UxOut.SupportedAssets()
}

// SimpleWalletAddress put together address with owner wallet
type SimpleWalletAddress struct {
Wallet core.Wallet
UxOut core.Address
Wallet core.Wallet
Address core.Address
}

// GetWallet return wallet
func (wa *SimpleWalletAddress) GetWallet() core.Wallet {
return wa.Wallet
}

// GetAddress return address
func (wa *SimpleWalletAddress) GetAddress() core.Address {
return wa.UxOut
// IsBip32 flag shall be set if address generation complies to BIP 32
func (wa *SimpleWalletAddress) IsBip32() bool {
return wa.Address.IsBip32()
}

// String return human-readable representation of this address
func (wa *SimpleWalletAddress) String() string {
return wa.Address.String()
}

// GetCryptoAccount provides access to address transaction history
func (wa *SimpleWalletAddress) GetCryptoAccount() core.CryptoAccount {
return wa.GetCryptoAccount()
}

// Bytes binary representation for address
func (wa *SimpleWalletAddress) Bytes() []byte {
return wa.Bytes()
}

// Checksum computes address consistency token
func (wa *SimpleWalletAddress) Checksum() core.Checksum {
return wa.Checksum()
}

// Verify checks that the address appears valid for the public key
func (wa *SimpleWalletAddress) Verify(pubkey core.PubKey) error {
return wa.Verify(pubkey)
}

// Null returns true if the address is null
func (wa *SimpleWalletAddress) Null() bool {
return wa.Null()
}

// Type assertions
var (
_ core.WalletOutput = &SimpleWalletOutput{}
_ core.WalletAddress = &SimpleWalletAddress{}
_ core.TransactionOutput = &SimpleWalletOutput{}
_ core.WalletObject = &SimpleWalletOutput{}
_ core.Address = &SimpleWalletAddress{}
_ core.WalletObject = &SimpleWalletOutput{}
)
32 changes: 29 additions & 3 deletions src/util/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,42 @@ import (

func TestSimpleWalletAddress(t *testing.T) {
wllt, addr := &mocks.Wallet{}, &mocks.Address{}
wa := &SimpleWalletAddress{Wallet: wllt, UxOut: addr}
wa := &SimpleWalletAddress{Wallet: wllt, Address: addr}
addr.On("String").Return("A1234")
addr.On("IsBip32").Return(true)
addr.On("GetCryptoAccount").Return(new(mocks.CryptoAccount))
addr.On("Bytes").Return([]byte{1, 2, 3, 4})
addr.On("Checksum").Return([]byte{5, 6, 7, 8})
pk1 := new(mocks.PubKey)
pk2 := new(mocks.PubKey)
addr.On("Verify", pk1).Return(true)
addr.On("Verify", pk2).Return(false)

require.Equal(t, wllt, wa.GetWallet())
require.Equal(t, addr, wa.GetAddress())
require.Equal(t, "A1234", wa.String())
require.Equal(t, true, wa.IsBip32())
require.Equal(t, addr.GetCryptoAccount(), wa.GetCryptoAccount())
require.Equal(t, addr.Bytes(), wa.Bytes())
require.Equal(t, addr.Checksum(), wa.Checksum())
require.Equal(t, true, wa.Verify(pk1))
require.Equal(t, false, wa.Verify(pk2))
}

func TestSimpleWalletOutput(t *testing.T) {
wllt, out := &mocks.Wallet{}, &mocks.TransactionOutput{}
wllt.On("GetId").Return("ID1")
wllt.On("IsSpent").Return(true)
wllt.On("GetAddress").Return(new(mocks.Address))
wllt.On("GetCoins", "X").Return(2000, nil)
wllt.On("SupportedAssets").Return([]string{"X", "Y", "Z"})
wa := &SimpleWalletOutput{Wallet: wllt, UxOut: out}

require.Equal(t, wllt, wa.GetWallet())
require.Equal(t, out, wa.GetOutput())
require.Equal(t, "ID1", wa.GetId())
require.Equal(t, true, wa.IsSpent())
require.Equal(t, out.GetAddress(), wa.GetAddress())
coins, err := wa.GetCoins("X")
require.NoError(t, err)
require.Equal(t, 2000, coins)
require.Equal(t, out.SupportedAssets(), wa.SupportedAssets())
}

0 comments on commit 4929c49

Please sign in to comment.