add use.getUseAddress function

This commit is contained in:
fnaticwang 2019-09-24 10:56:14 +08:00
parent f8346a2457
commit a11a67260f
13 changed files with 306 additions and 29 deletions

View file

@ -149,6 +149,9 @@ type Wallet interface {
// SignTxWithPassphrase is identical to SignTx, but also takes a password // SignTxWithPassphrase is identical to SignTx, but also takes a password
SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
// GetUseAddress represents the wallet to retrieve corresponding wanchain public address for a specific ordinary account/address
GetUseAddress(account Account) (common.UAddress, error)
} }
// Backend is a "wallet provider" that may contain a batch of accounts they can // Backend is a "wallet provider" that may contain a batch of accounts they can

View file

@ -203,6 +203,11 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
return res.Tx, nil return res.Tx, nil
} }
// TODO: TBI
func (api *ExternalSigner) GetUseAddress(account accounts.Account) (common.UAddress, error) {
return common.UAddress{}, nil
}
func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
return []byte{}, fmt.Errorf("password-operations not supported on external signers") return []byte{}, fmt.Errorf("password-operations not supported on external signers")
} }

View file

@ -64,6 +64,8 @@ type keyStore interface {
GetKey(addr common.Address, filename string, auth string) (*Key, error) GetKey(addr common.Address, filename string, auth string) (*Key, error)
// Writes and encrypts the key. // Writes and encrypts the key.
StoreKey(filename string, k *Key, auth string) error StoreKey(filename string, k *Key, auth string) error
// Loads an encrypted keyfile from disk
GetEncryptedKey(addr common.Address, filename string) (*Key, error)
// Joins filename with the key directory unless it is already absolute. // Joins filename with the key directory unless it is already absolute.
JoinPath(filename string) string JoinPath(filename string) string
} }

View file

