Skip to content
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: 46 additions & 91 deletions shared/pingpong/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,95 +18,58 @@ 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 (pps *WorkerState) ensureAccounts(ac libgoal.Client, initCfg PpConfig) (accounts map[string]*pingPongAccount, cfg PpConfig, err error) {
accounts = make(map[string]*pingPongAccount)
func ensureAccounts(ac libgoal.Client, initCfg PpConfig) (accounts map[string]uint64, cfg PpConfig, err error) {
accounts = make(map[string]uint64)
cfg = initCfg

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
}
wallet, err := ac.GetUnencryptedWalletHandle()

var srcAcctPresent bool
var richestAccount string
var richestBalance uint64

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

// 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)
if err != nil {
return nil, PpConfig{}, err
}

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

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

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

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

accounts[accountAddress.String()] = &pingPongAccount{
balance: amt,
sk: root.Secrets(),
pk: accountAddress,
fmt.Printf("Found local account: %s -> %v\n", addr, amt)
}
}

Expand Down Expand Up @@ -141,7 +104,7 @@ func (pps *WorkerState) ensureAccounts(ac libgoal.Client, initCfg PpConfig) (acc
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)
accounts, err = generateAccounts(ac, accounts, cfg.NumPartAccounts, wallet)
if err != nil {
return
}
Expand All @@ -166,7 +129,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]*pingPongAccount, client libgoal.Client) (resultAssetMaps map[uint64]v1.AssetParams, optIns map[uint64][]string, err error) {
func (pps *WorkerState) prepareAssets(assetAccounts map[string]uint64, 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 @@ -391,14 +354,14 @@ func (pps *WorkerState) prepareAssets(assetAccounts map[string]*pingPongAccount,
fmt.Printf("Distributing assets from %v to %v \n", creator, addr)
}

tx, signer, sendErr := pps.constructTxn(creator, addr, cfg.MaxFee, assetAmt, k, client)
tx, 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, signer, tx, client, cfg)
_, err = signAndBroadcastTransaction(accounts, creator, 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 @@ -445,9 +408,9 @@ func (pps *WorkerState) prepareAssets(assetAccounts map[string]*pingPongAccount,
return
}

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

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

func (pps *WorkerState) sendAsGroup(txgroup []transactions.Transaction, client libgoal.Client, senders []string) (err error) {
func sendAsGroup(txgroup []transactions.Transaction, client libgoal.Client, h []byte) (err error) {
if len(txgroup) == 0 {
err = fmt.Errorf("sendAsGroup: empty group")
return
Expand All @@ -633,15 +596,9 @@ func (pps *WorkerState) sendAsGroup(txgroup []transactions.Transaction, client l
return
}
var stxgroup []transactions.SignedTxn
for i, txn := range txgroup {
for _, txn := range txgroup {
txn.Group = gid
//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
}

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

func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client libgoal.Client, cfg PpConfig) (appParams map[uint64]v1.AppParams, optIns map[uint64][]string, err error) {
func prepareApps(accounts map[string]uint64, 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 @@ -729,6 +686,13 @@ func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client
}
}

// 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 @@ -737,7 +701,6 @@ func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client
end = toCreate
}
var txgroup []transactions.Transaction
var senders []string
for i := begin; i < end; i++ {
var tx transactions.Transaction

Expand Down Expand Up @@ -767,11 +730,10 @@ func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client
tx.Note = note[:]

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

err = pps.sendAsGroup(txgroup, client, senders)
err = sendAsGroup(txgroup, client, h)
if err != nil {
return
}
Expand Down Expand Up @@ -814,7 +776,6 @@ func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client
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 @@ -840,9 +801,8 @@ func (pps *WorkerState) prepareApps(accounts map[string]*pingPongAccount, client
optIns[aidx] = append(optIns[aidx], addr)

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

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

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

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

var seed crypto.Seed

for accountsRequired > 0 {
accountsRequired--

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

allAccounts[publicKey.String()] = &pingPongAccount{
sk: privateKey,
pk: publicKey,
addr, err := client.GenerateAddress(wallet)
if err != nil {
return allAccounts, err
}

allAccounts[addr] = 0
}

return allAccounts, nil
Expand Down
Loading