Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace the KMD usage in pingpong with direct signing #2653

Merged
merged 8 commits into from
Jul 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 91 additions & 46 deletions shared/pingpong/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,58 +18,95 @@ package pingpong

import (
"fmt"
"io/ioutil"
"math"
"math/rand"
"os"
"path/filepath"
"sort"
"strings"
"time"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
v1 "github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
algodAcct "github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/libgoal"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util/db"
)

func ensureAccounts(ac libgoal.Client, initCfg PpConfig) (accounts map[string]uint64, cfg PpConfig, err error) {
accounts = make(map[string]uint64)
func (pps *WorkerState) ensureAccounts(ac libgoal.Client, initCfg PpConfig) (accounts map[string]*pingPongAccount, cfg PpConfig, err error) {
accounts = make(map[string]*pingPongAccount)
cfg = initCfg

wallet, err := ac.GetUnencryptedWalletHandle()
genID, err2 := ac.GenesisID()
if err2 != nil {
err = err2
return
}
genesisDir := filepath.Join(ac.DataDir(), genID)
files, err2 := ioutil.ReadDir(genesisDir)
if err2 != nil {
err = err2
return
}

var srcAcctPresent bool
var richestAccount string
var richestBalance uint64

addresses, err := ac.ListAddresses(wallet)
for _, info := range files {
var handle db.Accessor

if err != nil {
return nil, PpConfig{}, err
}
// If it can't be a participation key database, skip it
if !config.IsRootKeyFilename(info.Name()) {
continue
}

// Fetch a handle to this database
handle, err = db.MakeErasableAccessor(filepath.Join(genesisDir, info.Name()))
if err != nil {
// Couldn't open it, skip it
continue
}

// Fetch an account.Participation from the database
root, err := algodAcct.RestoreRoot(handle)
handle.Close()
if err != nil {
// Couldn't read it, skip it
continue
}

publicKey := root.Secrets().SignatureVerifier
accountAddress := basics.Address(publicKey)

// find either srcAccount or the richest account
for _, addr := range addresses {
if addr == cfg.SrcAccount {
if accountAddress.String() == cfg.SrcAccount {
srcAcctPresent = true
}

amount, err := ac.GetBalance(addr)
amt, err := ac.GetBalance(accountAddress.String())
if err != nil {
return nil, PpConfig{}, err
}

amt := amount
if !srcAcctPresent && amt > richestBalance {
richestAccount = addr
richestAccount = accountAddress.String()
richestBalance = amt
}
accounts[addr] = amt

if !initCfg.Quiet {
fmt.Printf("Found local account: %s -> %v\n", addr, amt)
fmt.Printf("Found local account: %s -> %v\n", accountAddress.String(), amt)
}

accounts[accountAddress.String()] = &pingPongAccount{
balance: amt,
sk: root.Secrets(),
pk: accountAddress,
}
}

Expand Down Expand Up @@ -104,7 +141,7 @@ func ensureAccounts(ac libgoal.Client, initCfg PpConfig) (accounts map[string]ui
if len(accounts) != int(cfg.NumPartAccounts+1) {
fmt.Printf("Not enough accounts - creating %d more\n", int(cfg.NumPartAccounts+1)-len(accounts))
}
accounts, err = generateAccounts(ac, accounts, cfg.NumPartAccounts, wallet)
accounts, err = generateAccounts(ac, accounts, cfg.NumPartAccounts)
if err != nil {
return
}
Expand All @@ -129,7 +166,7 @@ func throttleTransactionRate(startTime time.Time, cfg PpConfig, totalSent uint64
// Step 1) Create X assets for each of the participant accounts
// Step 2) For each participant account, opt-in to assets of all other participant accounts
// Step 3) Evenly distribute the assets across all participant accounts
func (pps *WorkerState) prepareAssets(assetAccounts map[string]uint64, client libgoal.Client) (resultAssetMaps map[uint64]v1.AssetParams, optIns map[uint64][]string, err error) {
func (pps *WorkerState) prepareAssets(assetAccounts map[string]*pingPongAccount, client libgoal.Client) (resultAssetMaps map[uint64]v1.AssetParams, optIns map[uint64][]string, err error) {
accounts := assetAccounts
cfg := pps.cfg
proto, err := getProto(client)
Expand Down Expand Up @@ -354,14 +391,14 @@ func (pps *WorkerState) prepareAssets(assetAccounts map[string]uint64, client li
fmt.Printf("Distributing assets from %v to %v \n", creator, addr)
}

tx, sendErr := pps.constructTxn(creator, addr, cfg.MaxFee, assetAmt, k, client)
tx, signer, sendErr := pps.constructTxn(creator, addr, cfg.MaxFee, assetAmt, k, client)
if sendErr != nil {
fmt.Printf("Cannot transfer asset %v from account %v\n", k, creator)
err = sendErr
return
}

_, err = signAndBroadcastTransaction(accounts, creator, tx, client, cfg)
_, err = signAndBroadcastTransaction(accounts, signer, tx, client, cfg)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "signing and broadcasting asset distribution failed with error %v\n", err)
return
Expand Down Expand Up @@ -408,9 +445,9 @@ func (pps *WorkerState) prepareAssets(assetAccounts map[string]uint64, client li
return
}

func signAndBroadcastTransaction(accounts map[string]uint64, sender string, tx transactions.Transaction, client libgoal.Client, cfg PpConfig) (txID string, err error) {
func signAndBroadcastTransaction(accounts map[string]*pingPongAccount, sender string, tx transactions.Transaction, client libgoal.Client, cfg PpConfig) (txID string, err error) {
var signedTx transactions.SignedTxn
signedTx, err = signTxn(sender, tx, client, cfg)
signedTx, err = signTxn(sender, tx, accounts, cfg)
if err != nil {
fmt.Printf("Cannot sign trx %+v with account %v\nerror %v\n", tx, sender, err)
return
Expand All @@ -423,7 +460,7 @@ func signAndBroadcastTransaction(accounts map[string]uint64, sender string, tx t
if !cfg.Quiet {
fmt.Printf("Broadcast transaction %v\n", txID)
}
accounts[sender] -= tx.Fee.Raw
accounts[sender].balance -= tx.Fee.Raw

return
}
Expand Down Expand Up @@ -585,7 +622,7 @@ func genAppProgram(numOps uint32, numHashes uint32, hashSize string, numGlobalKe
return ops.Program, progAsm
}

func sendAsGroup(txgroup []transactions.Transaction, client libgoal.Client, h []byte) (err error) {
func (pps *WorkerState) sendAsGroup(txgroup []transactions.Transaction, client libgoal.Client, senders []string) (err error) {
if len(txgroup) == 0 {
err = fmt.Errorf("sendAsGroup: empty group")
return
Expand All @@ -596,9 +633,15 @@ func sendAsGroup(txgroup []transactions.Transaction, client libgoal.Client, h []
return
}
var stxgroup []transactions.SignedTxn
for _, txn := range txgroup {
for i, txn := range txgroup {
txn.Group = gid
signedTxn, signErr := client.SignTransactionWithWallet(h, nil, txn)
//signedTxn, signErr := client.SignTransactionWithWallet(h, nil, txn)
signedTxn, signErr := signTxn(senders[i], txn, pps.accounts, pps.cfg)
if err != nil {
fmt.Printf("Cannot sign trx %+v with account %v\nerror %v\n", txn, senders[i], err)
return
}

if signErr != nil {
fmt.Printf("Cannot sign app creation txn\n")
err = signErr
Expand Down Expand Up @@ -635,7 +678,7 @@ func getProto(client libgoal.Client) (config.ConsensusParams, error) {
return *proto, nil
}

func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig) (appParams map[uint64]v1.AppParams, optIns map[uint64][]string, err error) {
func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client libgoal.Client, cfg PpConfig) (appParams map[uint64]v1.AppParams, optIns map[uint64][]string, err error) {
proto, err := getProto(client)
if err != nil {
return
Expand Down Expand Up @@ -686,13 +729,6 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
}
}

// Get wallet handle token
var h []byte
h, err = client.GetUnencryptedWalletHandle()
if err != nil {
return
}

// create apps
for idx, appAccount := range appAccounts {
begin := idx * appsPerAcct
Expand All @@ -701,6 +737,7 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
end = toCreate
}
var txgroup []transactions.Transaction
var senders []string
for i := begin; i < end; i++ {
var tx transactions.Transaction

Expand Down Expand Up @@ -730,10 +767,11 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
tx.Note = note[:]

txgroup = append(txgroup, tx)
accounts[appAccount.Address] -= tx.Fee.Raw
accounts[appAccount.Address].balance -= tx.Fee.Raw
senders = append(senders, appAccount.Address)
}

err = sendAsGroup(txgroup, client, h)
err = pps.sendAsGroup(txgroup, client, senders)
if err != nil {
return
}
Expand Down Expand Up @@ -776,6 +814,7 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
optIns = make(map[uint64][]string)
for addr := range accounts {
var txgroup []transactions.Transaction
var senders []string
permAppIndices := rand.Perm(len(aidxs))
for i := uint32(0); i < cfg.NumAppOptIn; i++ {
j := permAppIndices[i]
Expand All @@ -801,8 +840,9 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
optIns[aidx] = append(optIns[aidx], addr)

txgroup = append(txgroup, tx)
senders = append(senders, addr)
if len(txgroup) == groupSize {
err = sendAsGroup(txgroup, client, h)
err = pps.sendAsGroup(txgroup, client, senders)
if err != nil {
return
}
Expand All @@ -811,7 +851,7 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
}
// broadcast leftovers
if len(txgroup) > 0 {
err = sendAsGroup(txgroup, client, h)
err = pps.sendAsGroup(txgroup, client, senders)
if err != nil {
return
}
Expand All @@ -822,7 +862,7 @@ func prepareApps(accounts map[string]uint64, client libgoal.Client, cfg PpConfig
return
}

func takeTopAccounts(allAccounts map[string]uint64, numAccounts uint32, srcAccount string) (accounts map[string]uint64) {
func takeTopAccounts(allAccounts map[string]*pingPongAccount, numAccounts uint32, srcAccount string) (accounts map[string]*pingPongAccount) {
allAddrs := make([]string, len(allAccounts))
var i int
for addr := range allAccounts {
Expand All @@ -833,12 +873,12 @@ func takeTopAccounts(allAccounts map[string]uint64, numAccounts uint32, srcAccou
sort.SliceStable(allAddrs, func(i, j int) bool {
amt1 := allAccounts[allAddrs[i]]
amt2 := allAccounts[allAddrs[j]]
return amt1 > amt2
return amt1.balance > amt2.balance
})

// Now populate a new map with just the accounts needed
accountsRequired := int(numAccounts + 1) // Participating and Src
accounts = make(map[string]uint64)
accounts = make(map[string]*pingPongAccount)
accounts[srcAccount] = allAccounts[srcAccount]
for _, addr := range allAddrs {
accounts[addr] = allAccounts[addr]
Expand All @@ -849,18 +889,23 @@ func takeTopAccounts(allAccounts map[string]uint64, numAccounts uint32, srcAccou
return
}

func generateAccounts(client libgoal.Client, allAccounts map[string]uint64, numAccounts uint32, wallet []byte) (map[string]uint64, error) {
func generateAccounts(client libgoal.Client, allAccounts map[string]*pingPongAccount, numAccounts uint32) (map[string]*pingPongAccount, error) {
// Compute the number of accounts to generate
accountsRequired := int(numAccounts+1) - len(allAccounts)

var seed crypto.Seed

for accountsRequired > 0 {
accountsRequired--
addr, err := client.GenerateAddress(wallet)
if err != nil {
return allAccounts, err
}

allAccounts[addr] = 0
crypto.RandBytes(seed[:])
privateKey := crypto.GenerateSignatureSecrets(seed)
publicKey := basics.Address(privateKey.SignatureVerifier)

allAccounts[publicKey.String()] = &pingPongAccount{
sk: privateKey,
pk: publicKey,
}
}

return allAccounts, nil
Expand Down
Loading