@ -486,6 +486,38 @@ func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (account
return a, nil return a, nil
} }
// getEncryptedKey loads an encrypted keyfile from the disk
func (ks *KeyStore) getEncryptedKey(a accounts.Account) (accounts.Account, *Key, error) {
a, err := ks.Find(a)
if err != nil {
return a, nil, err
}
key, err := ks.storage.GetEncryptedKey(a.Address, a.URL.Path)
if err != nil {
return a, nil, err
}
return a, key, nil
}
// GetUseAddress represents the keystore to retrieve corresponding usechain public address for a specific ordinary account/address
func (ks *KeyStore) GetUseAddress(account accounts.Account) (common.UAddress, error) {
ks.mu.RLock()
defer ks.mu.RUnlock()
unlockedKey, found := ks.unlocked[account.Address]
if !found {
_, ksen, err := ks.getEncryptedKey(account)
if err != nil {
return common.UAddress{}, ErrLocked
}
return ksen.UAddress, nil
}
ret := unlockedKey.UAddress
return ret, nil
}
// zeroKey zeroes a private key in memory. // zeroKey zeroes a private key in memory.
func zeroKey(k *ecdsa.PrivateKey) { func zeroKey(k *ecdsa.PrivateKey) {
b := k.D.Bits() b := k.D.Bits()

View file

@ -139,6 +139,49 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er
return os.Rename(tmpName, filename) return os.Rename(tmpName, filename)
} }
// Implements GetEncryptedKey method of keystore interface
func (ks keyStorePassphrase) GetEncryptedKey(a common.Address, filename string) (*Key, error) {
// load the encrypted json keyfile
keyjson, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
key, err := GenerateKeyWithUAddress(keyjson)
if err != nil {
return nil, err
}
key.Address = a
return key, nil
}
// Generate a Key initialized with UAddress field
func GenerateKeyWithUAddress(keyjson []byte) (*Key, error) {
// parse the json blob into a simple map to fetch the key version
m := make(map[string]interface{})
if err := json.Unmarshal(keyjson, &m); err != nil {
return nil, err
}
uaddress, ok := m["uaddress"].(string)
if !ok || uaddress == "" {
return nil, ErrUAddressFieldNotExist
}
uaddressRaw, err := hex.DecodeString(uaddress)
if err != nil {
return nil, err
}
if len(uaddressRaw) != common.UAddressLength {
return nil, ErrUAddressInvalid
}
key := new(Key)
copy(key.UAddress[:], uaddressRaw)
return key, nil
}
func (ks keyStorePassphrase) JoinPath(filename string) string { func (ks keyStorePassphrase) JoinPath(filename string) string {
if filepath.IsAbs(filename) { if filepath.IsAbs(filename) {
return filename return filename
@ -288,32 +331,59 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
} }
// Depending on the version try to parse one way or another // Depending on the version try to parse one way or another
var ( var (
keyBytes, keyId []byte keyBytes, keyBytes2, keyId []byte
err error err error
uaddressStr *string
) )
if version, ok := m["version"].(string); ok && version == "1" { if version, ok := m["version"].(string); ok && version == "1" {
k := new(encryptedKeyJSONV1) k := new(encryptedKeyJSONV1)
if err := json.Unmarshal(keyjson, k); err != nil { if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err return nil, err
} }
keyBytes, keyId, err = decryptKeyV1(k, auth) keyBytes, keyId, err = decryptKeyV1(k, auth)
key, err := crypto.ToECDSA(keyBytes)
if err != nil || key == nil {
return nil, err
}
return &Key{
Id: uuid.UUID(keyId),
Address: crypto.PubkeyToAddress(key.PublicKey),
PrivateKey: key,
}, nil
} else { } else {
k := new(encryptedKeyJSONV3) k := new(encryptedKeyJSONV3)
if err := json.Unmarshal(keyjson, k); err != nil { if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err return nil, err
} }
keyBytes, keyId, err = decryptKeyV3(k, auth) keyBytes, keyBytes2, keyId, err = decryptKeyV3(k, auth)
if err != nil {
return nil, err
}
uaddressStr = &k.UAddress
} }
// Handle any decryption errors and return the key // Handle any decryption errors and return the key
if err != nil { if err != nil {
return nil, err return nil, err
} }
key := crypto.ToECDSAUnsafe(keyBytes) key := crypto.ToECDSAUnsafe(keyBytes)
key2 := crypto.ToECDSAUnsafe(keyBytes2)
uaddressRaw, err := hex.DecodeString(*uaddressStr)
if err != nil {
return nil, err
}
var uaddress common.UAddress
copy(uaddress[:], uaddressRaw)
return &Key{ return &Key{
Id: uuid.UUID(keyId), Id: uuid.UUID(keyId),
Address: crypto.PubkeyToAddress(key.PublicKey), Address: crypto.PubkeyToAddress(key.PublicKey),
PrivateKey: key, PrivateKey: key,
PrivateKey2: key2,
UAddress: uaddress,
}, nil }, nil
} }
@ -353,16 +423,64 @@ func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) {
return plainText, err return plainText, err
} }
func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyBytes2 []byte, keyId []byte, err error) {
if keyProtected.Version != version { if keyProtected.Version != version {
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) return nil, nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
} }
keyId = uuid.Parse(keyProtected.Id) keyId = uuid.Parse(keyProtected.Id)
plainText, err := DecryptDataV3(keyProtected.Crypto, auth) plainText, err := decryptKeyV3Item(keyProtected.Crypto, auth)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
return plainText, keyId, err
plainText2, err2 := decryptKeyV3Item(keyProtected.Crypto2, auth)
if err2 != nil {
if "" == keyProtected.Crypto2.Cipher {
plainText2 = make([]byte, 0)
} else {
return nil, nil, nil, err2
}
}
return plainText, plainText2, keyId, err
}
func decryptKeyV3Item(cryptoItem CryptoJSON, auth string) (keyBytes []byte, err error) {
if cryptoItem.Cipher != "aes-128-ctr" {
return nil, fmt.Errorf("Cipher not supported: %v", cryptoItem.Cipher)
}
mac, err := hex.DecodeString(cryptoItem.MAC)
if err != nil {
return nil, err
}
iv, err := hex.DecodeString(cryptoItem.CipherParams.IV)
if err != nil {
return nil, err
}
cipherText, err := hex.DecodeString(cryptoItem.CipherText)
if err != nil {
return nil, err
}
derivedKey, err := getKDFKey(cryptoItem, auth)
if err != nil {
return nil, err
}
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
if !bytes.Equal(calculatedMAC, mac) {
return nil, ErrDecrypt
}
plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
if err != nil {
return nil, err
}
return plainText, err
} }
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {

View file

@ -59,3 +59,8 @@ func (ks keyStorePlain) JoinPath(filename string) string {
} }
return filepath.Join(ks.keysDirPath, filename) return filepath.Join(ks.keysDirPath, filename)
} }
// TODO: to be implemented
func (ks keyStorePlain) GetEncryptedKey(a common.Address, filename string) (*Key, error) {
return nil, nil
}

