Skip to content

Commit

Permalink
algod: Migrate internal uses of v1 algod API to v2 (#4684)
Browse files Browse the repository at this point in the history
  • Loading branch information
algochoi authored Nov 3, 2022
1 parent 855304e commit 06d146b
Show file tree
Hide file tree
Showing 43 changed files with 848 additions and 496 deletions.
15 changes: 12 additions & 3 deletions cmd/algoh/blockWatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import (
"sync"
"time"

"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/logging"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/rpcs"
)

var log = logging.Base()

type blockListener interface {
init(uint64)
onBlock(v1.Block)
onBlock(rpcs.EncodedBlockCert)
}

type blockWatcher struct {
Expand Down Expand Up @@ -75,7 +76,8 @@ func (bw *blockWatcher) run(watchers []blockListener, stallDetect time.Duration,
for {
// Inner loop needed during catchup.
for {
block, err := bw.client.Block(curBlock)
// Get the raw block from the client, then parse the block so we can get the bookkeeping block and certificate for proposer address.
resp, err := bw.client.RawBlock(curBlock)

// Generally this error will be due to the new block not being ready. In the case of a stall we will
// return, causing the loop to restart and handle any possible stall/catchup.
Expand All @@ -89,6 +91,13 @@ func (bw *blockWatcher) run(watchers []blockListener, stallDetect time.Duration,
break
}

// Parse the raw block
var block rpcs.EncodedBlockCert
err = protocol.DecodeReflect(resp, &block)
if err != nil {
return false
}

curBlock++
for _, watcher := range watchers {
watcher.onBlock(block)
Expand Down
4 changes: 2 additions & 2 deletions cmd/algoh/blockWatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"testing"
"time"

"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/rpcs"
"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -110,7 +110,7 @@ func (l *testlistener) init(block uint64) {
atomic.AddUint32(&(l.initCount), 1)
}

func (l *testlistener) onBlock(block v1.Block) {
func (l *testlistener) onBlock(rpcs.EncodedBlockCert) {
atomic.AddUint32(&(l.blockCount), 1)
}

Expand Down
23 changes: 12 additions & 11 deletions cmd/algoh/blockstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package main
import (
"time"

"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/logging/telemetryspec"
"github.com/algorand/go-algorand/rpcs"
)

const downtimeLimit time.Duration = 5 * time.Minute
Expand All @@ -34,20 +34,21 @@ type blockstats struct {
func (stats *blockstats) init(block uint64) {
}

func (stats *blockstats) onBlock(block v1.Block) {
func (stats *blockstats) onBlock(block rpcs.EncodedBlockCert) {
now := time.Now()
blockHeader := block.Block.BlockHeader

// Ensure we only create stats from consecutive blocks.
if stats.lastBlock+1 != block.Round {
stats.lastBlock = block.Round
if stats.lastBlock+1 != uint64(blockHeader.Round) {
stats.lastBlock = uint64(blockHeader.Round)
stats.lastBlockTime = now
return
}

// Grab unique users.
users := make(map[string]bool)
for _, tx := range block.Transactions.Transactions {
users[tx.From] = true
for _, tx := range block.Block.Payset {
users[tx.Txn.Sender.String()] = true
}

duration := now.Sub(stats.lastBlockTime)
Expand All @@ -57,15 +58,15 @@ func (stats *blockstats) onBlock(block v1.Block) {
}

stats.log.EventWithDetails(telemetryspec.Agreement, telemetryspec.BlockStatsEvent, telemetryspec.BlockStatsEventDetails{
Hash: block.Hash,
OriginalProposer: block.Proposer,
Round: block.Round,
Transactions: uint64(len(block.Transactions.Transactions)),
Hash: block.Block.Hash().String(),
OriginalProposer: block.Certificate.Proposal.OriginalProposer.String(),
Round: uint64(blockHeader.Round),
Transactions: uint64(len(block.Block.Payset)),
ActiveUsers: uint64(len(users)),
AgreementDurationMs: uint64(duration.Nanoseconds() / 1000 / 1000),
NetworkDowntimeMs: uint64(downtime.Nanoseconds() / 1000 / 1000),
})

stats.lastBlock = block.Round
stats.lastBlock = uint64(blockHeader.Round)
stats.lastBlockTime = now
}
68 changes: 58 additions & 10 deletions cmd/algoh/blockstats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import (
"testing"
"time"

"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/logging/telemetryspec"
"github.com/algorand/go-algorand/rpcs"
"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
)
Expand All @@ -31,33 +34,78 @@ type event struct {

identifier telemetryspec.Event

details interface{}
details telemetryspec.BlockStatsEventDetails
}

type MockEventSender struct {
events []event
}

func (mes *MockEventSender) EventWithDetails(category telemetryspec.Category, identifier telemetryspec.Event, details interface{}) {
mes.events = append(mes.events, event{category: category, identifier: identifier, details: details})
mes.events = append(mes.events, event{category: category, identifier: identifier, details: details.(telemetryspec.BlockStatsEventDetails)})
}

// Helper method to create an EncodedBlockCert for the block handler.
func makeTestBlock(round uint64) rpcs.EncodedBlockCert {
return rpcs.EncodedBlockCert{Block: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: basics.Round(round)}}}
}

func TestConsecutiveBlocks(t *testing.T) {
partitiontest.PartitionTest(t)
sender := MockEventSender{}
bs := blockstats{log: &sender}

bs.onBlock(v1.Block{Round: 300})
bs.onBlock(makeTestBlock(300))
// first consecutive block
bs.onBlock(v1.Block{Round: 301})
bs.onBlock(makeTestBlock(301))
// reset
bs.onBlock(v1.Block{Round: 303})
bs.onBlock(makeTestBlock(303))
// second consecutive block
bs.onBlock(v1.Block{Round: 304})
bs.onBlock(makeTestBlock(304))

require.Equal(t, 2, len(sender.events))
}

func TestEventWithDetails(t *testing.T) {
partitiontest.PartitionTest(t)
sender := MockEventSender{}
bs := blockstats{log: &sender}

// Create blocks with some senders in the payload.
makeStxnWithAddr := func(addr basics.Address) transactions.SignedTxnInBlock {
return transactions.SignedTxnInBlock{SignedTxnWithAD: transactions.SignedTxnWithAD{SignedTxn: transactions.SignedTxn{Txn: transactions.Transaction{Header: transactions.Header{Sender: addr}}}}}
}
addr := basics.Address{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
otherAddr := basics.Address{0x7, 0xda, 0xcb, 0x4b, 0x6d, 0x9e, 0xd1, 0x41, 0xb1, 0x75, 0x76, 0xbd, 0x45, 0x9a, 0xe6, 0x42, 0x1d, 0x48, 0x6d, 0xa3, 0xd4, 0xef, 0x22, 0x47, 0xc4, 0x9, 0xa3, 0x96, 0xb8, 0x2e, 0xa2, 0x21}
// Check that only unique addrs are returned by ActiveUsers.
stxn1 := makeStxnWithAddr(addr)
stxn2 := makeStxnWithAddr(otherAddr)
stxn3 := makeStxnWithAddr(addr)
// Make block with some transactions.
testBlock := makeTestBlock(300)
testBlock.Block.Payset = transactions.Payset{stxn1, stxn2, stxn3}

bs.onBlock(makeTestBlock(299))
bs.onBlock(testBlock)
bs.onBlock(makeTestBlock(301))

testCases := []struct {
round uint64
activeUsers uint64
txns uint64
}{
{uint64(300), uint64(2), uint64(3)},
{uint64(301), uint64(0), uint64(0)},
}

require.Equal(t, 2, len(sender.events))
for i, event := range sender.events {
require.Equal(t, testCases[i].round, event.details.Round)
require.Equal(t, testCases[i].activeUsers, event.details.ActiveUsers)
require.Equal(t, testCases[i].txns, event.details.Transactions)
}
}

func TestAgreementTime(t *testing.T) {
partitiontest.PartitionTest(t)
sleepTime := 50 * time.Millisecond
Expand All @@ -70,13 +118,13 @@ func TestAgreementTime(t *testing.T) {
bs := blockstats{log: &sender}

start := time.Now()
bs.onBlock(v1.Block{Round: 300})
bs.onBlock(makeTestBlock(300))
time.Sleep(sleepTime)
bs.onBlock(v1.Block{Round: 301})
bs.onBlock(makeTestBlock(301))
end := time.Now()

require.Equal(t, 1, len(sender.events))
details := sender.events[0].details.(telemetryspec.BlockStatsEventDetails)
details := sender.events[0].details

// Test to see that the wait duration is at least the amount of time we slept
require.True(t, int(details.AgreementDurationMs) >= int(sleepTime)/int(time.Millisecond))
Expand Down
3 changes: 1 addition & 2 deletions cmd/algoh/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ import (
"context"

generatedV2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated"
"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
)

// Client is a minimal interface for the RestClient
type Client interface {
Status() (generatedV2.NodeStatusResponse, error)
Block(round uint64) (v1.Block, error)
RawBlock(round uint64) ([]byte, error)
GetGoRoutines(ctx context.Context) (string, error)
HealthCheck() error
}
6 changes: 3 additions & 3 deletions cmd/algoh/deadman.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
"time"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/logging/telemetryspec"
"github.com/algorand/go-algorand/rpcs"
)

type deadManWatcher struct {
Expand Down Expand Up @@ -88,8 +88,8 @@ func (w deadManWatcher) run(initBlock uint64) {
}
}

func (w deadManWatcher) onBlock(block v1.Block) {
w.newBlockChan <- block.Round
func (w deadManWatcher) onBlock(block rpcs.EncodedBlockCert) {
w.newBlockChan <- uint64(block.Block.BlockHeader.Round)
}

func (w deadManWatcher) reportDeadManTimeout(curBlock uint64) (err error) {
Expand Down
20 changes: 12 additions & 8 deletions cmd/algoh/mockClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import (
"fmt"

generatedV2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated"
"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/rpcs"
)

//////////////////////////////////////
Expand All @@ -36,10 +39,10 @@ func makeNodeStatuses(blocks ...uint64) (ret []generatedV2.NodeStatusResponse) {
return ret
}

func makeBlocks(blocks ...uint64) (ret map[uint64]v1.Block) {
ret = map[uint64]v1.Block{}
func makeBlocks(blocks ...uint64) (ret map[uint64]rpcs.EncodedBlockCert) {
ret = map[uint64]rpcs.EncodedBlockCert{}
for _, block := range blocks {
ret[block] = v1.Block{Round: block}
ret[block] = rpcs.EncodedBlockCert{Block: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: basics.Round(block)}}}
}
return ret
}
Expand All @@ -54,10 +57,10 @@ type mockClient struct {
error []error
status []generatedV2.NodeStatusResponse
routine []string
block map[uint64]v1.Block
block map[uint64]rpcs.EncodedBlockCert
}

func makeMockClient(error []error, status []generatedV2.NodeStatusResponse, block map[uint64]v1.Block, routine []string) mockClient {
func makeMockClient(error []error, status []generatedV2.NodeStatusResponse, block map[uint64]rpcs.EncodedBlockCert, routine []string) mockClient {
return mockClient{
BlockCalls: make(map[uint64]int),
error: error,
Expand Down Expand Up @@ -90,15 +93,16 @@ func (c *mockClient) Status() (s generatedV2.NodeStatusResponse, e error) {
return
}

func (c *mockClient) Block(block uint64) (b v1.Block, e error) {
func (c *mockClient) RawBlock(block uint64) (b []byte, e error) {
c.BlockCalls[block]++
e = c.nextError()
b, ok := c.block[block]
bl, ok := c.block[block]
if !ok {
if e == nil {
e = fmt.Errorf("test is missing block %d", block)
}
}
b = protocol.EncodeReflect(bl)
return
}

Expand Down
14 changes: 7 additions & 7 deletions cmd/goal/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo
_, units = unicodePrintable(*createdAsset.Params.UnitName)
}

total := assetDecimalsFmt(createdAsset.Params.Total, uint32(createdAsset.Params.Decimals))
total := assetDecimalsFmt(createdAsset.Params.Total, createdAsset.Params.Decimals)

url := ""
if createdAsset.Params.Url != nil {
Expand All @@ -618,7 +618,7 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo
fmt.Fprintf(report, "\tID %d, error\n", assetHolding.AssetId)
}

amount := assetDecimalsFmt(assetHolding.Amount, uint32(assetParams.Params.Decimals))
amount := assetDecimalsFmt(assetHolding.Amount, assetParams.Params.Decimals)

assetName := "<unnamed>"
if assetParams.Params.Name != nil {
Expand Down Expand Up @@ -1137,15 +1137,15 @@ var listParticipationKeysCmd = &cobra.Command{
fmt.Printf(rowFormat, "Registered", "Account", "ParticipationID", "Last Used", "First round", "Last round")
for _, part := range parts {
onlineInfoStr := "unknown"
onlineAccountInfo, err := client.AccountInformation(part.Address)
onlineAccountInfo, err := client.AccountInformationV2(part.Address, false)
if err == nil {
votingBytes := part.Key.VoteParticipationKey
vrfBytes := part.Key.SelectionParticipationKey
if onlineAccountInfo.Participation != nil &&
(string(onlineAccountInfo.Participation.ParticipationPK) == string(votingBytes[:])) &&
(string(onlineAccountInfo.Participation.VRFPK) == string(vrfBytes[:])) &&
(onlineAccountInfo.Participation.VoteFirst == part.Key.VoteFirstValid) &&
(onlineAccountInfo.Participation.VoteLast == part.Key.VoteLastValid) &&
(string(onlineAccountInfo.Participation.VoteParticipationKey) == string(votingBytes[:])) &&
(string(onlineAccountInfo.Participation.SelectionParticipationKey) == string(vrfBytes[:])) &&
(onlineAccountInfo.Participation.VoteFirstValid == part.Key.VoteFirstValid) &&
(onlineAccountInfo.Participation.VoteLastValid == part.Key.VoteLastValid) &&
(onlineAccountInfo.Participation.VoteKeyDilution == part.Key.VoteKeyDilution) {
onlineInfoStr = "yes"
} else {
Expand Down
4 changes: 2 additions & 2 deletions cmd/goal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ var createAppCmd = &cobra.Command{
if err != nil {
reportErrorf(err.Error())
}
if txn.TransactionResults != nil && txn.TransactionResults.CreatedAppIndex != 0 {
reportInfof("Created app with app index %d", txn.TransactionResults.CreatedAppIndex)
if txn.ApplicationIndex != nil && *txn.ApplicationIndex != 0 {
reportInfof("Created app with app index %d", *txn.ApplicationIndex)
}
}
} else {
Expand Down
Loading

0 comments on commit 06d146b

Please sign in to comment.