the729 / go-libra

Libra go client library with crypto verifications
Apache License 2.0
44 stars 8 forks source link

[Opinion] Wallet operations. #10

Closed feliciss closed 4 years ago

feliciss commented 4 years ago

It's a good choice to add a wallet package and related functions such as newWallet, wallet.createAccount, and more such as client.mintCoin. Moreover, adding a wallet also tackles the problem of the differentiation of ed25519 between golang and rust. In golang, there is 64-bytes private key, whereas the libra uses 32-bytes private key (called PrivateKeySeed in golang). The private key generated from libra source code that can't be used directly to go-libra package because of the difference of key length. To eliminate the ambiguities, the choices are either to add wallet operations in golang package that would use golang's ed25519 or support the 32-bytes length private key from rust or other analogous programming languages that only produce 32-bytes private key by declaring a function like ed25519.NewKeyFromSeed().

feliciss commented 4 years ago

Pseudocode here (learned from the example cli):

wallet/wallet.go

type Account struct {
    PrivateKey     ed25519.PrivateKey
    Address        types.AccountAddress
    SequenceNumber uint64
}

type Wallet struct {
    Accounts map[string]*Account
}

func NewWallet() (*Wallet, error) {
    wallet := &Wallet{
        Accounts: make(map[string]*Account),
    }
    return wallet, nil
}

func (*Wallet) NewAccount() (*Account, error) {
    pubkey, prikey, err := ed25519.GenerateKey(rand.Reader)
    if err != nil {
        return nil, err
    }
    hasher := sha3.New256()
    hasher.Write(pubkey)
    account := &Account {
        PrivateKey: crypto.PrivateKey(prikey),
    }
    hasher.Sum(account.Address[:0])
    return account, nil
}

func (*Account) GetAddress(account Account) (*string, error) {
    address := hex.EncodeToString(account.Address[:])
    return &address, nil
}

func (*Account) MintCoin(address string, amount uint64) error {
    amountMicro := amount * 1000000

    faucetURL := fmt.Sprintf("http://faucet.testnet.libra.org/?amount=%d&address=%s", amountMicro, address)
    log.Printf("Going to POST to faucet service: %s", faucetURL)

    resp, err := http.PostForm(faucetURL, nil)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    log.Printf("Respone (code=%d): %s", resp.StatusCode, string(body))
    return nil
}
the729 commented 4 years ago

You are definately correct that we need a wallet library to work with libra blockchain.

Having said that, wallet is a separate module from client library. A wallet manages a set of public-private key pairs, while a client library uses these key pairs. Wallet and client should not be coupled heavily. Instead, they should agree on a simple APIs (or interfaces in term of golang). So I havn't decided whether to implement a wallet library in this project, or as a new project (just like LCS).

The wallet library should be compatible with the account generation algorithm with the official libra (rust) project. It should generate unlimited number of accounts using a BIP39 mnemonic, which acts as a master key.

The dead-simple wallet in example/cli is meant for testing the client library only. It is not secure nor complete. Not meant for further development. And definately not use it with the mainnet in the future.

If you are interested in implementing a full-fledged wallet library, I'm happy to help.

feliciss commented 4 years ago

You are definately correct that we need a wallet library to work with libra blockchain.

Having said that, wallet is a separate module from client library. A wallet manages a set of public-private key pairs, while a client library uses these key pairs. Wallet and client should not be coupled heavily. Instead, they should agree on a simple APIs (or interfaces in term of golang). So I havn't decided whether to implement a wallet library in this project, or as a new project (just like LCS).

The wallet library should be compatible with the account generation algorithm with the official libra (rust) project. It should generate unlimited number of accounts using a BIP39 mnemonic, which acts as a master key.

The dead-simple wallet in example/cli is meant for testing the client library only. It is not secure nor complete. Not meant for further development. And definately not use it with the mainnet in the future.

If you are interested in implementing a full-fledged wallet library, I'm happy to help.

The very simple wallet is to use tweetnacl lib to generate a key pair, translate it to libra address and use that address to request a libra coin so that address is a valid address. I learned that from your gopherjs-libra README. Many thanks. The libra wallet integration can be a part of a project's implementation or independent module. I'll try to separate it into a project if further needs are required.