View file

@ -17,10 +17,12 @@
package keystore package keystore
import ( import (
"errors"
"math/big" "math/big"
ethereum "github.com/ethereum/go-ethereum" ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
@ -146,3 +148,25 @@ func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphra
// Account seems valid, request the keystore to sign // Account seems valid, request the keystore to sign
return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID) return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID)
} }
// GetUseAddress represents the wallet to retrieve corresponding usechain public address for a specific ordinary account/address
func (w *keystoreWallet) GetUseAddress(account accounts.Account) (common.UAddress, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return common.UAddress{}, accounts.ErrUnknownAccount
}
if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return common.UAddress{}, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to retrieve
return w.keystore.GetUseAddress(account)
}
func (w *keystoreWallet) GetUnlockedKey(address common.Address) (*Key, error) {
value, ok := w.keystore.unlocked[address]
if !ok {
return nil, errors.New("can not found a unlock key of: " + address.Hex())
}
return value.Key, nil
}

View file

@ -788,6 +788,11 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP
return accounts.ParseDerivationPath(parts[1]) return accounts.ParseDerivationPath(parts[1])
} }
// TODO: TBI
func (w *Wallet) GetUseAddress(account accounts.Account) (common.UAddress, error) {
return common.UAddress{}, nil
}
// Session represents a secured communication session with the wallet. // Session represents a secured communication session with the wallet.
type Session struct { type Session struct {
Wallet *Wallet // A handle to the wallet that opened the session Wallet *Wallet // A handle to the wallet that opened the session

View file

@ -593,3 +593,8 @@ func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase str
func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return w.SignTx(account, tx, chainID) return w.SignTx(account, tx, chainID)
} }
// TODO: TBI
func (w *wallet) GetUseAddress(account accounts.Account) (common.UAddress, error) {
return common.UAddress{}, nil
}

View file

@ -1805,3 +1805,20 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint {
func (s *PublicNetAPI) Version() string { func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion) return fmt.Sprintf("%d", s.networkVersion)
} }
////////////////////added for privacy tx ////////////////////////////////////////
// GetUseAddress returns corresponding UAddress of an ordinary account
func (s *PublicTransactionPoolAPI) GetUseAddress(ctx context.Context, a common.Address) (string, error) {
account := accounts.Account{Address: a}
// first fetch the wallet/keystore, and then retrieve the useaddress
wallet, err := s.b.AccountManager().Find(account)
if err != nil {
return "", err
}
useAddr, err := wallet.GetUseAddress(account)
if err != nil {
return "", err
}
return hexutil.Encode(useAddr[:]), nil
}

View file

@ -96,11 +96,21 @@ func GetAPIs(apiBackend Backend) []rpc.API {
Version: "1.0", Version: "1.0",
Service: NewPublicBlockChainAPI(apiBackend), Service: NewPublicBlockChainAPI(apiBackend),
Public: true, Public: true,
}, {
Namespace: "use",
Version: "1.0",
Service: NewPublicBlockChainAPI(apiBackend),
Public: true,
},{ },{
Namespace: "eth", Namespace: "eth",
Version: "1.0", Version: "1.0",
Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock), Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock),
Public: true, Public: true,
},{
Namespace: "use",
Version: "1.0",
Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock),
Public: true,
},{ },{
Namespace: "txpool", Namespace: "txpool",
Version: "1.0", Version: "1.0",

File diff suppressed because one or more lines are too long

View file

@ -2509,6 +2509,7 @@ module.exports={
var RequestManager = require('./web3/requestmanager'); var RequestManager = require('./web3/requestmanager');
var Iban = require('./web3/iban'); var Iban = require('./web3/iban');
var Eth = require('./web3/methods/eth'); var Eth = require('./web3/methods/eth');
var Use = require('./web3/methods/use');
var DB = require('./web3/methods/db'); var DB = require('./web3/methods/db');
var Shh = require('./web3/methods/shh'); var Shh = require('./web3/methods/shh');
var Net = require('./web3/methods/net'); var Net = require('./web3/methods/net');
@ -2531,6 +2532,7 @@ function Web3 (provider) {
this._requestManager = new RequestManager(provider); this._requestManager = new RequestManager(provider);
this.currentProvider = provider; this.currentProvider = provider;
this.eth = new Eth(this); this.eth = new Eth(this);
this.use = new Use(this);
this.db = new DB(this); this.db = new DB(this);
this.shh = new Shh(this); this.shh = new Shh(this);
this.net = new Net(this); this.net = new Net(this);
@ -2632,7 +2634,7 @@ Web3.prototype.createBatch = function () {
module.exports = Web3; module.exports = Web3;
},{"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/extend":28,"./web3/httpprovider":32,"./web3/iban":33,"./web3/ipcprovider":34,"./web3/methods/db":37,"./web3/methods/eth":38,"./web3/methods/net":39,"./web3/methods/personal":40,"./web3/methods/shh":41,"./web3/methods/swarm":42,"./web3/property":45,"./web3/requestmanager":46,"./web3/settings":47,"bignumber.js":"bignumber.js"}],23:[function(require,module,exports){ },{"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/extend":28,"./web3/httpprovider":32,"./web3/iban":33,"./web3/ipcprovider":34,"./web3/methods/db":37,"./web3/methods/eth":38,"./web3/methods/use":87,"./web3/methods/net":39,"./web3/methods/personal":40,"./web3/methods/shh":41,"./web3/methods/swarm":42,"./web3/property":45,"./web3/requestmanager":46,"./web3/settings":47,"bignumber.js":"bignumber.js"}],23:[function(require,module,exports){
/* /*
This file is part of web3.js. This file is part of web3.js.
@ -5358,6 +5360,13 @@ var methods = function () {
outputFormatter: utils.toDecimal outputFormatter: utils.toDecimal
}); });
var getUseAddress = new Method({
name: 'getUseAddress',
call: 'eth_getUseAddress',
params: 1,
inputFormatter: [formatters.inputAddressFormatter]
});
var sendRawTransaction = new Method({ var sendRawTransaction = new Method({
name: 'sendRawTransaction', name: 'sendRawTransaction',
call: 'eth_sendRawTransaction', call: 'eth_sendRawTransaction',
@ -5444,6 +5453,7 @@ var methods = function () {
getTransactionFromBlock, getTransactionFromBlock,
getTransactionReceipt, getTransactionReceipt,
getTransactionCount, getTransactionCount,
getUseAddress,
call, call,
estimateGas, estimateGas,
sendRawTransaction, sendRawTransaction,
@ -13608,7 +13618,44 @@ module.exports = transfer;
},{}],86:[function(require,module,exports){ },{}],86:[function(require,module,exports){
module.exports = XMLHttpRequest; module.exports = XMLHttpRequest;
},{}],"bignumber.js":[function(require,module,exports){ },{}],87:[function(require,module,exports){
/* use.js */
var Method = require('../method');
var formatters = require('../formatters');
function Use(web3) {
this._requestManager = web3._requestManager;
var self = this;
methods().forEach(function(method) {
method.attachToObject(self);
method.setRequestManager(self._requestManager);
});
properties().forEach(function(p) {
p.attachToObject(self);
p.setRequestManager(self._requestManager);
});
}
var methods = function () {
var getUseAddress = new Method({
name: 'getUseAddress',
call: 'use_getUseAddress',
params: 1,
inputFormatter: [formatters.inputAddressFormatter]
});
return [
getUseAddress,
];
};
var properties = function () {
return [];
};
module.exports = Use;
},{"../formatters":30,"../method":36}],"bignumber.js":[function(require,module,exports){
'use strict'; 'use strict';
module.exports = BigNumber; // jshint ignore:line module.exports = BigNumber; // jshint ignore:line