diff --git a/agreement/agreementtest/simulate.go b/agreement/agreementtest/simulate.go
index 8d8b713c68..408b44a29a 100644
--- a/agreement/agreementtest/simulate.go
+++ b/agreement/agreementtest/simulate.go
@@ -31,7 +31,6 @@ import (
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/logging"
- "github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util/db"
"github.com/algorand/go-algorand/util/timers"
)
@@ -52,7 +51,7 @@ func makeInstant() *instant {
return i
}
-func (i *instant) Decode([]byte) (timers.Clock, error) {
+func (i *instant) Decode([]byte) (timers.Clock[agreement.TimeoutType], error) {
return i, nil
}
@@ -60,7 +59,7 @@ func (i *instant) Encode() []byte {
return nil
}
-func (i *instant) TimeoutAt(d time.Duration) <-chan time.Time {
+func (i *instant) TimeoutAt(d time.Duration, timeoutType agreement.TimeoutType) <-chan time.Time {
ta := make(chan time.Time)
select {
case <-i.timeoutAtCalled:
@@ -69,13 +68,13 @@ func (i *instant) TimeoutAt(d time.Duration) <-chan time.Time {
return ta
}
- if d == agreement.FilterTimeout(0, protocol.ConsensusCurrentVersion) && !i.HasPending("pseudonode") {
+ if timeoutType == agreement.TimeoutFilter && !i.HasPending("pseudonode") {
close(ta)
}
return ta
}
-func (i *instant) Zero() timers.Clock {
+func (i *instant) Zero() timers.Clock[agreement.TimeoutType] {
i.Z0 <- struct{}{}
// pause here until runRound is called
i.Z1 <- struct{}{}
diff --git a/agreement/demux.go b/agreement/demux.go
index f31c4d075d..c225396293 100644
--- a/agreement/demux.go
+++ b/agreement/demux.go
@@ -19,7 +19,6 @@ package agreement
import (
"context"
"fmt"
- "time"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/logging"
@@ -190,7 +189,7 @@ func (d *demux) verifyBundle(ctx context.Context, m message, r round, p period,
// next blocks until it observes an external input event of interest for the state machine.
//
// If ok is false, there are no more events so the agreement service should quit.
-func (d *demux) next(s *Service, deadline time.Duration, fastDeadline time.Duration, currentRound round) (e externalEvent, ok bool) {
+func (d *demux) next(s *Service, deadline Deadline, fastDeadline Deadline, currentRound round) (e externalEvent, ok bool) {
defer func() {
if !ok {
return
@@ -250,8 +249,8 @@ func (d *demux) next(s *Service, deadline time.Duration, fastDeadline time.Durat
}
ledgerNextRoundCh := s.Ledger.Wait(nextRound)
- deadlineCh := s.Clock.TimeoutAt(deadline)
- fastDeadlineCh := s.Clock.TimeoutAt(fastDeadline)
+ deadlineCh := s.Clock.TimeoutAt(deadline.Duration, deadline.Type)
+ fastDeadlineCh := s.Clock.TimeoutAt(fastDeadline.Duration, fastDeadline.Type)
d.UpdateEventsQueue(eventQueueDemux, 0)
d.monitor.dec(demuxCoserviceType)
diff --git a/agreement/demux_test.go b/agreement/demux_test.go
index 027dbc9e13..c6aee6619c 100644
--- a/agreement/demux_test.go
+++ b/agreement/demux_test.go
@@ -422,14 +422,14 @@ func TestDemuxNext(t *testing.T) {
}
// implement timers.Clock
-func (t *demuxTester) Zero() timers.Clock {
+func (t *demuxTester) Zero() timers.Clock[TimeoutType] {
// we don't care about this function in this test.
return t
}
// implement timers.Clock
-func (t *demuxTester) TimeoutAt(delta time.Duration) <-chan time.Time {
- if delta == fastTimeoutChTime {
+func (t *demuxTester) TimeoutAt(delta time.Duration, timeoutType TimeoutType) <-chan time.Time {
+ if timeoutType == TimeoutFastRecovery {
return nil
}
@@ -450,7 +450,7 @@ func (t *demuxTester) Encode() []byte {
}
// implement timers.Clock
-func (t *demuxTester) Decode([]byte) (timers.Clock, error) {
+func (t *demuxTester) Decode([]byte) (timers.Clock[TimeoutType], error) {
// we don't care about this function in this test.
return t, nil
}
@@ -675,7 +675,7 @@ func (t *demuxTester) TestUsecase(testcase demuxTestUsecase) bool {
close(s.quit)
}
- e, ok := dmx.next(s, time.Second, fastTimeoutChTime, 300)
+ e, ok := dmx.next(s, Deadline{Duration: time.Second, Type: TimeoutDeadline}, Deadline{Duration: fastTimeoutChTime, Type: TimeoutFastRecovery}, 300)
if !assert.Equal(t, testcase.ok, ok) {
return false
diff --git a/agreement/fuzzer/fuzzer_test.go b/agreement/fuzzer/fuzzer_test.go
index 332b2fb87b..e505faa197 100644
--- a/agreement/fuzzer/fuzzer_test.go
+++ b/agreement/fuzzer/fuzzer_test.go
@@ -47,7 +47,7 @@ type Fuzzer struct {
wallClock int32
agreements []*agreement.Service
facades []*NetworkFacade
- clocks []timers.Clock
+ clocks []timers.Clock[agreement.TimeoutType]
disconnected [][]bool
crashAccessors []db.Accessor
router *Router
@@ -80,7 +80,7 @@ func MakeFuzzer(config FuzzerConfig) *Fuzzer {
networkName: config.FuzzerName,
agreements: make([]*agreement.Service, config.NodesCount),
facades: make([]*NetworkFacade, config.NodesCount),
- clocks: make([]timers.Clock, config.NodesCount),
+ clocks: make([]timers.Clock[agreement.TimeoutType], config.NodesCount),
disconnected: make([][]bool, config.NodesCount),
crashAccessors: make([]db.Accessor, config.NodesCount),
accounts: make([]account.Participation, config.NodesCount),
diff --git a/agreement/fuzzer/networkFacade_test.go b/agreement/fuzzer/networkFacade_test.go
index 6db2d88c2e..d18f8251dd 100644
--- a/agreement/fuzzer/networkFacade_test.go
+++ b/agreement/fuzzer/networkFacade_test.go
@@ -31,6 +31,7 @@ import (
"github.com/algorand/go-deadlock"
+ "github.com/algorand/go-algorand/agreement"
"github.com/algorand/go-algorand/network"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util/timers"
@@ -48,7 +49,7 @@ type NetworkFacadeMessage struct {
type NetworkFacade struct {
network.GossipNode
NetworkFilter
- timers.Clock
+ timers.Clock[agreement.TimeoutType]
nodeID int
mux *network.Multiplexer
fuzzer *Fuzzer
@@ -345,7 +346,7 @@ func (n *NetworkFacade) Disconnect(sender network.Peer) {
n.fuzzer.Disconnect(n.nodeID, sourceNode)
}
-func (n *NetworkFacade) Zero() timers.Clock {
+func (n *NetworkFacade) Zero() timers.Clock[agreement.TimeoutType] {
n.clockSync.Lock()
defer n.clockSync.Unlock()
@@ -375,7 +376,7 @@ func (n *NetworkFacade) Rezero() {
// Since implements the Clock interface.
func (n *NetworkFacade) Since() time.Duration { return 0 }
-func (n *NetworkFacade) TimeoutAt(d time.Duration) <-chan time.Time {
+func (n *NetworkFacade) TimeoutAt(d time.Duration, timeoutType agreement.TimeoutType) <-chan time.Time {
defer n.timeoutAtInitOnce.Do(func() {
n.timeoutAtInitWait.Done()
})
@@ -414,7 +415,7 @@ func (n *NetworkFacade) Encode() []byte {
return buf.Bytes()
}
-func (n *NetworkFacade) Decode(in []byte) (timers.Clock, error) {
+func (n *NetworkFacade) Decode(in []byte) (timers.Clock[agreement.TimeoutType], error) {
n.clockSync.Lock()
defer n.clockSync.Unlock()
diff --git a/agreement/msgp_gen.go b/agreement/msgp_gen.go
index 19a803b759..d083edd8e8 100644
--- a/agreement/msgp_gen.go
+++ b/agreement/msgp_gen.go
@@ -34,6 +34,24 @@ import (
// |-----> (*) MsgIsZero
// |-----> ConsensusVersionViewMaxSize()
//
+// Deadline
+// |-----> (*) MarshalMsg
+// |-----> (*) CanMarshalMsg
+// |-----> (*) UnmarshalMsg
+// |-----> (*) CanUnmarshalMsg
+// |-----> (*) Msgsize
+// |-----> (*) MsgIsZero
+// |-----> DeadlineMaxSize()
+//
+// TimeoutType
+// |-----> MarshalMsg
+// |-----> CanMarshalMsg
+// |-----> (*) UnmarshalMsg
+// |-----> (*) CanUnmarshalMsg
+// |-----> Msgsize
+// |-----> MsgIsZero
+// |-----> TimeoutTypeMaxSize()
+//
// actionType
// |-----> MarshalMsg
// |-----> CanMarshalMsg
@@ -961,6 +979,183 @@ func ConsensusVersionViewMaxSize() (s int) {
return
}
+// MarshalMsg implements msgp.Marshaler
+func (z *Deadline) MarshalMsg(b []byte) (o []byte) {
+ o = msgp.Require(b, z.Msgsize())
+ // map header, size 2
+ // string "Duration"
+ o = append(o, 0x82, 0xa8, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e)
+ o = msgp.AppendDuration(o, (*z).Duration)
+ // string "Type"
+ o = append(o, 0xa4, 0x54, 0x79, 0x70, 0x65)
+ o = msgp.AppendInt8(o, int8((*z).Type))
+ return
+}
+
+func (_ *Deadline) CanMarshalMsg(z interface{}) bool {
+ _, ok := (z).(*Deadline)
+ return ok
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *Deadline) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ var field []byte
+ _ = field
+ var zb0001 int
+ var zb0002 bool
+ zb0001, zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if _, ok := err.(msgp.TypeError); ok {
+ zb0001, zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ if zb0001 > 0 {
+ zb0001--
+ (*z).Duration, bts, err = msgp.ReadDurationBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "struct-from-array", "Duration")
+ return
+ }
+ }
+ if zb0001 > 0 {
+ zb0001--
+ {
+ var zb0003 int8
+ zb0003, bts, err = msgp.ReadInt8Bytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "struct-from-array", "Type")
+ return
+ }
+ (*z).Type = TimeoutType(zb0003)
+ }
+ }
+ if zb0001 > 0 {
+ err = msgp.ErrTooManyArrayFields(zb0001)
+ if err != nil {
+ err = msgp.WrapError(err, "struct-from-array")
+ return
+ }
+ }
+ } else {
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ if zb0002 {
+ (*z) = Deadline{}
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, bts, err = msgp.ReadMapKeyZC(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch string(field) {
+ case "Duration":
+ (*z).Duration, bts, err = msgp.ReadDurationBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Duration")
+ return
+ }
+ case "Type":
+ {
+ var zb0004 int8
+ zb0004, bts, err = msgp.ReadInt8Bytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Type")
+ return
+ }
+ (*z).Type = TimeoutType(zb0004)
+ }
+ default:
+ err = msgp.ErrNoField(string(field))
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ }
+ o = bts
+ return
+}
+
+func (_ *Deadline) CanUnmarshalMsg(z interface{}) bool {
+ _, ok := (z).(*Deadline)
+ return ok
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z *Deadline) Msgsize() (s int) {
+ s = 1 + 9 + msgp.DurationSize + 5 + msgp.Int8Size
+ return
+}
+
+// MsgIsZero returns whether this is a zero value
+func (z *Deadline) MsgIsZero() bool {
+ return ((*z).Duration == 0) && ((*z).Type == 0)
+}
+
+// MaxSize returns a maximum valid message size for this message type
+func DeadlineMaxSize() (s int) {
+ s = 1 + 9 + msgp.DurationSize + 5 + msgp.Int8Size
+ return
+}
+
+// MarshalMsg implements msgp.Marshaler
+func (z TimeoutType) MarshalMsg(b []byte) (o []byte) {
+ o = msgp.Require(b, z.Msgsize())
+ o = msgp.AppendInt8(o, int8(z))
+ return
+}
+
+func (_ TimeoutType) CanMarshalMsg(z interface{}) bool {
+ _, ok := (z).(TimeoutType)
+ if !ok {
+ _, ok = (z).(*TimeoutType)
+ }
+ return ok
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *TimeoutType) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ {
+ var zb0001 int8
+ zb0001, bts, err = msgp.ReadInt8Bytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ (*z) = TimeoutType(zb0001)
+ }
+ o = bts
+ return
+}
+
+func (_ *TimeoutType) CanUnmarshalMsg(z interface{}) bool {
+ _, ok := (z).(*TimeoutType)
+ return ok
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z TimeoutType) Msgsize() (s int) {
+ s = msgp.Int8Size
+ return
+}
+
+// MsgIsZero returns whether this is a zero value
+func (z TimeoutType) MsgIsZero() bool {
+ return z == 0
+}
+
+// MaxSize returns a maximum valid message size for this message type
+func TimeoutTypeMaxSize() (s int) {
+ s = msgp.Int8Size
+ return
+}
+
// MarshalMsg implements msgp.Marshaler
func (z actionType) MarshalMsg(b []byte) (o []byte) {
o = msgp.Require(b, z.Msgsize())
@@ -3753,31 +3948,46 @@ func PeriodRouterMaxSize() (s int) {
// MarshalMsg implements msgp.Marshaler
func (z *player) MarshalMsg(b []byte) (o []byte) {
o = msgp.Require(b, z.Msgsize())
- // map header, size 8
- // string "Deadline"
- o = append(o, 0x88, 0xa8, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65)
- o = msgp.AppendDuration(o, (*z).Deadline)
- // string "FastRecoveryDeadline"
- o = append(o, 0xb4, 0x46, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65)
- o = msgp.AppendDuration(o, (*z).FastRecoveryDeadline)
- // string "LastConcluding"
- o = append(o, 0xae, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67)
- o = msgp.AppendUint64(o, uint64((*z).LastConcluding))
- // string "Napping"
- o = append(o, 0xa7, 0x4e, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67)
- o = msgp.AppendBool(o, (*z).Napping)
- // string "Pending"
- o = append(o, 0xa7, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67)
- o = (*z).Pending.MarshalMsg(o)
- // string "Period"
- o = append(o, 0xa6, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64)
- o = msgp.AppendUint64(o, uint64((*z).Period))
- // string "Round"
- o = append(o, 0xa5, 0x52, 0x6f, 0x75, 0x6e, 0x64)
- o = (*z).Round.MarshalMsg(o)
- // string "Step"
- o = append(o, 0xa4, 0x53, 0x74, 0x65, 0x70)
- o = msgp.AppendUint64(o, uint64((*z).Step))
+ // omitempty: check for empty values
+ zb0001Len := uint32(9)
+ var zb0001Mask uint16 /* 10 bits */
+ if (*z).OldDeadline == 0 {
+ zb0001Len--
+ zb0001Mask |= 0x1
+ }
+ // variable map header, size zb0001Len
+ o = append(o, 0x80|uint8(zb0001Len))
+ if zb0001Len != 0 {
+ if (zb0001Mask & 0x1) == 0 { // if not empty
+ // string "Deadline"
+ o = append(o, 0xa8, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65)
+ o = msgp.AppendDuration(o, (*z).OldDeadline)
+ }
+ // string "FastRecoveryDeadline"
+ o = append(o, 0xb4, 0x46, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65)
+ o = msgp.AppendDuration(o, (*z).FastRecoveryDeadline)
+ // string "LastConcluding"
+ o = append(o, 0xae, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67)
+ o = msgp.AppendUint64(o, uint64((*z).LastConcluding))
+ // string "Napping"
+ o = append(o, 0xa7, 0x4e, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67)
+ o = msgp.AppendBool(o, (*z).Napping)
+ // string "Pending"
+ o = append(o, 0xa7, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67)
+ o = (*z).Pending.MarshalMsg(o)
+ // string "Period"
+ o = append(o, 0xa6, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64)
+ o = msgp.AppendUint64(o, uint64((*z).Period))
+ // string "Round"
+ o = append(o, 0xa5, 0x52, 0x6f, 0x75, 0x6e, 0x64)
+ o = (*z).Round.MarshalMsg(o)
+ // string "Step"
+ o = append(o, 0xa4, 0x53, 0x74, 0x65, 0x70)
+ o = msgp.AppendUint64(o, uint64((*z).Step))
+ // string "TimersDeadline"
+ o = append(o, 0xae, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x73, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65)
+ o = (*z).Deadline.MarshalMsg(o)
+ }
return
}
@@ -3845,12 +4055,20 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) {
}
if zb0001 > 0 {
zb0001--
- (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts)
+ bts, err = (*z).Deadline.UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, "struct-from-array", "Deadline")
return
}
}
+ if zb0001 > 0 {
+ zb0001--
+ (*z).OldDeadline, bts, err = msgp.ReadDurationBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "struct-from-array", "OldDeadline")
+ return
+ }
+ }
if zb0001 > 0 {
zb0001--
(*z).Napping, bts, err = msgp.ReadBoolBytes(bts)
@@ -3934,12 +4152,18 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) {
}
(*z).LastConcluding = step(zb0008)
}
- case "Deadline":
- (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts)
+ case "TimersDeadline":
+ bts, err = (*z).Deadline.UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, "Deadline")
return
}
+ case "Deadline":
+ (*z).OldDeadline, bts, err = msgp.ReadDurationBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "OldDeadline")
+ return
+ }
case "Napping":
(*z).Napping, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
@@ -3978,18 +4202,18 @@ func (_ *player) CanUnmarshalMsg(z interface{}) bool {
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *player) Msgsize() (s int) {
- s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + (*z).Pending.Msgsize()
+ s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 15 + (*z).Deadline.Msgsize() + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + (*z).Pending.Msgsize()
return
}
// MsgIsZero returns whether this is a zero value
func (z *player) MsgIsZero() bool {
- return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline == 0) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline == 0) && ((*z).Pending.MsgIsZero())
+ return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline.MsgIsZero()) && ((*z).OldDeadline == 0) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline == 0) && ((*z).Pending.MsgIsZero())
}
// MaxSize returns a maximum valid message size for this message type
func PlayerMaxSize() (s int) {
- s = 1 + 6 + basics.RoundMaxSize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + ProposalTableMaxSize()
+ s = 1 + 6 + basics.RoundMaxSize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 15 + DeadlineMaxSize() + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + ProposalTableMaxSize()
return
}
diff --git a/agreement/msgp_gen_test.go b/agreement/msgp_gen_test.go
index 99053ca4c3..2d3952add9 100644
--- a/agreement/msgp_gen_test.go
+++ b/agreement/msgp_gen_test.go
@@ -134,6 +134,66 @@ func BenchmarkUnmarshalConsensusVersionView(b *testing.B) {
}
}
+func TestMarshalUnmarshalDeadline(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ v := Deadline{}
+ bts := v.MarshalMsg(nil)
+ left, err := v.UnmarshalMsg(bts)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(left) > 0 {
+ t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
+ }
+
+ left, err = msgp.Skip(bts)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(left) > 0 {
+ t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
+ }
+}
+
+func TestRandomizedEncodingDeadline(t *testing.T) {
+ protocol.RunEncodingTest(t, &Deadline{})
+}
+
+func BenchmarkMarshalMsgDeadline(b *testing.B) {
+ v := Deadline{}
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.MarshalMsg(nil)
+ }
+}
+
+func BenchmarkAppendMsgDeadline(b *testing.B) {
+ v := Deadline{}
+ bts := make([]byte, 0, v.Msgsize())
+ bts = v.MarshalMsg(bts[0:0])
+ b.SetBytes(int64(len(bts)))
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bts = v.MarshalMsg(bts[0:0])
+ }
+}
+
+func BenchmarkUnmarshalDeadline(b *testing.B) {
+ v := Deadline{}
+ bts := v.MarshalMsg(nil)
+ b.ReportAllocs()
+ b.SetBytes(int64(len(bts)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := v.UnmarshalMsg(bts)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
func TestMarshalUnmarshalblockAssembler(t *testing.T) {
partitiontest.PartitionTest(t)
v := blockAssembler{}
diff --git a/agreement/persistence.go b/agreement/persistence.go
index 5e85955b30..0e5e75915a 100644
--- a/agreement/persistence.go
+++ b/agreement/persistence.go
@@ -53,7 +53,7 @@ func persistent(as []action) bool {
}
// encode serializes the current state into a byte array.
-func encode(t timers.Clock, rr rootRouter, p player, a []action, reflect bool) (raw []byte) {
+func encode(t timers.Clock[TimeoutType], rr rootRouter, p player, a []action, reflect bool) (raw []byte) {
var s diskState
if reflect {
s.Router = protocol.EncodeReflect(rr)
@@ -194,8 +194,8 @@ func restore(log logging.Logger, crash db.Accessor) (raw []byte, err error) {
// decode process the incoming raw bytes array and attempt to reconstruct the agreement state objects.
//
// In all decoding errors, it returns the error code in err
-func decode(raw []byte, t0 timers.Clock, log serviceLogger, reflect bool) (t timers.Clock, rr rootRouter, p player, a []action, err error) {
- var t2 timers.Clock
+func decode(raw []byte, t0 timers.Clock[TimeoutType], log serviceLogger, reflect bool) (t timers.Clock[TimeoutType], rr rootRouter, p player, a []action, err error) {
+ var t2 timers.Clock[TimeoutType]
var rr2 rootRouter
var p2 player
a2 := []action{}
@@ -244,6 +244,10 @@ func decode(raw []byte, t0 timers.Clock, log serviceLogger, reflect bool) (t tim
return
}
}
+ if p2.OldDeadline != 0 {
+ p2.Deadline = Deadline{Duration: p2.OldDeadline, Type: TimeoutDeadline}
+ p2.OldDeadline = 0 // clear old value
+ }
rr2 = makeRootRouter(p2)
err = protocol.Decode(s.Router, &rr2)
if err != nil {
@@ -280,7 +284,7 @@ type persistentRequest struct {
step step
raw []byte
done chan error
- clock timers.Clock
+ clock timers.Clock[TimeoutType]
events chan<- externalEvent
}
@@ -302,7 +306,7 @@ func makeAsyncPersistenceLoop(log serviceLogger, crash db.Accessor, ledger Ledge
}
}
-func (p *asyncPersistenceLoop) Enqueue(clock timers.Clock, round basics.Round, period period, step step, raw []byte, done chan error) (events <-chan externalEvent) {
+func (p *asyncPersistenceLoop) Enqueue(clock timers.Clock[TimeoutType], round basics.Round, period period, step step, raw []byte, done chan error) (events <-chan externalEvent) {
eventsChannel := make(chan externalEvent, 1)
p.pending <- persistentRequest{
round: round,
diff --git a/agreement/persistence_test.go b/agreement/persistence_test.go
index fbd9323b09..ef738e86d6 100644
--- a/agreement/persistence_test.go
+++ b/agreement/persistence_test.go
@@ -37,14 +37,14 @@ func TestAgreementSerialization(t *testing.T) {
partitiontest.PartitionTest(t)
// todo : we need to deserialize some more meaningful state.
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
- status := player{Round: 350, Step: soft, Deadline: time.Duration(23) * time.Second}
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ status := player{Round: 350, Step: soft, Deadline: Deadline{Duration: time.Duration(23) * time.Second, Type: TimeoutDeadline}}
router := makeRootRouter(status)
a := []action{checkpointAction{}, disconnectAction(messageEvent{}, nil)}
encodedBytes := encode(clock, router, status, a, false)
- t0 := timers.MakeMonotonicClock(time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC))
+ t0 := timers.MakeMonotonicClock[TimeoutType](time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC))
log := makeServiceLogger(logging.Base())
clock2, router2, status2, a2, err := decode(encodedBytes, t0, log, false)
require.NoError(t, err)
@@ -52,14 +52,30 @@ func TestAgreementSerialization(t *testing.T) {
require.Equalf(t, router, router2, "Router wasn't serialized/deserialized correctly")
require.Equalf(t, status, status2, "Status wasn't serialized/deserialized correctly")
require.Equalf(t, a, a2, "Action wasn't serialized/deserialized correctly")
+
+ // also check if old version gets "upgraded" as side effect of decode
+ clock3 := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ status3 := player{Round: 350, Step: soft, OldDeadline: time.Duration(23) * time.Second}
+ router3 := makeRootRouter(status3)
+ a3 := []action{checkpointAction{}, disconnectAction(messageEvent{}, nil)}
+
+ encodedBytes2 := encode(clock3, router3, status3, a3, false)
+
+ t1 := timers.MakeMonotonicClock[TimeoutType](time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC))
+ clock4, router4, status4, a4, err := decode(encodedBytes2, t1, log, false)
+ require.NoError(t, err)
+ require.Equalf(t, clock, clock4, "Clock wasn't serialized/deserialized correctly")
+ require.Equalf(t, status, status4, "Status wasn't serialized/deserialized correctly")
+ require.Equalf(t, router, router4, "Router wasn't serialized/deserialized correctly")
+ require.Equalf(t, a, a4, "Action wasn't serialized/deserialized correctly")
}
func BenchmarkAgreementSerialization(b *testing.B) {
// todo : we need to deserialize some more meaningful state.
b.SkipNow()
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
- status := player{Round: 350, Step: soft, Deadline: time.Duration(23) * time.Second}
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ status := player{Round: 350, Step: soft, Deadline: Deadline{Duration: time.Duration(23) * time.Second, Type: TimeoutDeadline}}
router := makeRootRouter(status)
a := []action{}
@@ -73,13 +89,13 @@ func BenchmarkAgreementDeserialization(b *testing.B) {
// todo : we need to deserialize some more meaningful state.
b.SkipNow()
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
- status := player{Round: 350, Step: soft, Deadline: time.Duration(23) * time.Second}
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ status := player{Round: 350, Step: soft, Deadline: Deadline{Duration: time.Duration(23) * time.Second, Type: TimeoutDeadline}}
router := makeRootRouter(status)
a := []action{}
encodedBytes := encode(clock, router, status, a, false)
- t0 := timers.MakeMonotonicClock(time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC))
+ t0 := timers.MakeMonotonicClock[TimeoutType](time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC))
log := makeServiceLogger(logging.Base())
b.ResetTimer()
for n := 0; n < b.N; n++ {
@@ -171,11 +187,13 @@ func randomizeDiskState() (rr rootRouter, p player) {
if err != nil {
return
}
+
rr2, err := protocol.RandomizeObject(&rootRouter{})
if err != nil {
return
}
p = *(p2.(*player))
+ p.OldDeadline = 0
rr = *(rr2.(*rootRouter))
return
}
@@ -185,7 +203,7 @@ func TestRandomizedEncodingFullDiskState(t *testing.T) {
for i := 0; i < 5000; i++ {
router, player := randomizeDiskState()
a := []action{}
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
log := makeServiceLogger(logging.Base())
e1 := encode(clock, router, player, a, true)
e2 := encode(clock, router, player, a, false)
@@ -201,7 +219,7 @@ func TestRandomizedEncodingFullDiskState(t *testing.T) {
}
func BenchmarkRandomizedEncode(b *testing.B) {
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
router, player := randomizeDiskState()
a := []action{}
b.ResetTimer()
@@ -211,7 +229,7 @@ func BenchmarkRandomizedEncode(b *testing.B) {
}
func BenchmarkRandomizedDecode(b *testing.B) {
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
router, player := randomizeDiskState()
a := []action{}
ds := encode(clock, router, player, a, false)
@@ -241,10 +259,10 @@ func TestEmptyMapDeserialization(t *testing.T) {
func TestDecodeFailures(t *testing.T) {
partitiontest.PartitionTest(t)
- clock := timers.MakeMonotonicClock(time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
+ clock := timers.MakeMonotonicClock[TimeoutType](time.Date(2015, 1, 2, 5, 6, 7, 8, time.UTC))
ce := clock.Encode()
log := makeServiceLogger(logging.Base())
- player := player{Round: 350, Step: soft, Deadline: time.Duration(23) * time.Second}
+ player := player{Round: 350, Step: soft, Deadline: Deadline{Duration: time.Duration(23) * time.Second, Type: TimeoutDeadline}}
router := makeRootRouter(player)
pe := protocol.Encode(&player)
re := protocol.Encode(&router)
diff --git a/agreement/player.go b/agreement/player.go
index 1ae552b0b1..a3451ea0db 100644
--- a/agreement/player.go
+++ b/agreement/player.go
@@ -40,7 +40,13 @@ type player struct {
// Deadline contains the time of the next timeout expected by the player
// state machine (relevant to the start of the current period).
- Deadline time.Duration
+ Deadline Deadline `codec:"TimersDeadline"`
+
+ // OldDeadline contains the value of Deadline used from a previous version,
+ // for backwards compatibility when deserializing player.
+ // TODO: remove after consensus upgrade that introduces the Deadline struct.
+ OldDeadline time.Duration `codec:"Deadline,omitempty"`
+
// Napping is set when the player is expecting a random timeout (i.e.,
// to determine when the player chooses to send a next-vote).
Napping bool
@@ -111,7 +117,7 @@ func (p *player) handle(r routerHandle, e event) []action {
delta := time.Duration(e.RandomEntropy % uint64(upper-lower))
p.Napping = true
- p.Deadline = lower + delta
+ p.Deadline = Deadline{Duration: lower + delta, Type: TimeoutDeadline}
return actions
}
case roundInterruptionEvent:
@@ -145,7 +151,7 @@ func (p *player) handleFastTimeout(r routerHandle, e timeoutEvent) []action {
func (p *player) issueSoftVote(r routerHandle) (actions []action) {
defer func() {
- p.Deadline = deadlineTimeout
+ p.Deadline = Deadline{Duration: deadlineTimeout, Type: TimeoutDeadline}
}()
e := r.dispatch(*p, proposalFrozenEvent{}, proposalMachinePeriod, p.Round, p.Period, 0)
@@ -213,7 +219,7 @@ func (p *player) issueNextVote(r routerHandle) []action {
_, upper := p.Step.nextVoteRanges()
p.Napping = false
- p.Deadline = upper
+ p.Deadline = Deadline{Duration: upper, Type: TimeoutDeadline}
return actions
}
@@ -327,7 +333,7 @@ func (p *player) enterPeriod(r routerHandle, source thresholdEvent, target perio
p.Step = soft
p.Napping = false
p.FastRecoveryDeadline = 0 // set immediately
- p.Deadline = FilterTimeout(target, source.Proto)
+ p.Deadline = Deadline{Duration: FilterTimeout(target, source.Proto), Type: TimeoutFilter}
// update tracer state to match player
r.t.setMetadata(tracerMetadata{p.Round, p.Period, p.Step})
@@ -375,11 +381,11 @@ func (p *player) enterRound(r routerHandle, source event, target round) []action
switch source := source.(type) {
case roundInterruptionEvent:
- p.Deadline = FilterTimeout(0, source.Proto.Version)
+ p.Deadline = Deadline{Duration: FilterTimeout(0, source.Proto.Version), Type: TimeoutFilter}
case thresholdEvent:
- p.Deadline = FilterTimeout(0, source.Proto)
+ p.Deadline = Deadline{Duration: FilterTimeout(0, source.Proto), Type: TimeoutFilter}
case filterableMessageEvent:
- p.Deadline = FilterTimeout(0, source.Proto.Version)
+ p.Deadline = Deadline{Duration: FilterTimeout(0, source.Proto.Version), Type: TimeoutFilter}
}
// update tracer state to match player
diff --git a/agreement/player_test.go b/agreement/player_test.go
index 75987c2ed0..84aad574ba 100644
--- a/agreement/player_test.go
+++ b/agreement/player_test.go
@@ -500,7 +500,7 @@ func TestPlayerLateBlockProposalPeriod0(t *testing.T) {
func setupP(t *testing.T, r round, p period, s step) (plyr *player, pMachine ioAutomata, helper *voteMakerHelper) {
// Set up a composed test machine starting at specified rps
- rRouter := makeRootRouter(player{Round: r, Period: p, Step: s, Deadline: FilterTimeout(p, protocol.ConsensusCurrentVersion)})
+ rRouter := makeRootRouter(player{Round: r, Period: p, Step: s, Deadline: Deadline{Duration: FilterTimeout(p, protocol.ConsensusCurrentVersion), Type: TimeoutFilter}})
concreteMachine := ioAutomataConcretePlayer{rootRouter: &rRouter}
plyr = concreteMachine.underlying()
pMachine = &concreteMachine
diff --git a/agreement/service.go b/agreement/service.go
index 3cac126193..765f4270a9 100644
--- a/agreement/service.go
+++ b/agreement/service.go
@@ -19,7 +19,6 @@ package agreement
//go:generate dbgen -i agree.sql -p agreement -n agree -o agreeInstall.go -h ../scripts/LICENSE_HEADER
import (
"context"
- "time"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/logging"
@@ -68,7 +67,7 @@ type Parameters struct {
BlockFactory
RandomSource
EventsProcessingMonitor
- timers.Clock
+ timers.Clock[TimeoutType]
db.Accessor
logging.Logger
config.Local
@@ -80,8 +79,8 @@ type parameters Parameters
// externalDemuxSignals used to syncronize the external signals that goes to the demux with the main loop.
type externalDemuxSignals struct {
- Deadline time.Duration
- FastRecoveryDeadline time.Duration
+ Deadline Deadline
+ FastRecoveryDeadline Deadline
CurrentRound round
}
@@ -188,7 +187,7 @@ func (s *Service) demuxLoop(ctx context.Context, input chan<- externalEvent, out
// 4. If necessary, persist state to disk.
func (s *Service) mainLoop(input <-chan externalEvent, output chan<- []action, ready chan<- externalDemuxSignals) {
// setup
- var clock timers.Clock
+ var clock timers.Clock[TimeoutType]
var router rootRouter
var status player
var a []action
@@ -212,7 +211,7 @@ func (s *Service) mainLoop(input <-chan externalEvent, output chan<- []action, r
s.log.Errorf("unable to retrieve consensus version for round %d, defaulting to binary consensus version", nextRound)
nextVersion = protocol.ConsensusCurrentVersion
}
- status = player{Round: nextRound, Step: soft, Deadline: FilterTimeout(0, nextVersion)}
+ status = player{Round: nextRound, Step: soft, Deadline: Deadline{Duration: FilterTimeout(0, nextVersion), Type: TimeoutFilter}}
router = makeRootRouter(status)
a1 := pseudonodeAction{T: assemble, Round: s.Ledger.NextRound()}
@@ -226,7 +225,8 @@ func (s *Service) mainLoop(input <-chan externalEvent, output chan<- []action, r
for {
output <- a
- ready <- externalDemuxSignals{Deadline: status.Deadline, FastRecoveryDeadline: status.FastRecoveryDeadline, CurrentRound: status.Round}
+ fastRecoveryDeadline := Deadline{Duration: status.FastRecoveryDeadline, Type: TimeoutFastRecovery}
+ ready <- externalDemuxSignals{Deadline: status.Deadline, FastRecoveryDeadline: fastRecoveryDeadline, CurrentRound: status.Round}
e, ok := <-input
if !ok {
break
diff --git a/agreement/service_test.go b/agreement/service_test.go
index e24f81890c..fc50c302d5 100644
--- a/agreement/service_test.go
+++ b/agreement/service_test.go
@@ -44,29 +44,34 @@ import (
"github.com/algorand/go-algorand/util/timers"
)
+type testingTimeout struct {
+ delta time.Duration
+ ch chan time.Time
+}
+
type testingClock struct {
mu deadlock.Mutex
zeroes uint
- TA map[time.Duration]chan time.Time // TimeoutAt
+ TA map[TimeoutType]testingTimeout // TimeoutAt
monitor *coserviceMonitor
}
func makeTestingClock(m *coserviceMonitor) *testingClock {
c := new(testingClock)
- c.TA = make(map[time.Duration]chan time.Time)
+ c.TA = make(map[TimeoutType]testingTimeout)
c.monitor = m
return c
}
-func (c *testingClock) Zero() timers.Clock {
+func (c *testingClock) Zero() timers.Clock[TimeoutType] {
c.mu.Lock()
defer c.mu.Unlock()
c.zeroes++
- c.TA = make(map[time.Duration]chan time.Time)
+ c.TA = make(map[TimeoutType]testingTimeout)
c.monitor.clearClock()
return c
}
@@ -75,23 +80,24 @@ func (c *testingClock) Since() time.Duration {
return 0
}
-func (c *testingClock) TimeoutAt(d time.Duration) <-chan time.Time {
+func (c *testingClock) TimeoutAt(d time.Duration, timeoutType TimeoutType) <-chan time.Time {
c.mu.Lock()
defer c.mu.Unlock()
- ta := c.TA[d]
- if ta == nil {
- c.TA[d] = make(chan time.Time)
- ta = c.TA[d]
+ ta, ok := c.TA[timeoutType]
+ if !ok || ta.delta != d {
+ c.TA[timeoutType] = testingTimeout{delta: d, ch: make(chan time.Time)}
+ ta = c.TA[timeoutType]
}
- return ta
+
+ return ta.ch
}
func (c *testingClock) Encode() []byte {
return nil
}
-func (c *testingClock) Decode([]byte) (timers.Clock, error) {
+func (c *testingClock) Decode([]byte) (timers.Clock[TimeoutType], error) {
return makeTestingClock(nil), nil // TODO
}
@@ -99,14 +105,14 @@ func (c *testingClock) prepareToFire() {
c.monitor.inc(clockCoserviceType)
}
-func (c *testingClock) fire(d time.Duration) {
+func (c *testingClock) fire(timeoutType TimeoutType) {
c.mu.Lock()
defer c.mu.Unlock()
- if c.TA[d] == nil {
- c.TA[d] = make(chan time.Time)
+ if _, ok := c.TA[timeoutType]; !ok {
+ panic(fmt.Errorf("no timeout of type %v", timeoutType))
}
- close(c.TA[d])
+ close(c.TA[timeoutType].ch)
}
type testingNetwork struct {
@@ -696,12 +702,12 @@ func (testingRand) Uint64() uint64 {
return maxuint64 / 2
}
-func setupAgreement(t *testing.T, numNodes int, traceLevel traceLevel, ledgerFactory func(map[basics.Address]basics.AccountData) Ledger) (*testingNetwork, Ledger, func(), []*Service, []timers.Clock, []Ledger, *activityMonitor) {
+func setupAgreement(t *testing.T, numNodes int, traceLevel traceLevel, ledgerFactory func(map[basics.Address]basics.AccountData) Ledger) (*testingNetwork, Ledger, func(), []*Service, []timers.Clock[TimeoutType], []Ledger, *activityMonitor) {
var validator testBlockValidator
return setupAgreementWithValidator(t, numNodes, traceLevel, validator, ledgerFactory)
}
-func setupAgreementWithValidator(t *testing.T, numNodes int, traceLevel traceLevel, validator BlockValidator, ledgerFactory func(map[basics.Address]basics.AccountData) Ledger) (*testingNetwork, Ledger, func(), []*Service, []timers.Clock, []Ledger, *activityMonitor) {
+func setupAgreementWithValidator(t *testing.T, numNodes int, traceLevel traceLevel, validator BlockValidator, ledgerFactory func(map[basics.Address]basics.AccountData) Ledger) (*testingNetwork, Ledger, func(), []*Service, []timers.Clock[TimeoutType], []Ledger, *activityMonitor) {
bufCap := 1000 // max number of buffered messages
// system state setup: keygen, stake initialization
@@ -716,7 +722,7 @@ func setupAgreementWithValidator(t *testing.T, numNodes int, traceLevel traceLev
log.SetLevel(logging.Debug)
// node setup
- clocks := make([]timers.Clock, numNodes)
+ clocks := make([]timers.Clock[TimeoutType], numNodes)
ledgers := make([]Ledger, numNodes)
dbAccessors := make([]db.Accessor, numNodes)
services := make([]*Service, numNodes)
@@ -809,7 +815,7 @@ func (m *coserviceMonitor) clearClock() {
}
}
-func expectNewPeriod(clocks []timers.Clock, zeroes uint) (newzeroes uint) {
+func expectNewPeriod(clocks []timers.Clock[TimeoutType], zeroes uint) (newzeroes uint) {
zeroes++
for i := range clocks {
if clocks[i].(*testingClock).zeroes != zeroes {
@@ -820,7 +826,7 @@ func expectNewPeriod(clocks []timers.Clock, zeroes uint) (newzeroes uint) {
return zeroes
}
-func expectNoNewPeriod(clocks []timers.Clock, zeroes uint) (newzeroes uint) {
+func expectNoNewPeriod(clocks []timers.Clock[TimeoutType], zeroes uint) (newzeroes uint) {
for i := range clocks {
if clocks[i].(*testingClock).zeroes != zeroes {
errstr := fmt.Sprintf("unexpected number of zeroes: %v != %v", clocks[i].(*testingClock).zeroes, zeroes)
@@ -830,19 +836,30 @@ func expectNoNewPeriod(clocks []timers.Clock, zeroes uint) (newzeroes uint) {
return zeroes
}
-func triggerGlobalTimeout(d time.Duration, clocks []timers.Clock, activityMonitor *activityMonitor) {
+func triggerGlobalTimeout(d time.Duration, timeoutType TimeoutType, clocks []timers.Clock[TimeoutType], activityMonitor *activityMonitor) {
+ for i := range clocks {
+ clocks[i].(*testingClock).prepareToFire()
+ }
+ for i := range clocks {
+ clocks[i].(*testingClock).fire(timeoutType)
+ }
+ activityMonitor.waitForActivity()
+ activityMonitor.waitForQuiet()
+}
+
+func triggerGlobalTimeoutType(timeoutType TimeoutType, clocks []timers.Clock[TimeoutType], activityMonitor *activityMonitor) {
for i := range clocks {
clocks[i].(*testingClock).prepareToFire()
}
for i := range clocks {
- clocks[i].(*testingClock).fire(d)
+ clocks[i].(*testingClock).fire(timeoutType)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
}
-func runRound(clocks []timers.Clock, activityMonitor *activityMonitor, zeroes uint, filterTimeout time.Duration) (newzeroes uint) {
- triggerGlobalTimeout(filterTimeout, clocks, activityMonitor)
+func runRound(clocks []timers.Clock[TimeoutType], activityMonitor *activityMonitor, zeroes uint, filterTimeout time.Duration) (newzeroes uint) {
+ triggerGlobalTimeout(filterTimeout, TimeoutFilter, clocks, activityMonitor)
return expectNewPeriod(clocks, zeroes)
}
@@ -1039,23 +1056,23 @@ func TestAgreementFastRecoveryDownEarly(t *testing.T) {
baseNetwork.dropAllSoftVotes()
baseNetwork.dropAllSlowNextVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeoutType(TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(0, clocks, activityMonitor) // activates fast partition recovery timer
+ triggerGlobalTimeout(0, TimeoutFastRecovery, clocks, activityMonitor) // activates fast partition recovery timer
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(firstFPR, clocks, activityMonitor)
+ triggerGlobalTimeout(firstFPR, TimeoutFastRecovery, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// terminate on period 1
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1096,13 +1113,13 @@ func TestAgreementFastRecoveryDownMiss(t *testing.T) {
{
// fail all steps
baseNetwork.dropAllVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(0, clocks, activityMonitor) // activates fast partition recovery timer
+ triggerGlobalTimeout(0, TimeoutFastRecovery, clocks, activityMonitor) // activates fast partition recovery timer
zeroes = expectNoNewPeriod(clocks, zeroes)
firstClocks := clocks[:4]
@@ -1112,7 +1129,7 @@ func TestAgreementFastRecoveryDownMiss(t *testing.T) {
firstClocks[i].(*testingClock).prepareToFire()
}
for i := range firstClocks {
- firstClocks[i].(*testingClock).fire(firstFPR)
+ firstClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
@@ -1123,20 +1140,20 @@ func TestAgreementFastRecoveryDownMiss(t *testing.T) {
restClocks[i].(*testingClock).prepareToFire()
}
for i := range restClocks {
- restClocks[i].(*testingClock).fire(firstFPR)
+ restClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(secondFPR, clocks, activityMonitor)
+ triggerGlobalTimeout(secondFPR, TimeoutFastRecovery, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// terminate on period 1
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1179,7 +1196,7 @@ func TestAgreementFastRecoveryLate(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
baseNetwork.dropAllSlowNextVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1200,10 +1217,10 @@ func TestAgreementFastRecoveryLate(t *testing.T) {
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(0, clocks, activityMonitor) // activates fast partition recovery timer
+ triggerGlobalTimeout(0, TimeoutFastRecovery, clocks, activityMonitor) // activates fast partition recovery timer
zeroes = expectNoNewPeriod(clocks, zeroes)
baseNetwork.dropAllVotes()
@@ -1214,7 +1231,7 @@ func TestAgreementFastRecoveryLate(t *testing.T) {
firstClocks[i].(*testingClock).prepareToFire()
}
for i := range firstClocks {
- firstClocks[i].(*testingClock).fire(firstFPR)
+ firstClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
@@ -1225,20 +1242,20 @@ func TestAgreementFastRecoveryLate(t *testing.T) {
restClocks[i].(*testingClock).prepareToFire()
}
for i := range restClocks {
- restClocks[i].(*testingClock).fire(firstFPR)
+ restClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(secondFPR, clocks, activityMonitor)
+ triggerGlobalTimeout(secondFPR, TimeoutFastRecovery, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// terminate on period 1
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1292,7 +1309,7 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
baseNetwork.dropAllSlowNextVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1313,10 +1330,10 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(0, clocks, activityMonitor) // activates fast partition recovery timer
+ triggerGlobalTimeout(0, TimeoutFastRecovery, clocks, activityMonitor) // activates fast partition recovery timer
zeroes = expectNoNewPeriod(clocks, zeroes)
baseNetwork.dropAllVotes()
@@ -1327,7 +1344,7 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
firstClocks[i].(*testingClock).prepareToFire()
}
for i := range firstClocks {
- firstClocks[i].(*testingClock).fire(firstFPR)
+ firstClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
@@ -1338,26 +1355,26 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
restClocks[i].(*testingClock).prepareToFire()
}
for i := range restClocks {
- restClocks[i].(*testingClock).fire(firstFPR)
+ restClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(secondFPR, clocks, activityMonitor)
+ triggerGlobalTimeout(secondFPR, TimeoutFastRecovery, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// fail period 1 with value again
{
baseNetwork.dropAllVotes()
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(0, clocks, activityMonitor) // activates fast partition recovery timer
+ triggerGlobalTimeout(0, TimeoutFastRecovery, clocks, activityMonitor) // activates fast partition recovery timer
zeroes = expectNoNewPeriod(clocks, zeroes)
baseNetwork.dropAllVotes()
@@ -1368,7 +1385,7 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
firstClocks[i].(*testingClock).prepareToFire()
}
for i := range firstClocks {
- firstClocks[i].(*testingClock).fire(firstFPR)
+ firstClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
@@ -1379,20 +1396,20 @@ func TestAgreementFastRecoveryRedo(t *testing.T) {
restClocks[i].(*testingClock).prepareToFire()
}
for i := range restClocks {
- restClocks[i].(*testingClock).fire(firstFPR)
+ restClocks[i].(*testingClock).fire(TimeoutFastRecovery)
}
activityMonitor.waitForActivity()
activityMonitor.waitForQuiet()
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(secondFPR, clocks, activityMonitor)
+ triggerGlobalTimeout(secondFPR, TimeoutFastRecovery, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// terminate on period 2
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(2, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(2, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1443,26 +1460,26 @@ func TestAgreementBlockReplayBug_b29ea57(t *testing.T) {
// fail period 0
{
baseNetwork.dropAllSoftVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// fail period 1 on bottom with block
{
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// terminate on period 2
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(2, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(2, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1503,12 +1520,12 @@ func TestAgreementLateCertBug(t *testing.T) {
pocket := make(chan multicastParams, 100)
{
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
baseNetwork.repairAll()
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1563,7 +1580,7 @@ func TestAgreementRecoverGlobalStartingValue(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1584,7 +1601,7 @@ func TestAgreementRecoverGlobalStartingValue(t *testing.T) {
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 4, int(zeroes))
}
@@ -1594,7 +1611,7 @@ func TestAgreementRecoverGlobalStartingValue(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1611,7 +1628,7 @@ func TestAgreementRecoverGlobalStartingValue(t *testing.T) {
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 5, int(zeroes))
}
@@ -1620,7 +1637,7 @@ func TestAgreementRecoverGlobalStartingValue(t *testing.T) {
// todo: make more transparent, I want to kow what v we agreed on
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(2, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(2, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 6, int(zeroes))
}
@@ -1662,7 +1679,7 @@ func TestAgreementRecoverGlobalStartingValueBadProposal(t *testing.T) {
{
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1689,7 +1706,7 @@ func TestAgreementRecoverGlobalStartingValueBadProposal(t *testing.T) {
}
return params
})
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 4, int(zeroes))
}
@@ -1699,7 +1716,7 @@ func TestAgreementRecoverGlobalStartingValueBadProposal(t *testing.T) {
baseNetwork.repairAll()
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1715,7 +1732,7 @@ func TestAgreementRecoverGlobalStartingValueBadProposal(t *testing.T) {
panic(errstr)
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1723,7 +1740,7 @@ func TestAgreementRecoverGlobalStartingValueBadProposal(t *testing.T) {
// Finish in period 2
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(2, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(2, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 6, int(zeroes))
}
@@ -1765,7 +1782,7 @@ func TestAgreementRecoverBothVAndBotQuorums(t *testing.T) {
{
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllSoftVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
pocketedSoft := make([]multicastParams, len(pocket))
@@ -1790,7 +1807,7 @@ func TestAgreementRecoverBothVAndBotQuorums(t *testing.T) {
}
// generate a bottom quorum; let only one node see it.
baseNetwork.crown(0)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
if clocks[0].(*testingClock).zeroes != zeroes+1 {
errstr := fmt.Sprintf("node 0 did not enter new period from bot quorum")
panic(errstr)
@@ -1809,12 +1826,12 @@ func TestAgreementRecoverBothVAndBotQuorums(t *testing.T) {
// actually create the value quorum
_, upper := (next).nextVoteRanges()
- triggerGlobalTimeout(upper, clocks[1:], activityMonitor) // activates next timers
+ triggerGlobalTimeout(upper, TimeoutDeadline, clocks[1:], activityMonitor) // activates next timers
zeroes = expectNoNewPeriod(clocks[1:], zeroes)
lower, upper := (next + 1).nextVoteRanges()
delta := time.Duration(testingRand{}.Uint64() % uint64(upper-lower))
- triggerGlobalTimeout(lower+delta, clocks[1:], activityMonitor)
+ triggerGlobalTimeout(lower+delta, TimeoutDeadline, clocks[1:], activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 4, int(zeroes))
}
@@ -1824,7 +1841,7 @@ func TestAgreementRecoverBothVAndBotQuorums(t *testing.T) {
baseNetwork.repairAll()
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCertVotes(pocket)
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
closeFn()
@@ -1841,14 +1858,14 @@ func TestAgreementRecoverBothVAndBotQuorums(t *testing.T) {
}
}
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// Finish in period 2
{
baseNetwork.repairAll()
- triggerGlobalTimeout(FilterTimeout(2, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(2, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 6, int(zeroes))
}
@@ -1889,13 +1906,13 @@ func TestAgreementSlowPayloadsPreDeadline(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCompound(pocket) // (takes effect next round)
{
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// run round with late payload
{
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
// release payloads; expect new round
@@ -1947,15 +1964,15 @@ func TestAgreementSlowPayloadsPostDeadline(t *testing.T) {
pocket := make(chan multicastParams, 100)
closeFn := baseNetwork.pocketAllCompound(pocket) // (takes effect next round)
{
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// force network into period 1 by delaying proposals
{
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -1972,7 +1989,7 @@ func TestAgreementSlowPayloadsPostDeadline(t *testing.T) {
activityMonitor.waitForQuiet()
zeroes = expectNoNewPeriod(clocks, zeroes)
- triggerGlobalTimeout(FilterTimeout(1, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(1, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -2012,11 +2029,11 @@ func TestAgreementLargePeriods(t *testing.T) {
for p := 0; p < 60; p++ {
{
baseNetwork.partition(0, 1, 2)
- triggerGlobalTimeout(FilterTimeout(period(p), version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(period(p), version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
baseNetwork.repairAll()
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
require.Equal(t, 4+p, int(zeroes))
}
@@ -2024,7 +2041,7 @@ func TestAgreementLargePeriods(t *testing.T) {
// terminate
{
- triggerGlobalTimeout(FilterTimeout(60, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(60, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
@@ -2111,13 +2128,13 @@ func TestAgreementRegression_WrongPeriodPayloadVerificationCancellation_8ba23942
ch := validator.suspend()
closeFn := baseNetwork.pocketAllCompound(pocket0) // (takes effect next round)
{
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks, zeroes)
}
// force network into period 1 by failing period 0, entering with bottom and no soft threshold (to prevent proposal value pinning)
baseNetwork.dropAllSoftVotes()
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNoNewPeriod(clocks, zeroes)
// resume delivery of payloads in following period
@@ -2128,7 +2145,7 @@ func TestAgreementRegression_WrongPeriodPayloadVerificationCancellation_8ba23942
// release proposed blocks in a controlled manner to prevent oversubscription of verification
pocket1 := make(chan multicastParams, 100)
closeFn = baseNetwork.pocketAllCompound(pocket1)
- triggerGlobalTimeout(deadlineTimeout, clocks, activityMonitor)
+ triggerGlobalTimeout(deadlineTimeout, TimeoutDeadline, clocks, activityMonitor)
baseNetwork.repairAll()
close(pocket1)
{
@@ -2312,7 +2329,7 @@ func TestAgreementCertificateDoesNotStallSingleRelay(t *testing.T) {
return params
})
// And with some hypothetical second relay the network achieves consensus on a certificate and block.
- triggerGlobalTimeout(FilterTimeout(0, version), clocks, activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks, activityMonitor)
zeroes = expectNewPeriod(clocks[1:], zeroes)
require.Equal(t, uint(3), clocks[0].(*testingClock).zeroes)
close(pocketCert)
@@ -2331,7 +2348,7 @@ func TestAgreementCertificateDoesNotStallSingleRelay(t *testing.T) {
activityMonitor.waitForQuiet()
// this relay must still relay initial messages. Note that payloads were already relayed with
// the previous global timeout.
- triggerGlobalTimeout(FilterTimeout(0, version), clocks[1:], activityMonitor)
+ triggerGlobalTimeout(FilterTimeout(0, version), TimeoutFilter, clocks[1:], activityMonitor)
zeroes = expectNewPeriod(clocks[1:], zeroes)
require.Equal(t, uint(3), clocks[0].(*testingClock).zeroes)
@@ -2401,6 +2418,6 @@ func TestAgreementServiceStartDeadline(t *testing.T) {
default:
require.Fail(t, "ready channel was empty while it should have contained a single entry")
}
- require.Equal(t, testConsensusParams.AgreementFilterTimeoutPeriod0, demuxSignal.Deadline)
+ require.Equal(t, testConsensusParams.AgreementFilterTimeoutPeriod0, demuxSignal.Deadline.Duration)
require.Equal(t, baseLedger.NextRound(), demuxSignal.CurrentRound)
}
diff --git a/agreement/types.go b/agreement/types.go
index bc2decb7d0..664fd3a2b0 100644
--- a/agreement/types.go
+++ b/agreement/types.go
@@ -25,6 +25,31 @@ import (
"github.com/algorand/go-algorand/protocol"
)
+// TimeoutType defines the type of a Deadline, to distinguish between different timeouts
+// set by agreement.
+type TimeoutType int8
+
+const (
+ // TimeoutDeadline annotates timeout events in the agreement protocol (e.g.,
+ // for receiving a block).
+ TimeoutDeadline TimeoutType = iota
+ // TimeoutFastRecovery annotates the fast recovery timeout in the agreement
+ // protocol.
+ TimeoutFastRecovery
+ // TimeoutFilter annotates the filter step timeout event in the agreement
+ // protocol.
+ TimeoutFilter
+)
+
+// Deadline marks a timeout event of type Type that the player schedules to
+// happen after Duration time.
+type Deadline struct {
+ _struct struct{} `codec:","`
+ Duration time.Duration
+ // Type is used to allow tests fire timeouts of specific types.
+ Type TimeoutType
+}
+
var deadlineTimeout = config.Protocol.BigLambda + config.Protocol.SmallLambda
var partitionStep = next + 3
var recoveryExtraTimeout = config.Protocol.SmallLambda
diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go
index b7e2a0f414..5efecfcfb6 100644
--- a/cmd/goal/clerk.go
+++ b/cmd/goal/clerk.go
@@ -78,6 +78,7 @@ var (
simulateEnableRequestTrace bool
simulateStackChange bool
simulateScratchChange bool
+ simulateAppStateChange bool
simulateAllowUnnamedResources bool
)
@@ -172,6 +173,7 @@ func init() {
simulateCmd.Flags().BoolVar(&simulateEnableRequestTrace, "trace", false, "Enable simulation time execution trace of app calls")
simulateCmd.Flags().BoolVar(&simulateStackChange, "stack", false, "Report stack change during simulation time")
simulateCmd.Flags().BoolVar(&simulateScratchChange, "scratch", false, "Report scratch change during simulation time")
+ simulateCmd.Flags().BoolVar(&simulateAppStateChange, "state", false, "Report application state changes during simulation time")
simulateCmd.Flags().BoolVar(&simulateAllowUnnamedResources, "allow-unnamed-resources", false, "Allow access to unnamed resources during simulation")
}
@@ -1380,11 +1382,13 @@ func traceCmdOptionToSimulateTraceConfigModel() simulation.ExecTraceConfig {
Enable: true,
Stack: true,
Scratch: true,
+ State: true,
}
}
traceConfig.Enable = traceConfig.Enable || simulateEnableRequestTrace
traceConfig.Stack = traceConfig.Stack || simulateStackChange
traceConfig.Scratch = traceConfig.Scratch || simulateScratchChange
+ traceConfig.State = traceConfig.State || simulateAppStateChange
return traceConfig
}
diff --git a/config/localTemplate.go b/config/localTemplate.go
index aa25417e30..a72ac2fcec 100644
--- a/config/localTemplate.go
+++ b/config/localTemplate.go
@@ -176,7 +176,7 @@ type Local struct {
// EnableTxBacklogRateLimiting controls if a rate limiter and congestion manager shouild be attached to the tx backlog enqueue process
// if enabled, the over-all TXBacklog Size will be larger by MAX_PEERS*TxBacklogReservedCapacityPerPeer
- EnableTxBacklogRateLimiting bool `version[27]:"false"`
+ EnableTxBacklogRateLimiting bool `version[27]:"false" version[30]:"true"`
// TxBacklogSize is the queue size used for receiving transactions. default of 26000 to approximate 1 block of transactions
// if EnableTxBacklogRateLimiting enabled, the over-all size will be larger by MAX_PEERS*TxBacklogReservedCapacityPerPeer
diff --git a/config/local_defaults.go b/config/local_defaults.go
index 1b867ff8e6..21a296b970 100644
--- a/config/local_defaults.go
+++ b/config/local_defaults.go
@@ -76,7 +76,7 @@ var defaultLocal = Local{
EnableRequestLogger: false,
EnableRuntimeMetrics: false,
EnableTopAccountsReporting: false,
- EnableTxBacklogRateLimiting: false,
+ EnableTxBacklogRateLimiting: true,
EnableTxnEvalTracer: false,
EnableUsageLog: false,
EnableVerbosedTransactionSyncLogging: false,
diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json
index e4c8f8bbe8..7337b2a98a 100644
--- a/daemon/algod/api/algod.oas2.json
+++ b/daemon/algod/api/algod.oas2.json
@@ -3684,6 +3684,10 @@
"scratch-change": {
"description": "A boolean option enabling returning scratch slot changes together with execution trace during simulation.",
"type": "boolean"
+ },
+ "state-change": {
+ "description": "A boolean option enabling returning application state changes (global, local, and box changes) with the execution trace during simulation.",
+ "type": "boolean"
}
}
},
@@ -4092,6 +4096,37 @@
}
}
},
+ "ApplicationStateOperation": {
+ "description": "An operation against an application's global/local/box state.",
+ "required": [
+ "operation",
+ "app-state-type",
+ "key"
+ ],
+ "properties": {
+ "operation": {
+ "description": "Operation type. Value `w` is **write**, `d` is **delete**.",
+ "type": "string"
+ },
+ "app-state-type": {
+ "description": "Type of application state. Value `g` is **global state**, `l` is **local state**, `b` is **boxes**.",
+ "type": "string"
+ },
+ "key": {
+ "description": "The key (name) of the global/local/box state.",
+ "type": "string",
+ "format": "byte"
+ },
+ "new-value": {
+ "$ref": "#/definitions/AvmValue"
+ },
+ "account": {
+ "description": "For local state changes, the address of the account associated with the local state.",
+ "type": "string",
+ "x-algorand-format": "Address"
+ }
+ }
+ },
"SimulationOpcodeTraceUnit": {
"description": "The set of trace information and effect from evaluating a single opcode.",
"type": "object",
@@ -4110,6 +4145,13 @@
"$ref": "#/definitions/ScratchChange"
}
},
+ "state-changes": {
+ "description": "The operations against the current application's states.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ApplicationStateOperation"
+ }
+ },
"spawned-inners": {
"description": "The indexes of the traces for inner transactions spawned by this opcode, if any.",
"type": "array",
@@ -4141,6 +4183,11 @@
"$ref": "#/definitions/SimulationOpcodeTraceUnit"
}
},
+ "approval-program-hash": {
+ "description": "SHA512_256 hash digest of the approval program executed in transaction.",
+ "type": "string",
+ "format": "byte"
+ },
"clear-state-program-trace": {
"description": "Program trace that contains a trace of opcode effects in a clear state program.",
"type": "array",
@@ -4148,6 +4195,11 @@
"$ref": "#/definitions/SimulationOpcodeTraceUnit"
}
},
+ "clear-state-program-hash": {
+ "description": "SHA512_256 hash digest of the clear state program executed in transaction.",
+ "type": "string",
+ "format": "byte"
+ },
"logic-sig-trace": {
"description": "Program trace that contains a trace of opcode effects in a logic sig.",
"type": "array",
@@ -4155,6 +4207,11 @@
"$ref": "#/definitions/SimulationOpcodeTraceUnit"
}
},
+ "logic-sig-hash": {
+ "description": "SHA512_256 hash digest of the logic sig executed in transaction.",
+ "type": "string",
+ "format": "byte"
+ },
"inner-trace": {
"description": "An array of SimulationTransactionExecTrace representing the execution trace of any inner transactions executed.",
"type": "array",
diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml
index 01183b62b9..ebe8cdc0df 100644
--- a/daemon/algod/api/algod.oas3.yml
+++ b/daemon/algod/api/algod.oas3.yml
@@ -1300,6 +1300,39 @@
],
"type": "object"
},
+ "ApplicationStateOperation": {
+ "description": "An operation against an application's global/local/box state.",
+ "properties": {
+ "account": {
+ "description": "For local state changes, the address of the account associated with the local state.",
+ "type": "string",
+ "x-algorand-format": "Address"
+ },
+ "app-state-type": {
+ "description": "Type of application state. Value `g` is **global state**, `l` is **local state**, `b` is **boxes**.",
+ "type": "string"
+ },
+ "key": {
+ "description": "The key (name) of the global/local/box state.",
+ "format": "byte",
+ "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
+ "type": "string"
+ },
+ "new-value": {
+ "$ref": "#/components/schemas/AvmValue"
+ },
+ "operation": {
+ "description": "Operation type. Value `w` is **write**, `d` is **delete**.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "app-state-type",
+ "key",
+ "operation"
+ ],
+ "type": "object"
+ },
"ApplicationStateSchema": {
"description": "Specifies maximums on the number of each type that may be stored.",
"properties": {
@@ -2101,6 +2134,10 @@
"stack-change": {
"description": "A boolean option enabling returning stack changes together with execution trace during simulation.",
"type": "boolean"
+ },
+ "state-change": {
+ "description": "A boolean option enabling returning application state changes (global, local, and box changes) with the execution trace during simulation.",
+ "type": "boolean"
}
},
"type": "object"
@@ -2281,6 +2318,13 @@
"stack-pop-count": {
"description": "The number of deleted stack values by this opcode.",
"type": "integer"
+ },
+ "state-changes": {
+ "description": "The operations against the current application's states.",
+ "items": {
+ "$ref": "#/components/schemas/ApplicationStateOperation"
+ },
+ "type": "array"
}
},
"required": [
@@ -2291,6 +2335,12 @@
"SimulationTransactionExecTrace": {
"description": "The execution trace of calling an app or a logic sig, containing the inner app call trace in a recursive way.",
"properties": {
+ "approval-program-hash": {
+ "description": "SHA512_256 hash digest of the approval program executed in transaction.",
+ "format": "byte",
+ "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
+ "type": "string"
+ },
"approval-program-trace": {
"description": "Program trace that contains a trace of opcode effects in an approval program.",
"items": {
@@ -2298,6 +2348,12 @@
},
"type": "array"
},
+ "clear-state-program-hash": {
+ "description": "SHA512_256 hash digest of the clear state program executed in transaction.",
+ "format": "byte",
+ "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
+ "type": "string"
+ },
"clear-state-program-trace": {
"description": "Program trace that contains a trace of opcode effects in a clear state program.",
"items": {
@@ -2312,6 +2368,12 @@
},
"type": "array"
},
+ "logic-sig-hash": {
+ "description": "SHA512_256 hash digest of the logic sig executed in transaction.",
+ "format": "byte",
+ "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
+ "type": "string"
+ },
"logic-sig-trace": {
"description": "Program trace that contains a trace of opcode effects in a logic sig.",
"items": {
diff --git a/daemon/algod/api/server/v2/account.go b/daemon/algod/api/server/v2/account.go
index 41a32b6c8a..31483d63b9 100644
--- a/daemon/algod/api/server/v2/account.go
+++ b/daemon/algod/api/server/v2/account.go
@@ -467,11 +467,11 @@ func AssetParamsToAsset(creator string, idx basics.AssetIndex, params *basics.As
Decimals: uint64(params.Decimals),
DefaultFrozen: &frozen,
Name: omitEmpty(printableUTF8OrEmpty(params.AssetName)),
- NameB64: byteOrNil([]byte(params.AssetName)),
+ NameB64: sliceOrNil([]byte(params.AssetName)),
UnitName: omitEmpty(printableUTF8OrEmpty(params.UnitName)),
- UnitNameB64: byteOrNil([]byte(params.UnitName)),
+ UnitNameB64: sliceOrNil([]byte(params.UnitName)),
Url: omitEmpty(printableUTF8OrEmpty(params.URL)),
- UrlB64: byteOrNil([]byte(params.URL)),
+ UrlB64: sliceOrNil([]byte(params.URL)),
Clawback: addrOrNil(params.Clawback),
Freeze: addrOrNil(params.Freeze),
Manager: addrOrNil(params.Manager),
diff --git a/daemon/algod/api/server/v2/generated/data/routes.go b/daemon/algod/api/server/v2/generated/data/routes.go
index d7429328dc..3af90c3d66 100644
--- a/daemon/algod/api/server/v2/generated/data/routes.go
+++ b/daemon/algod/api/server/v2/generated/data/routes.go
@@ -114,200 +114,204 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "dx/+bwAAAP//oCDbo8rnAAA=",
+ "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",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/generated/experimental/routes.go b/daemon/algod/api/server/v2/generated/experimental/routes.go
index 8efeb17bb2..2448cb966d 100644
--- a/daemon/algod/api/server/v2/generated/experimental/routes.go
+++ b/daemon/algod/api/server/v2/generated/experimental/routes.go
@@ -90,200 +90,205 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
+ "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",
+ "AAAA///Cen75tekAAA==",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/generated/model/types.go b/daemon/algod/api/server/v2/generated/model/types.go
index 68249b1c67..6fab39c06e 100644
--- a/daemon/algod/api/server/v2/generated/model/types.go
+++ b/daemon/algod/api/server/v2/generated/model/types.go
@@ -325,6 +325,24 @@ type ApplicationParams struct {
LocalStateSchema *ApplicationStateSchema `json:"local-state-schema,omitempty"`
}
+// ApplicationStateOperation An operation against an application's global/local/box state.
+type ApplicationStateOperation struct {
+ // Account For local state changes, the address of the account associated with the local state.
+ Account *string `json:"account,omitempty"`
+
+ // AppStateType Type of application state. Value `g` is **global state**, `l` is **local state**, `b` is **boxes**.
+ AppStateType string `json:"app-state-type"`
+
+ // Key The key (name) of the global/local/box state.
+ Key []byte `json:"key"`
+
+ // NewValue Represents an AVM value.
+ NewValue *AvmValue `json:"new-value,omitempty"`
+
+ // Operation Operation type. Value `w` is **write**, `d` is **delete**.
+ Operation string `json:"operation"`
+}
+
// ApplicationStateSchema Specifies maximums on the number of each type that may be stored.
type ApplicationStateSchema struct {
// NumByteSlice \[nbs\] num of byte slices.
@@ -715,6 +733,9 @@ type SimulateTraceConfig struct {
// StackChange A boolean option enabling returning stack changes together with execution trace during simulation.
StackChange *bool `json:"stack-change,omitempty"`
+
+ // StateChange A boolean option enabling returning application state changes (global, local, and box changes) with the execution trace during simulation.
+ StateChange *bool `json:"state-change,omitempty"`
}
// SimulateTransactionGroupResult Simulation result for an atomic transaction group
@@ -814,19 +835,31 @@ type SimulationOpcodeTraceUnit struct {
// StackPopCount The number of deleted stack values by this opcode.
StackPopCount *uint64 `json:"stack-pop-count,omitempty"`
+
+ // StateChanges The operations against the current application's states.
+ StateChanges *[]ApplicationStateOperation `json:"state-changes,omitempty"`
}
// SimulationTransactionExecTrace The execution trace of calling an app or a logic sig, containing the inner app call trace in a recursive way.
type SimulationTransactionExecTrace struct {
+ // ApprovalProgramHash SHA512_256 hash digest of the approval program executed in transaction.
+ ApprovalProgramHash *[]byte `json:"approval-program-hash,omitempty"`
+
// ApprovalProgramTrace Program trace that contains a trace of opcode effects in an approval program.
ApprovalProgramTrace *[]SimulationOpcodeTraceUnit `json:"approval-program-trace,omitempty"`
+ // ClearStateProgramHash SHA512_256 hash digest of the clear state program executed in transaction.
+ ClearStateProgramHash *[]byte `json:"clear-state-program-hash,omitempty"`
+
// ClearStateProgramTrace Program trace that contains a trace of opcode effects in a clear state program.
ClearStateProgramTrace *[]SimulationOpcodeTraceUnit `json:"clear-state-program-trace,omitempty"`
// InnerTrace An array of SimulationTransactionExecTrace representing the execution trace of any inner transactions executed.
InnerTrace *[]SimulationTransactionExecTrace `json:"inner-trace,omitempty"`
+ // LogicSigHash SHA512_256 hash digest of the logic sig executed in transaction.
+ LogicSigHash *[]byte `json:"logic-sig-hash,omitempty"`
+
// LogicSigTrace Program trace that contains a trace of opcode effects in a logic sig.
LogicSigTrace *[]SimulationOpcodeTraceUnit `json:"logic-sig-trace,omitempty"`
}
diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go
index 94c2b17f3e..91b3b3617f 100644
--- a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go
+++ b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go
@@ -130,201 +130,205 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "+L7Z6FAEqNnwj+8//t8AAAD//5R90cnG6AAA",
+ "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",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go
index 6f12f9a396..d5c1c489b6 100644
--- a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go
+++ b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go
@@ -724,276 +724,281 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
+ "H4sIAAAAAAAC/+y9+3fbtrIw+q9g6fvWyuMT5bzas+u7us51k7bbp81jxW732afJbSByJGGbArgB0Jaa",
+ "m//9WxgAJEiCEmXLdtL6p8QiCQwGg3lhHh9HqVgWggPXanT4cVRQSZegQeJfNE1FyXXCMvNXBiqVrNBM",
+ "8NGhf0aUlozPR+MRM78WVC9G4xGnS6jfMd+PRxL+XTIJ2ehQyxLGI5UuYEnNwHpdmLerkVbJXCRuiCM7",
+ "xPGL0acND2iWSVCqC+Vrnq8J42leZkC0pFzR1DxS5ILpBdELpoj7mDBOBAciZkQvGi+TGYM8UxO/yH+X",
+ "INfBKt3k/Uv6VIOYSJFDF87nYjllHDxUUAFVbQjRgmQww5cWVBMzg4HVv6gFUUBluiAzIbeAaoEI4QVe",
+ "LkeHv40U8Awk7lYK7Bz/O5MAf0CiqZyDHr0fxxY30yATzZaRpR077EtQZa4VwXdxjXN2DpyYrybkZak0",
+ "mQKhnLz94Tl5+vTpN2YhS6o1ZI7IeldVzx6uyX4+OhxlVIN/3KU1ms+FpDxLqvff/vAc5z9xCxz6FlUK",
+ "4oflyDwhxy/6FuA/jJAQ4xrmuA8N6jdfRA5F/fMUZkLCwD2xL+91U8L5b3VXUqrTRSEY15F9IfiU2MdR",
+ "HhZ8vomHVQA03i8MpqQZ9LdHyTfvPz4eP3706X/9dpT8j/vzq6efBi7/eTXuFgxEX0xLKYGn62QugeJp",
+ "WVDexcdbRw9qIco8Iwt6jptPl8jq3bfEfGtZ5znNS0MnLJXiKJ8LRagjowxmtMw18ROTkueGTZnRHLUT",
+ "pkghxTnLIBsb7nuxYOmCpFTZIfA9csHy3NBgqSDro7X46jYcpk8hSgxcl8IHLujzRUa9ri2YgBVygyTN",
+ "hYJEiy3iyUscyjMSCpRaVqndhBU5XQDByc0DK2wRd9zQdJ6vicZ9zQhVhBIvmsaEzchalOQCNydnZ/i9",
+ "W43B2pIYpOHmNOSoObx96OsgI4K8qRA5UI7I8+euizI+Y/NSgiIXC9ALJ/MkqEJwBURM/wWpNtv+Xyev",
+ "XxEhyUtQis7hDU3PCPBUZJBNyPGMcKED0nC0hDg0X/atw8EVE/L/UsLQxFLNC5qexSV6zpYssqqXdMWW",
+ "5ZLwcjkFabbUixAtiARdSt4HkB1xCyku6ao76akseYr7X0/b0OUMtTFV5HSNCFvS1bePxg4cRWiekwJ4",
+ "xvic6BXv1ePM3NvBS6QoeTZAzdFmTwPBqgpI2YxBRqpRNkDiptkGD+O7wVMrXwE4fpBecKpZtoDDYRWh",
+ "GXO6zRNS0DkEJDMhvzjmhk+1OANeETqZrvFRIeGciVJVH/XAiFNv1sC50JAUEmYsQmMnDh2Gwdh3HAde",
+ "Oh0oFVxTxiEzzBmBFhoss+qFKZhws73TleJTquDrZ30yvn46cPdnor3rG3d80G7jS4k9khHRaZ66AxvX",
+ "rBrfD7APw7kVmyf2585GsvmpkTYzlqMk+pfZP4+GUiETaCDCyybF5pzqUsLhO/7Q/EUScqIpz6jMzC9L",
+ "+9PLMtfshM3NT7n96WcxZ+kJm/cgs4I1anDhZ0v7jxkvzo71KmpX/CzEWVmEC0obhut0TY5f9G2yHXNX",
+ "wjyqrN3Q8DhdeWNk1y/0qtrIHiB7cVdQ8+IZrCUYaGk6w39WM6QnOpN/mH+KIjdf62IWQ62hYyeS0X3g",
+ "3ApHRZGzlBokvnWPzVPDBMAaErR+4wAF6uHHAMRCigKkZnZQWhRJLlKaJ0pTjSP9bwmz0eHofx3U/pcD",
+ "+7k6CCb/2Xx1gh8ZldWqQQktih3GeGNUH7WBWRgGjY+QTVi2h0oT43YTDSkxw4JzOKdcT2qTpcEPqgP8",
+ "m5upxrfVdiy+WyZYL8KJfXEKymrA9sV7igSoJ4hWgmhFhXSei2n1w/2joqgxiM+PisLiA7VHYKiYwYop",
+ "rR7g8ml9ksJ5jl9MyI/h2KiKC56vjXCwqoaRDTMntZwUq3xLbg31iPcUwe0UcmK2xqPBqPn7oDg0KxYi",
+ "N1rPVloxL//dvRuSmfl90MdfBomFuO0nLjS0HOasjYO/BMbN/RbldAnHuXsm5Kj97eXIxowSJ5hL0crG",
+ "/bTjbsBjhcILSQsLoHtiZSnjaKTZlyysV+SmAxldFObgDAe0hlBd+qxtPQ9RSJAUWjB8l4v07O9ULfZw",
+ "5qd+rO7xw2nIAmgGkiyoWkxGMS0jPF71aEOOmHkRDXwyDaaaVEvc1/K2LC2jmgZLc/DG1RKLevwOmR7I",
+ "iO3yGv9Dc2Iem7NtWL8ddkJOkYEpe5zdJUNmrH1rINiZzAvohRBkaQ18YqzunaB8Xk8e36dBe/S99Sm4",
+ "HXKLqHbodMUyta9twsH69ipUUI9fWItOw1JFrLZqVVRKuo6v3c41BAGnoiA5nEPeBsGyLBzNIkSs9s4X",
+ "vhOrGEzfiVWHJ4gV7GUnzDioV3vsboHvhYNMyO2Yx7GHIN0s0OjyCtkDD1UgM0vtrT6aCnk5dtzis5zU",
+ "PnhCzaiBNBq3kISvlkXizmbEj2dfaA1UX3tu5qLt4WMYa2DhRNNrwIIyo+4DC82B9o0FsSxYDnsg/UVU",
+ "Ck6pgqdPyMnfj756/OT3J199bUiykGIu6ZJM1xoUue+MVaL0OocH3ZWhuVjmOj7618+857Y5bmwcJUqZ",
+ "wpIW3aGsR9jqhPY1Yt7rYq2JZlx1BeAgjghGtFm0E3vZYUB7wZRROZfTvWxGH8KyepaMOEgy2EpMuy6v",
+ "nmYdLlGuZbkP2x6kFDIqugoptEhFnpyDVExErpfeuDeIe8Pr+0X7dwstuaCKmLnRF15y1LAilKVXfDjf",
+ "t0OfrniNm42c3643sjo375B9aSLfu1YVKUAmesVJBtNy3jANZ1IsCSUZfogy+kfQVm9hSzjRdFm8ns32",
+ "YzsLHChiw7IlKDMTsW8YrUFBKrgNDdlirrpRh6CnjRjvs9T9ADiMnKx5io7XfRzbfkt+yTjeAqk1TwOz",
+ "3sCYQzZvkOXVzfc+dNip7qkIOAYdP+Nj9Py8gFzTH4Q8rdW+H6Uoi70ree05hy6HusU431JmvvVOBcbn",
+ "eTMcaW5gn8TWeCsLeu6Pr1sDQo8U+TObL3RgZ72RQsz2D2Nslhig+MBaqbn5pmurvhKZYSa6VHtQwerB",
+ "ag5n6Dbka3QqSk0o4SID3PxSxZWzngAWvDnHC38d6nt6YQ3PKRjqSmlpVlsWBK+zO/Ki/jChqT2hCaJG",
+ "9VzmVbew9i07nQ2OyCXQbE2mAJyIqbsxc3d5uEiKd/HaqzdONYzwiwZchRQpKAVZ4jx1W0Hz71nRoTfg",
+ "CQFHgKtZiBJkRuWVgT073wrnGawTjBxR5P5Pv6oHtwCvFprmWxCL78TQW/k93LVoF+ph028iuPbkIdlR",
+ "CcTLFaIFarM5aOhD4U446d2/NkSdXbw6Ws5B4gXltVK8n+RqBFSBes30flVoy6InHtKZt0bDMxvGKRde",
+ "sYoNllOlk21s2bzUsMHNCgJOGOPEOHCP4vUzVdpeqjOeoS/QihOcxyphZop+gHvNEDPyr94C6Y6dGjnI",
+ "Vakqc0SVRSGkhiy2Bg6rDXO9glU1l5gFY1c2jxakVLBt5D4sBeM7ZNmVWARRXd09uaiT7uLwhsbI+XUU",
+ "lQ0gakRsAuTEvxVgN4wJ6wGEqRrRlnCYalFOFYg2HiktisJwC52UvPquD00n9u0j/Uv9bpe4qK7ldiZA",
+ "YSiae99BfmExa6MBF1QRBwdZ0jOje6AbxN7+d2E2hzFRjKeQbKJ8NPHMW+ER2HpIy2IuaQZJBjlddwf9",
+ "xT4m9vGmAXDHa3NXaEhsWFd802tK9lE0G4YWOJ6KKY8En5DUHEFjCtQE4r7eMnIGOHaMOTk6ulcNhXNF",
+ "t8iPh8u2Wx0ZEaXhudBmxx09IMiOow8BuAcP1dCXRwV+nNS2Z3uKf4JyE1R6xO6TrEH1LaEef6cF9PhQ",
+ "XcR8cF5a7L3FgaNss5eNbeEjfUe2x6H7hkrNUlagrfMTrPdu+rUniN67kgw0ZTlkJHhgzcAi/J7YgKT2",
+ "mJczBQf53rrgd5xvkeXkTKHK0wT+DNZoc7+xka6Bq2MftmxkVCOfKCcIqI+fMyp4+AqsaKrztVHU9ALW",
+ "5AIkEFVOl0xrG8HeNHW1KJJwgOi9xoYZ3a1m9E5x4zXrCQ4VLK+7FeORtQk2w3faMgwa6HC2QCFEPsBD",
+ "1kFGFIJBATCkEGbXmQum9+HUnpIaQDqmjVfalfi/pxpoxhWQf4qSpJSjyVVqqHQaIVFRQAXSzGBUsGpO",
+ "F+pSYwhyWIK1JPHJw4fthT986PacKTKDC5+BYl5so+PhQ/TjvBFKNw7XHvyh5rgdR8QHXvgYweeskDZP",
+ "2R5q4UYespNvWoNXt0TmTCnlCNcs/8oMoHUyV0PWHtLIsDATHHfQXU7jyr67btz3E7Ysc6r3cWsF5zRP",
+ "xDlIyTLYysndxEzw789p/rr6DLNrIDU0mkKSYk7IwLHg1Hxj00i22YZ1eB1bLiFjVEO+JoWEFGzag1H5",
+ "VAXjhNiAyHRB+Rw1fSnKuYvIs+Mgpy6V9anIkneGiGpDesUT9E7HOLeLwvaZL0YPAmpssbZr21oeF7Sa",
+ "zyU7DRGpAfLarv7o7dZ41GuqGqSe16aqRU4zfWcAF28oagF+6okH3oEg6ozS0sVXuC3mFJjNvR5fez10",
+ "DMruxEGMYP2wL0zQ2Mn5eg/aih2ISCgkKJQtoX9J2adiFqbqOeGj1krDsuuCt5/+3nP83vYaeoLnjEOy",
+ "FBzW0ex0xuElPoweJ5RvPR+jptH3bdt4aMDfAqs5zxBqvCp+cbfbJ7R91aR+EHJfd5l2wMF6+YCrw633",
+ "5G7Ky15w0jyP3Am6RJ42A1DjqnAAk4QqJVKGytZxpsb2oLlrRJf100T/myo8eQ9nrz1u6/IrzBFF5y7k",
+ "BaEkzRm6fgVXWpapfscpOpeCpUailrwV3e9ufO5fifs3I+5HN9Q7TjFirXI5RSMtZhDxr/wA4L2OqpzP",
+ "QemWkTIDeMfdW4yTkjONcy3NcUnseSlAYujQxL65pGsyMzShBfkDpCDTUjfVdsxTU5rlubuJM9MQMXvH",
+ "qSY5UKXJS8ZPVzicv633R5aDvhDyrMJCXLrPgYNiKolHV/1on2IksFv+wkUFY10B+9hHWdaJsyOzzEau",
+ "/P93/z8PfztK/ocmfzxKvvk/B+8/Pvv04GHnxyefvv32/2/+9PTTtw/+83/HdsrDHsuicpAfv3Am7fEL",
+ "tFvqy5sO7DfmuF8ynkSJLAzDaNEWuY8Zw46AHjS9WnoB77hecUNI5zRnmeEtlyGHtoTpnEV7OlpU09iI",
+ "lhfLr3VHa+AKXIZEmEyLNV5ai+oGJMbzFfE20aUg4nmZldxupde+bTqODwwTs3GVk2rL1RwSTFhcUB/V",
+ "6P588tXXo3GdaFg9H41H7un7CCWzbBVLJ81gFTPy3AHBg3FPkYKuFeg490DYozFwNigjHHYJyylItWDF",
+ "zXMKpdk0zuF8koNzFq34MbcR7eb84N3k2l15iNnNw60lQAaFXsTKWDQUNXyr3k2AVrxIIcU58DFhE5i0",
+ "nTWZsRddNF4OdIblFND6FEOsoeocWELzVBFgPVzIII9IjH5a8fxO+Ku9m0Nu4Bhc7Tmri0j/txbk3o/f",
+ "n5IDxzDVPZvZbIcOclEjprRLt2pEEhluZov3WCXvHX/HX8CMcWaeH77jGdX0YEoVS9VBqUB+R3PKU5jM",
+ "BTn0GVwvqKbveEfT6q2vFeTOkaKc5iwlZ6FBUpOnrZnSHeHdu99oPhfv3r3vBFV0zQc3VZS/2AkSowiL",
+ "Uieu4kMi4YLK2KWVqjL+cWRb0mXTrFbJFqX1bPqKEm78OM+jRaHamb/d5RdFbpYfkKFyea1my4jSQnpd",
+ "xCgoFhrc31fCCQZJL7xfpVSgyIclLX5jXL8nybvy0aOnQBqpsB+cyDc0uS5gsHelNzO57VTBhVuzElZa",
+ "0qSg89jd2Lt3v2mgBe4+6stL9HHkOcHPGim4PqIeh6oX4PHRvwEWjp3TCXFxJ/YrX90rvgR8hFuI7xh1",
+ "o76xv+x+BUm5l96uVmJvZ5dKvUjM2Y6uShkS9ztTFf2ZGyXLh1EoNkdr1dVHmgJJF5CeucI1sCz0etz4",
+ "3EfqOEXTsw6mbEkjm1KHRTXwZmEKpCwy6lRxytft6gYKtPbxwG/hDNanoq7JsUs5g2Z2veo7qEipgXZp",
+ "iDU8tm6M9ua7cDA07IvCJ6ljtqIni8OKLvw3/QfZqrx7OMQxomhkf/chgsoIIizx96DgEgs1412J9GPL",
+ "M1bG1Eq+SHkjz/uJe6U2nlzkVrga9Lrb50vA+mjiQpEpNXq7cKW9bAZ5wMVKRefQoyGHlzsD87QbF0I4",
+ "yDa5F5V0YtYWaB15EwXZvpyYNUcpBcwTQypozLTi9fxM9v7Q3UxgxU6HsGmOalIV2GiZDpWNSzZbgrAP",
+ "tDgBg+S1wuHBaGIk1GwWVPmqY1iczZ/lQTrANVZE2FQH5zgINQsqsFVVbjzPbZ/TjnXpquH4Eji+7k1o",
+ "Wg6oYWM0fIxuj22H4KgAZZDD3C7cvuwJpa7OUG+QgeP1bJYzDiSJRa0FbtBAzLg5wOjHDwmxHngyeIQY",
+ "GQdg4704DkxeifBs8vkuQHJXXYL6sfFGPfgb4nlfNo7bqDyiMCyc9dxqpZ4DUBfqWMmvVsAtDkMYHxPD",
+ "5s5pbtics/jqQTrlWFBtbRVfcZEZD/rU2Q0XIFaw7LQmK4ous5pQZ/JAxxW6DRBPxSqxiZ9RjXe6mhp6",
+ "j4a2Yxpq7GDawjf3FJmKFUb7oGixodRbYOmHw4MRWPgrppBe8bs+aW6B2TTtZm0qRoUKSca58ypy6VMn",
+ "hkzdo8H0kcv9oJbNpQBoOTvqwtDO+N1qpDbVk64wr6XauK7R5rOGYse/7whFd6kHf10vTFV95k1bY4n6",
+ "KZpBK83CO4EKGSN6wya6lzTdqyAFOaBRkDSUqOQsdnNqbBtAiXPiPwucF1jeh/L1gyASSsKcKQ21E93H",
+ "SdyGe5JiVUEhZv2r04WcmfW9FaISU/YaET9sLPPGV4ChxDMmlU7wBiK6BPPSDwqN6h/Mq3FdqRlrZWvw",
+ "sizOG3DaM1gnGcvLOL26eX96YaZ9VbFEVU6R3zJuA1amWDM6GoG5YWobpLtxwT/bBf9M97beYafBvGom",
+ "loZcmnN8IeeixXk3sYMIAcaIo7trvSjdwCCDzNkudwz0puCOf7LJ+9o5TJkfe2vUjs/f7ZNRdqToWgKH",
+ "wcZVMLwmMmoJ00HJ5W5Ka88ZoEXBslXLF2pH7bWY6U4OD1+oroUF3F032BYMoEr7FmYgIepCqB7Z6OhK",
+ "XQoLFWJmd6MUTmTTe53/TVeaF5RV54hgoks4wVxpyf49rmMvG6UXm0uJ9C7ozloyrr9+1qXIysdvYBmy",
+ "Gydx1/qJMTSaiA/MLVvKfMsmsB7DPSTPgD2HUzHlG3F0ybbKgdxGuadA859g/at5F5cz+jQeXc2RHaN8",
+ "N+IWXL+pDlsUzxgoYR2bjXupHVFOi0KKc5onzt3fxyikOHeMAl/3twM3LHjilH36/dHPbxz4n8ajNAcq",
+ "k0px610Vvld8MauyxSh7Dogv9G8scG9BWcU+2Pyqgl54RXCxAFcxPbANOqVd6+uf4Ci6K4NZPF5rK+9z",
+ "N1V2iRturKCoLqxqZ6q9r2reUdFzynLvxfTQ9sRW4eKG1QeOcoVwgCvfdQVXlsle2U3ndMdPR01dW3gS",
+ "zvUaSyLFtRPuCiYhK3J3V00WdE85yjrAVR9MxaqWngNl8g9CNpi/C6yP3n15gd1mjHuR3Q6PPaFGvgtH",
+ "W/GcEKQl8mH+wZzGhw/Do/bw4Zh8yN2DAED8fep+R2fRw4dRt2TU6jBMAo0KTpfwoAoS7N2ImzVROVwM",
+ "E9BH50tEHcZ695NhRaH2Esuj+8Jh70Iyh8/M/ZJBDuan7Qk0rU236A6BGXKCTvoC6asYiaVt/KGI4O2Q",
+ "IMzhMKSFzH5JsbSx9fJ2jxAvl+gZTVTO0vidEZ8qw165jQUwLxN8uce4NiOWrCe0hJcsGMu8NqRWVwvI",
+ "YI4oMlW0XFiNu6lwx7vk7N8lEJYB1+aRRLnWEnXeOMBROwqpsYW6c7mB7Y1jPfxVbKawrHdbZ0QgNhtM",
+ "YeRBB9wXlQvQL7TysNc2064BTOGMHca9IfjI0YejZhuMvWhGEAyzY4Y0gPOMztUX75kj2tCNqWQmxR8Q",
+ "91uhuy+SgOkLmTOM2vsDQvMsbGPUYCmVt7ruS1fPvm27h9vGfRt/ZVvYL7qqnX4ZYRo/1btt5GWMXhUv",
+ "E+iQ3GeEhVcXzci2HtaCxyuI5cCy1f5ak3J7nmz2YSNAOn4qw1SEAzt+fSodzJ30jZxeTGmsprexhQxM",
+ "wfY2LmC1IP5jvwGqStGzs5MgAKl6l9kKJgXIOgG9Ww3tknaNnXawRVMbMEhRoekytkEjuRKRYUp+Qbnt",
+ "hWa+s/zKfa3A3piYry6ExPpDKn5XnEHKljSPGzhZ2r0XzNic2TZfpYKgj5QbyLZQtFTkenFViacONccz",
+ "8mgcNLNzu5Gxc6bYNAd847F9Y0oVisvq9qL6xCwPuF4ofP3JgNcXJc8kZHqhLGKVIJXtiUpeFfEwBX0B",
+ "wMkjfO/xN+Q+xnoodg4PDBadEjQ6fPwN3tTZPx7FpKxr07aJZWfIs//heHacjjHYxY5hmKQbdRIt1WL7",
+ "tPZLhw2nyX465Czhm06gbD9LS8rpHOLhhcstMNlvcTfx9qWFF57ZJoNKS7EmTMfnB00Nf+pJWTLsz4JB",
+ "UrFcMr10EQFKLA091U2i7KR+ONux0NX393D5hxhYU/i4gpav64bNGLrsCTnG8KdXdAlNtI4JtUWnclaH",
+ "vPmuI+TY17TDhgdVnwOLGzOXWTrqkhgBNyOFZFyj/6PUs+RvxiyWNDXsb9IHbjL9+lmkcUCztjbfDfAb",
+ "x7sEBfI8jnrZQ/ZeZ3Hfkvtc8GRpOEr2oE4RDE5lbwRQPNajL+Bk89BDNV8zStJLbmWD3GjAqa9EeHzD",
+ "gFckxWo9O9Hjziu7ccosZZw8aGl26Je3PzstYylkrFBtfdydxiFBSwbnGPAd3yQz5hX3QuaDduEq0N/u",
+ "dbVXOQO1zJ/lqCHgnU6bEr2MCv/rS9eUuKN79wSn2eiz6psbTmCLOi2thtZwmz3+QKSxJFEbffgQgX74",
+ "cOyUuQ9Pmo8tk3r4MF6+Leo4Mr/WWLiKXYffxvbwOxFx4/heKdUVuktSi7jR+liteWCO8tQNNSbNvhQ3",
+ "Lwv3E/4cD3GJn4J3737DJx4P+EcbEbd85HED6yA+u5IeQgn68kRJJqueB8F1lHwnVkMJp8VJPfF8Bijq",
+ "QclAJxOupNN3KHrpvDXqIaBRM+oUcmFMpbCkeuiV/nLwbBY/3oDtkuXZr3WBjZYgkZSni2ho0tR8+Hvd",
+ "H7haomWV0SrNC8o55NHhrIX2u7fkIrbmv8TQeZaMD3y33ffKLre1uBrwJpgeKD+hQS/TuZkgxGqzdkGV",
+ "G5fPRUZwnrokcM0cuw3kgq42/y5B6djRwAc2Ph+vbAzztU1VCPAMfTgT8iNmERtYGvUe0XfiC3I1i9OU",
+ "RS5oNsZCYaffH/1M7Kz2G9vl0jZ1maProLmKqK93eLGeqmFlPAt1+Dib0+LMqpVOqh4ssTof5o26Swxr",
+ "BQCgUyHEzoS8CJr525IgZgiCdeLkErKg5Yu1KJAmzH+0pukCHSUNQdZP8sO7EXmqVEFL9Kq1aVUCHM+d",
+ "gds1JLL9iMZE6AXIC6YA847gHJqlRao6O85R50uNNJcnS84tpUx20Cmqgt+7ot0DZxUSf8MZhayF+B3N",
+ "ZNvMa9fmTCf4VbQiabvTU6cXui1UUbWsfOm72VMuOEuxHmhMIcIyCMPuTAaUTo1fdqiRO6GRwxXtL1Vl",
+ "PDgs9nac8ozQIa57/xg8NZtqqcP+qWHl+g7MQSvH2SAb+zZpzjvPuAJX0t0QUcgnhYxEWMRUjqS6zd2R",
+ "jDDDucfd8oN59so54zD174xxNLsd2pyabf3n2MFeG1udaTIXoNx6mmVe1G/mmwlWPMlg9X7iO97jGDam",
+ "xyzbBrB1hzry4WwufMy8+9y86+pQVj83YlPspEdF4Sbtb6IX7xy64r0IjgVR+FvtALnV+OFoG8htYxwq",
+ "ylNDaHCOITRQoBzuEEbVUK7VvdWYCJai8A1io/GjxagYj4DxM+P+PicuINKoSMCNwfPa851KJdVWBRzE",
+ "006B5lXMTJuhKe0uBK86VLsKp0EJrtHP0b+NdS+8HsZRvVArbpSviT8UhroDZeI5zas4zkhnO9SqnBKV",
+ "YXJoq9ddjHEYxu27aTYFwJYGuuP6cyxJu6sk6qv3MS2zOeiEZlmswv53+JTgU5KVqDnACtKyqsReFCTF",
+ "8nbNen9danMTpYKrcrlhLv/CFacLmkdGqCFsYOl3GPOJp2v8d5fWxlUE584ZHT5cM9utyGU3QyWm9Rqa",
+ "ThSbJ8MxgTLl6uiop74codff75XSczFvAnIbTtIeLhfuUYy/fW8ER1gEqxMsa0VLVaMKA1OF74GOZmNV",
+ "XaXJlVCUdYrt4xVs1VJ4sxuivznwGIVfTxZV6PK28tW6gftyqdLe1D+qXRECTclGFtSb2G0DF1tO9O59",
+ "Rl+woo1V3J/z2a11I0J9HHkXoJ98kgopKHMBKzWz6GLWhfl20z2HxNHWG9xehEvZ6/WP/nTel17na97i",
+ "83bz0DNwlYkKCedMlD4UxAdkepPQ/tpoxVklOEbXHw1zvm3nc6+r/NQ1cbLLdDb5T7/a8F0CXMv1Z+A4",
+ "72x6py1pV9u17qn6FVL1/xjUD6QhFYfUg46VHna6YaMx6pa2rh2yejFEHei2aR2PjrOdBGasfPXIjhI7",
+ "dvGmq/3VPeuKnnjECqFY3YYn1o11YOTzKTZUDaqTdsfyEXHnkGrsvVRH+kiAXWqVmsmC/u53VT57zOkq",
+ "QNwV99xU0bPbcGmLjO8k3QeFI2yzmsnw+pVHVTynTUe5oAqrPdsW680EzsFpZLMZpJqdbyly8I8F8CCB",
+ "fuz9MgjLLKh5wKqkCqyRt7vXsQZoUw2CjfAEtaqvDE5fUu0ZrO8p0qCGaPecKqPoMuXREAPIHRJDIkLF",
+ "4qWsI9mFsDBVUQZiwccn2s+hLjTb23gzKNlxybk8SRrBUZfx2DBlvPPfoLnMpzsVt8H8gL46CN3GYf32",
+ "xwvs06aqpti+vFpopZPjbhHqC1eeDUtSVHcnvlAbKP+brz9jZ8nZGYStQfGm6oLKzL8Rdb14r06yQR51",
+ "ihf4pldtoGfVzKyOJu/eVUfKmmJiRpoLo0YkfdktzQDuKvrpnrJharbLDoamG7hmIF0LZdR/c6Eg0cJH",
+ "n2+CYxMqbCzepZCgekuJW+B6C/y9rSsYYksFigX9qAvBCxdIJCypgU4GdQb759yE7Of2uc8I9iX1t3qY",
+ "Knrd3tvJ5xEw1UFiSPUz4qTl9kzjyzibGOcgE3/z1C46yEE2b0MKKbIytQI6PBiVQ25wSc8NrCTqp0m7",
+ "q2zZCEHG7hmsD6wR5Jti+R0MgbaakwU9KFbV2uS9ut9UDO75XsC7Tc/VeFQIkSc9lx3H3UqJbYo/Y+kZ",
+ "ZMRICh9v29OokNxHH3t1m32xWPvKgEUBHLIHE0KOuM1w8BfbzVYdrcn5Pb1p/hXOmpW2eKlzqk3e8Xio",
+ "OJYVlVfkZn6YzTxMgWF1V5zKDrKlDt+qp0qjpBeRtp2ToVZ596q53UqxJioLRUwnObE3Vs/xoMccR5iP",
+ "HRQOwItMStxNF1G5iIVkXiZn3AwVx1Q4GQKkgQ9JXa6gcINHEVC1SdwSKFTFCNUd5uo4oa56lOfiIsFj",
+ "lFR1ZmNGl3lPNcWEL61ff2fobQpBxBFVToVYkwXNSCqkhDT8Ip4WZaFaCglJLjAAKXY3OtNGI1xiLgQn",
+ "uZgTURhD39Zr9rdI0f6HnblKzikKdAjiPaIooGmK1qcg7htSfTN0yn21l7TFT+yiE3vL1hMSCcoVO3EY",
+ "si934d3Q4XH37pGni4izDDHnCWTnFpGOyHfu7BaAOeBwbXcUHsU6YDbX1e7F2tcZWYslS+Po/rJChHoD",
+ "e2LUG636Ypsr2DxdfA15SsjHqhthPD1dNAOn0zwqH9zxczdjSOfmv6g2tMclM3D8rIeHdo+0Y/1J2iug",
+ "WgAgpDZ5TJfSdmQIxUfV51XMbbIp3uu1AR3IcDB84mqwmRH2DpSGKwHVCdmqALxvLaaxrc5jw7+mYuWf",
+ "P6jL91wK+E+bqTzWxTZyiivSck12fap/D0eIRpVsDuKwnc2nQ0M5qu45A5l/AEB/cEcDhkEhHruCMaMs",
+ "hyyhESQfV4b1ODAPXFpAuycaU46Tp9Q61hZAzNilBJd6bluat3qoFtSQkqhe77q/eAYrUJgXbhtBUmWd",
+ "td5p7Pqpty0YUSQ5nEMj5sXlw5eohbBzCHux249JBlDgFUrbsI8Fc4SyvGXtubUnQTjAEOxGzT+LWLtT",
+ "ZIttF7VEVzyxx0QNPUoGonOWlbSBP3WFrtT9Dak76mNi1UR7IIZM84sd4a0f4Mh/H1NlPCbeD+NDO7Og",
+ "OOo2MaCtwV14oqKnnsdju8JiD5VXGGfLqtsjS+I131AFveD9XpQuydea+PBu8QFiv19BilpNM3jp6jgh",
+ "OBhRrUIuvSq4rHb48t64W6HhjSTcO17M1FCADLY2xmpfuV9HRRdhy3rsgsWN2mu0Zuw84fi/439jbNxr",
+ "BzImoG2EEXbmfwH+2gNry1YeX6fQskqg+SCtsSst1rYfWRCeuqRrIiT+w4Um/y5pzmZrPKEWfP8ZUQtq",
+ "SMjds9gLQBf0ZSberJiMPWDehBV+KrtuNnTMYLi1GSUA2ohAIqRz2S/pGYTbgHeblvOk2rAcVU6XTCkU",
+ "dq3t7GLBLd6nhy9pBkEuCRapanYg82ULzdf/T536Ek7la8sUOU3rjsKKLlteRdvayBOXXsByc25U1zz2",
+ "JFC1S6qJVvqcyMyWLrH4q+oUoCaC/5kyLalcb4jU3Hr9HQs4Rs15G9idNjKohu9tGbv0NazTSzdklQ1a",
+ "yr53YeglewdovKnzBX62gG8Ls/liQDeB/2j9uL5lDAH/c8F7T/edEF7baOcGsNzIm47Aal2AU7FKJMzU",
+ "tvtk6wM0hrCsM659EAHjqQSq7AX78WtnstXl0Rg3JqQNAauuMKpRMpgxXjNLxotmt3vHrrFKGl8HCAs9",
+ "qYjWHo95n5Zg1LBzmr8+BylZ1rdx5nTY7h9heWrvPXbfRoz/SqZ2B2Cqtn4wHQvqdJ/gNSPAMzabgbTR",
+ "WUpTnlGZha8zTlKQRu6TC7pWl3fTG2hlafSLLY56GmgzzSThwGWPpG0BydfuDuiKTvQKQLpHb/oALziG",
+ "AUY84NYpokWP07sLQzw3na6SXMwxSaeHAF0dOrymsMaK4OiwtfrQbvMo9gdsngZL8LqDrwXOOmSKzefs",
+ "NaIODZ5fONMbT5r1prWzpmxYmz0Inv75vI6ttZvTpf9Yotupba4fJru1e9X6vbZ37HY+6Om90/Tg9uwi",
+ "3jK6LMnQXauG32Q0LjJj6XTWhk3QtlUbomdBBd39Uxf90HX6dIxii5SxS0bc0SdkPcleDvSAZxvcubPV",
+ "nLa6kTbjDNc1guvXOESFKJJ0SEiVrdKdOYe2g7QJYw99BO7qnnVXt891z+VGdYhGAXurKV9G3W0V0N92",
+ "L1Okm4zsPodGDwdtOsvFDHkZHmHrxsFA+cp5MW6ncDQdNhWTIJRISEuJDs0Lut7eYqSnOuTJ34++evzk",
+ "9ydffU3MCyRjc1B1hdFWi4467Ibxtp/lZgNtOsvT8U3wyb0Wcf6mzOcsVJvizprltlZz49EGJbt4QiMC",
+ "INaKutsa4lJ7hePUkbOf13bFFrn3HYuh4Hr2zIUHxhdwxJ39ImZkM8+oL0b8cY/wC6P8R4SU39pLLLDP",
+ "H9ufXHoZeqwdsp8NFUayZfdGe9Vyr4Piolrm5bruDQKtmzkZIQ8EoCclqpHMEjblrIv+SevbRS+wvzBr",
+ "C7GX9UXa1thdhMR/sAW8MMepfq8KN3Xg3HL1vJcVUoKlvO+jhMbyt6VNuQXWN4/BFjlTV2uwLZJtDaDm",
+ "vgQ5cep5lWrWo9t2MtKwA6exb/I8kslmrW88UyHhGMVSntP85rkGtmY9QnxA9rY/fj1MZwqRbFGpLldM",
+ "6Wc6aO4gdWl/U/M3mD33DzB7FJVzbih36diRZug7obmNNJy5TGQzJLnAMW1QyeOvydSVZy4kpEy1LzPt",
+ "jZPLxcLsHZBs5lLhYKW3pAttW+evQl+BjGc+8oC8Ci4lBDp/agjrI3rLTKXn5EapPEZ9HbKI4C/Go8J2",
+ "blvExVkjJ7/WxQOJJiTsOTc/qLKzY25+t1Hd0OXZ/HMjdEoF3XUOltYN3EYEdb22oYUlBtdSxgb7Q+pB",
+ "xOsem8+xIMVeCiDvVP74GkpRWBy5Mdy8MYr5ta84oS3A11MHs7UfJcu3hhk0qpp+Go/mwEExhXU7f3fV",
+ "xm9WlnoIbHps96haWK+S028RE1lrY/JgqqBe6YBSpe6zSGFSTD1JS8n0GjvNeTcM+z1aNOPHKgHbJfBX",
+ "NyBO9mlxBlW3zzpdu1Reuv4oaI7yyF7McCOFRD4h36/ossidU5F8e2/6H/D0b8+yR08f/8f0b4++epTC",
+ "s6++efSIfvOMPv7m6WN48revnj2Cx7Ovv5k+yZ48ezJ99uTZ1199kz599nj67Otv/uOe4UMGZAuoL6N7",
+ "OPrv5Cifi+TozXFyaoCtcUIL9hOYvUFbeSawE5JBaoonEZaU5aND/9P/60/YJBXLenj/68hV9B8ttC7U",
+ "4cHBxcXFJPzkYI75mYkWZbo48PNgf5qGvvLmuIpJttETuKO1DxI31ZHCET57+/3JKTl6czypCWZ0OHo0",
+ "eTR57Johclqw0eHoKf6Ep2eB+37giG10+PHTeHSwAJpjOQPzxxK0ZKl/JIFma/d/dUHnc5ATDDu3P50/",
+ "OfBqxcFHl6f6ycwQvbWxVW2DUqa+80bd4t7lvKM70UYGq7CvmPWzlmpMprbznA8+5BkGiNjUTxV2XzzO",
+ "DMLs58c10/LN82x39MPfIrVDfMS67+kWhvwEwUD/dfL6FRGSOPPmDU3Pqmh9cjyzPXqkOGdYwzILCp+a",
+ "Lyeefv9dglzX9OU4X9hrGni5NEzEhf0v1bxoltGrtaqY16eDaz+zIYuAsKus8ppx4R1fAEnNhg1rfZR8",
+ "8/7jV3/7NBoACJY4UIAtfj7QPP9ALlieE1hhRGAr7mHcF5EyrrOU8YN6J8fokaqeBp/X7zSrz37ggsOH",
+ "vm1wgEX3gea5eVFwiO3Be2xCg8SCZ+7Jo0ee0Tg1PoDuwJ2poZ3FfcFl62uuRvEkcYmBugzJPnpbFSKT",
+ "tLBn0T2xqWnO229fmhi+82yPC22WS7vyctvDdRb9Hc2IdCl5uJTHX+xSjrmNxDOCxQrAT+PRV1/w3hxz",
+ "w3NoTvDNoMNbV9D8ws+4uOD+TaP8lMsllWtUbXTFC9vF3Olc4RUbskh7toNaN3w+ev+pV+odhCFnBx8b",
+ "hSqyK8lEG2XTaIWwRUzeU32cs9vG/f5RUWDE3Un1/KgobMNIvFUGhtIPVkxp9WBCfgy/Ru6N7YZsM59S",
+ "YtRQ7U4xUq/qn+i7MjZuToNOTFGhHbiL7+T3bcvvo6azo9HoOAZM4xRshKkTu3JVAdpNbggKUuwajloV",
+ "I3WqReL6lQwcw7dx3lszngF56Ham9zFTcCujvsNdD+761KQA3kpjqjsB3Qxr9nUNK0nSEBnXyLi/cKXv",
+ "Jc0NnQTLbfUPsN2/75TBv4wyWNU/m1vtrCj2oB5iTPzBR9/RfQ8qoWuEPkAZDM3q4Nsgrvl+i508mNjO",
+ "4eE7l+MZruDZVjUP++zfKXifgYJnK8ZtU+0cHd+qUhem1OyS4dLQRrDd/5CPv3At7i+MrF61zUC6XWG7",
+ "BPvsKGOOWV8bW/1TKmEOaXfq119a/arKkF5JAQsDVA9chndwjXUl713bO8d0pYk1S9EGnA2LIGCusz3C",
+ "4zqk27AYGy7sAoXV2FuGeJ1qjUa7WeOO3dhVsX6E0ED9bn38Ypt29QX5eQZ3lIxIgfjeXDcvjV47vL2Z",
+ "a4dhvOnZo2c3B0G4C6+EJj+gFL9mDnmtLC1OVruysE0c6WBqu5dv4kq8xZaqslm2K3nAo6oa3OPguXnb",
+ "Rmncx2zKZg+SBxPie6XXFRZctvBcGEbls4KonNuPDK8zyCD3/J+HOP69CfkBc920GmOwGVZSwhcZ14eP",
+ "nzx95l6R9MLGcrXfm3797PDo22/da4VkXGM8gLVzOq8rLQ8XkOfCfeBkRHdc8+Dwv//5P5PJ5N5WtipW",
+ "361f2aaFnwtvHcfqsFUE0LdbX/gmxax13+x9G+pu5Pr+O7GKSgGxupNCtyaFDPb/FNJn2iQjZ4hWnsxG",
+ "W4M9SiN7THaRR2Pfl9zwnUqYTMgr4TrMlDmVtvYGFvZUZF5SSbkGyCaeUrGsk7IdNdKcYZq4JArkOchE",
+ "sQzq2qNVgYhCwjnGyNelJxsQbGf0GEn72TL5l3QVpEhPKzGthVsyuj2XdEWwZLomCvTYVqdakW+/JY/G",
+ "tfWS52aApEJMjLku6Wp0g16/itiGllx54bAj5PYAXRx7iAep1n6qqndh8/q/Nuf+YjV3S+5uY/fEOXe+",
+ "+KkvdkI/guvjstGDYBU7jTVaVVkU+bquzmm0PK9CxVmcmWGoc+AzviPY6pqOGqFt9N4d4jsnwJVYSZug",
+ "dmQbmHWqDj6iXR7yjM65xay5v9Z1aXB3JMXSXx4JMgOdLlzCbgv1EfYkXdJgP29aMs6WBspH42vXanAX",
+ "u7VlwzaaGbVp8kM6tQS5lHiBBzJCxK99Y2nzmM1swWnfhsBXisOrKVezt+pdZ41v283SxfP7vN6CNnrx",
+ "bYfyeT15VyFDtOzj/vMOwbshuMMcv3c1Cezxcov4M0T8e1MyIa9EnTZuLag/5dXjdUr2617QK8HB3rEb",
+ "zdfS4t11aqV2GMZhkeLrhVj7pWqZfmkV5MDX2dmoh/zdvLRFFxkivbFmz5cowv8erUbUkDJmbZOtxRDq",
+ "0YYwZ/OirTXfbOJ9i1bMrfDTz9C0uQ2OdTMsBg+p5zNOLeD7ZTpYgscS80HVv7mPA8Vb4g/mRlpUYWjR",
+ "LvZTyAWfq8+TFW2ijjheIlRiK03ZlhWd9U/+gmf3uesn4fsiu3pPivEUiBJLQJPB6OjY48AGSz579Leb",
+ "g1CzpW+CysPc1VvmLl89enpz05+APGcpkFNYFkJSyfI1+YVXfSOuwu0UoW7PQ29whDkwjrdNzbpgaVjE",
+ "6PJMsBG69lGvWPZpOzMMCinuyAcZD/hgWESbFgVQeXkGuP3qqt1k8vhFGB3caMNfVdSKgGJQtGOA/P8Z",
+ "DfQ7Ydq7mDnhV3ILqK/+5diEC90Vs3EVHGO0ADE7JO/4Q6IW1BendH8++errHs+ZmccV7en6zuqBzGM7",
+ "zBAH2hftDtyv1l7h9/Cmd3u3TRyPWLaKNuqGVVA6vNkEz6ll9xQp6Lq3m38RL0RZaQPhsEswarxasOLm",
+ "ix0qzabxaq/e/KmaqR7z7yor2FbkM8p3cRtF7sYjLQEyKPRia+1LfKveTXBVMJlyVe9thcIxYROY2AJ+",
+ "dTeQDHvmG4uakhzorGrrIcSQ5ImAzxhC81QRYD1cyBCbNEo/WDAEifLmjdM6ycAKOo882ZI5t6ro6tsy",
+ "UhO0UYF7xaaJltvTKbGZ/Di47i6k0CIVuY1dKYtCSF2dbjUZpO5B37VdQ9vrI9wrKXMrlqmtfrRTfGsP",
+ "jrQmZasvxo926tEUc6TFFnXJinz1XENY2qkoSKeJqwHhVvnandMtxs9aPrcv3eWme0lvzx64lOp0URYH",
+ "H/E/WJHwU50ohbXa1YFe8QPsqXTwcWNIE7LU3Ogm0pZ5b9jR0ZbQXbcefl6XlP9ByE5P/20hSy2kjdtC",
+ "3/aHwtinCHu8HmvyL22EbfRXtjb86ldwkRE757XKAw663FS0GzQq8Km9tsdVhITvrow/rwXVTtwZ4xmh",
+ "wTa2fE1VH1pvA/zti130bfiFb/6e/Ksv+Jy9EpocLwvb8B+yq0UbkjaH89Jjo7jdTTFwor8bktiV+aHE",
+ "94HUlS6yVcDvYPcEpSPAT0cl1nIwsvp6zJ07Sf55S/LnvkR6gwzv5PKXI5elD/++E8Gfvwh++sWu5hov",
+ "jgeKZC+JLi2Ga0t8R4HcUQacD6vlONh0r4ymd3uV6gchfTueOyn+hV6K2p0cnGQ5xEOzzRPrptxHqP9n",
+ "Bf0wP0OeRzwNfQd1bHuT6QUwLJIlUob9Do4zNbaH2Dkn3Cm+U3w+a8Un2Os7vefO9fCFuR56tBxn9ef5",
+ "EEVjVwXofCky8BerYjZzRSn7tJ9mryxDnkrTZUHsl1Etx17CsiWcmDdf2yn2KmJrsFtqUQs8gywFqeCZ",
+ "GhDF4Ua9rBzCi6Z+AG78ZrPaAQ+LK1cxuTTJvg1qXnUogbSRr7DHmS/O6ZCRwTkxBDjZA9kefLT/ojut",
+ "ECqymhNPwJ2Nue+2xVYbteM2ACRvUAl1Hf3dV2JGHtmioyXHzMK6mSnlGdFybRRVX2NJAs1J2sgoquDo",
+ "npyT3pOz1RTorK5nTXFbQNQndJ8RDK1szp9u/AA8p9yRfBdBWhBKOMypZufgr/wndxVALi3NXP2NDQxw",
+ "TGiW2dNYbwKcg1wTVU6V0XV4MzD8nmqelx0YBqwKkMyIaJrXF/DWTDiw5T02xRGd2DeuKLRavMgWFZHN",
+ "qEUvWV3JETEjL1kqxVE+F8rHoaq10rDstAp1n/7eUyTaOxK6MauC54xDshQ81sDyNT59iQ9jX2OJlL6P",
+ "T83Dvm9b8rYJfwus5jxDZPJV8fuZnP4rBbq0ViuhENJYt1PbVNvS/45HyR+aNU+7J2nN0+BSyz0MBgrb",
+ "XTZ+PvjY+NMV93FvqkWpM3ERfIuWvQ1SHFLXI2isfwlPWqtBvbpeX9p13iEFeIidmOpppFVh/bC/W+Ff",
+ "NJ/NXbmERIKh5qk4B6la5tldUtufKqlt8L7vxGNta95tHK1U+9VIXokM7LjNztixevJcZOA6CHcVkSrY",
+ "MZ4I5KVS/V4rNSOl5XyhSVkQLWJJIPWHCU0tk02seROfMKjgaI0gnG5Bz4HQHPsykykAJ2JqFl3LR1wk",
+ "VVhD02eSuJDOqCoUwFVIkYJSkCW+fv420Kq+zBiArjfgCQFHgKtZiBJkRuWVgT073wrnGawTNHEVuf/T",
+ "r8ZgvnF4rSq4GbG2cl8EvVV1IKftdaEeNv0mgmtPHpIdlUC8aoCJb2JZ5OBS3yIo3AknvfvXhqizi1dH",
+ "C+aGsWumeD/J1QioAvWa6f2q0JZFYuR3F8Tn9ukpW6ImxikX3q8YGyynSifb2LJ5KVyLMisIOGGME+PA",
+ "PQbnz1Tpty4LOsOKWVac4DxWxzZT9ANcdeKPjfyrfRgbOzXykKtSETeCz2yCLLYGDqsNc72CVTUXpqH7",
+ "savUKevh2zZyH5aC8R2ygiYChOrgNt8MF1kc+h+pc1B0UdkAokbEJkBO/FsBdsNr/B5AmKoRbQkHiyKH",
+ "lDMVIgfKbQaqKArDLXRS8uq7PjSd2LeP9C/1u13iorqW25kAFaa1OcgvLGYVOmgXVBEHB1nSM5f5NndN",
+ "4bowm8OYYMWKZBPlo8vWvBUega2HtCzmkmaQZJDTiCvlF/uY2MebBsAd9+SZnAsNyRRmQkJ802tKlr0u",
+ "ompogeOpmPJI8AlJzRE0xnNNIO7rLSNngGPHmJOjo3vVUDhXdIv8eLhsu9U9bikzhtlxRw8IsuPoQwDu",
+ "wUM19OVRgR8ntfugPcU/QbkJKj1i90nWoPqWUI+/0wLa7rxQgDUkRYu9tzhwlG32srEtfKTvyMYciF+k",
+ "s78du3SNqXNNB2pgAE4uY9weXFCmk5mQVpFO6EyD3BoQ/w/K/HW4T8oVrpYKwRGc3HTjIJMPW/M4LmJB",
+ "IE5cGBKZkNMFSDAyjJLHZMl4qe0TUeqxrSQqgaYLo7SHnlU7EjZXdO0GJcypzHJsvDer5KaQKIyYbgl4",
+ "BDqSZdi0+M26fxByUH3iZhUuyjQpuWZ50KOhsts/P+/lnUfiziNx55G480jceSTuPBJ3Hok7j8SdR+LO",
+ "I3HnkbjzSPx1PRK3Vfwo8RqHr8PIBU/aIZJ3EZJ/qgK9lajyDhL0TlxQpl3HYV97oN9vsYMjSAPNEQcs",
+ "h/6YbRtKevr90c9EiVKmQFIDIeOkyKkxDWClq/6Xzc7Kvue7baJrmzZTBU+fkJO/H/k6ogtX77L57v0j",
+ "2+CNKL3O4YHrMAM8s5qobzUD3CDddZqhXiT4PpmuayjLMd5dke/x7RdwDrkoQNoShUTLMtJo/hRo/tzh",
+ "ZovD5x9mchdA+8GM9mHccHo5tC1p4dV8v1aqCLV5lORFkFn5YUZzBR/6kivteEtaxFpVVoLPuoKQmXwn",
+ "snXrhJhdO8ANbJ6Nupoo41SuI7WfuokNbdLQwrArR1hdX9anvde87RJtl8y2UVhMW5egoud4E5VHi71W",
+ "G9YZyqbfzlp0MopljrYrnI4qAAeV+8PkB7sn5K397naL+yFE7ojVzPyziWJsvlkxDXzXGBGO9XypGQIe",
+ "8dHTi2d/bAg7K1MgTCviy+ZuFy/j0SoxI82BJ44BJVORrZMG+xo1pFDGFFUKltPtkijkn645uxM+5slm",
+ "OXU7YuRFsLhNPDkkmlXiGHAPd15rGMybK2zhiI49Bxi/bhbdx0ZDEIjjTzGnUov37cr06mnWd4zvjvEF",
+ "p7GlETDuyoy3mcjkGhmfXMuS9/O871eQlga48CTfR+88XsnBSjcuWTOYlvM5Npnv3NGZpQGOxwS/JVZo",
+ "lzuUC+5GQXbwqvHwVVPP28N1uUuQDX7f11t8gNtB+RovM5YF5Wt/5QuJYssytzi0/Tn3y2htJfBY4eja",
+ "99fn1X7jXX6B79aJ2ubvFi3kgipi9xcyUvLM5TF1Klav+PDqJXbo0xWv2fTGSiV2vZHVuXmHiAi/y80E",
+ "ckUKkIlecXugGofJ9SWwJ3dy11z7ryE2bPo59DDYbo39miHsSXrIgK+h+Ag6KdWJeY3+SrSZJNh4hh6N",
+ "/hSXsOWSfXOvgSWd4ZvxJbW7xd2fQl4QStKc4e2q4ErLMtXvOMX7m2Bhk27siXdU9/O+5/6V+BVi5IbP",
+ "DfWOUwwyqm51ojxwBpErjB8APItV5XwOyvDRkIBmAO+4e4txUnJjhYkZWbJUisQmzJrzZXSXiX1zSddk",
+ "hnVKBPkDpCBTI/WDXbe+ZKVZnrtgFzMNEbN3nGqSA1WavGSGA5vhfJGEKuQM9IWQZxUW4h145sBBMZXE",
+ "HTM/2qfY5MYt3zsA0ZlpH9fNKW62u42HnWW9kB+/wBg1rLGcM6Xr+IgO7Dd2N75kPIkS2ekCiAsXa9MW",
+ "uY+V3RwBPWheHOkFvONG+mlBkONTfTlyaN8Adc6iPR0tqmlsROuiyK91kPm3Fy5DIkzm7trlT5RCGtCB",
+ "v9nEjbdV81t7v+MVS0PkAs/M0x6BbJ+6pog9LzkDouEka5WtcW+cNkDeeH/x5ReL3L8t6dG4N2uyO2CX",
+ "XTXb3iHe/IaPCc0Fn9tqica6FLhPjBelxgDw63TgwTnNE3EOUrIM1MCVMsG/P6f56+qzT+MRrCBNtKQp",
+ "JNajMBRrp+YbS6fbBGnQ/HO5hIxRDfmaFBJSyGxdMKZIbYhPbGUFki4on6PMlaKcL+xrdpwLkFD1STS2",
+ "b3uIeF2WFU9sjbgujEfEOjHDMrpA00WkjwtKJmNse0rIGi2iBiKvUQG0z7oej3o1ZIPU8zrmzSKnyR8G",
+ "iP+GIA/wU0+8j5Kpd9R6R623Rq2x0oSIulnLP2DxFW7LNTuSrrsQ5w36pW6lSu9dqfs/e6l7z4EUoUTS",
+ "htYf77FGFWGaXGAhoikQI3hK9Ie7xnXOQsbctuCou4qVyrW5SxeUcVfFpsokQDi067qufZvXa3ElWmaG",
+ "PkSDDkhLyfQa7QRasN/PwPz/vVG0Fchzb0KUMh8djhZaF4cHB7lIab4QSh+MPo3DZ6r18H0F/0ev/ReS",
+ "nRuL5tP7T/83AAD//2UrnPtBngEA",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/generated/participating/private/routes.go b/daemon/algod/api/server/v2/generated/participating/private/routes.go
index 46da1c3e3d..37433a761d 100644
--- a/daemon/algod/api/server/v2/generated/participating/private/routes.go
+++ b/daemon/algod/api/server/v2/generated/participating/private/routes.go
@@ -158,203 +158,208 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "3zXk8b65RzyZfHj34f8HAAD//w2Fuvhe8gAA",
+ "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",
+ "AA==",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/generated/participating/public/routes.go b/daemon/algod/api/server/v2/generated/participating/public/routes.go
index 1be6755019..207ec3f291 100644
--- a/daemon/algod/api/server/v2/generated/participating/public/routes.go
+++ b/daemon/algod/api/server/v2/generated/participating/public/routes.go
@@ -177,212 +177,216 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "AA==",
+ "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",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go
index d1da2895d1..85b44c1668 100644
--- a/daemon/algod/api/server/v2/utils.go
+++ b/daemon/algod/api/server/v2/utils.go
@@ -29,6 +29,7 @@ import (
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
+ "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
@@ -101,6 +102,14 @@ func addrOrNil(addr basics.Address) *string {
return &ret
}
+func digestOrNil(digest crypto.Digest) *[]byte {
+ if digest.IsZero() {
+ return nil
+ }
+ ret := digest.ToSlice()
+ return &ret
+}
+
// omitEmpty defines a handy impl for all comparable types to convert from default value to nil ptr
func omitEmpty[T comparable](val T) *T {
var defaultVal T
@@ -110,18 +119,12 @@ func omitEmpty[T comparable](val T) *T {
return &val
}
-func byteOrNil(data []byte) *[]byte {
- if len(data) == 0 {
- return nil
- }
- return &data
-}
-
-func nilToZero(numPtr *uint64) uint64 {
- if numPtr == nil {
- return 0
+func nilToZero[T any](valPtr *T) T {
+ if valPtr == nil {
+ var defaultV T
+ return defaultV
}
- return *numPtr
+ return *valPtr
}
func computeCreatableIndexInPayset(tx node.TxnWithStatus, txnCounter uint64, payset []transactions.SignedTxnWithAD) (cidx *uint64) {
@@ -372,84 +375,83 @@ func ConvertInnerTxn(txn *transactions.SignedTxnWithAD) PreEncodedTxInfo {
return response
}
-func convertScratchChanges(scratchChanges []simulation.ScratchChange) *[]model.ScratchChange {
- if len(scratchChanges) == 0 {
- return nil
+func convertToAVMValue(tv basics.TealValue) model.AvmValue {
+ return model.AvmValue{
+ Type: uint64(tv.Type),
+ Uint: omitEmpty(tv.Uint),
+ Bytes: sliceOrNil([]byte(tv.Bytes)),
}
- modelSC := make([]model.ScratchChange, len(scratchChanges))
- for i, scratchChange := range scratchChanges {
- modelSC[i] = model.ScratchChange{
- Slot: scratchChange.Slot,
- NewValue: model.AvmValue{
- Type: uint64(scratchChange.NewValue.Type),
- Uint: omitEmpty(scratchChange.NewValue.Uint),
- Bytes: byteOrNil([]byte(scratchChange.NewValue.Bytes)),
- },
- }
+}
+
+func convertScratchChange(scratchChange simulation.ScratchChange) model.ScratchChange {
+ return model.ScratchChange{
+ Slot: scratchChange.Slot,
+ NewValue: convertToAVMValue(scratchChange.NewValue),
}
- return &modelSC
}
-func convertTealValueSliceToModel(tvs []basics.TealValue) *[]model.AvmValue {
- if len(tvs) == 0 {
- return nil
+func convertApplicationState(stateEnum logic.AppStateEnum) string {
+ switch stateEnum {
+ case logic.LocalState:
+ return "l"
+ case logic.GlobalState:
+ return "g"
+ case logic.BoxState:
+ return "b"
+ default:
+ return ""
}
- modelTvs := make([]model.AvmValue, len(tvs))
- for i := range tvs {
- modelTvs[i] = model.AvmValue{
- Type: uint64(tvs[i].Type),
- Uint: omitEmpty(tvs[i].Uint),
- Bytes: byteOrNil([]byte(tvs[i].Bytes)),
- }
+}
+
+func convertApplicationStateOperation(opEnum logic.AppStateOpEnum) string {
+ switch opEnum {
+ case logic.AppStateWrite:
+ return "w"
+ case logic.AppStateDelete:
+ return "d"
+ default:
+ return ""
}
- return &modelTvs
}
-func convertProgramTrace(programTrace []simulation.OpcodeTraceUnit) *[]model.SimulationOpcodeTraceUnit {
- if len(programTrace) == 0 {
- return nil
+func convertApplicationStateChange(stateChange simulation.StateOperation) model.ApplicationStateOperation {
+ return model.ApplicationStateOperation{
+ Key: []byte(stateChange.Key),
+ NewValue: omitEmpty(convertToAVMValue(stateChange.NewValue)),
+ Operation: convertApplicationStateOperation(stateChange.AppStateOp),
+ AppStateType: convertApplicationState(stateChange.AppState),
+ Account: addrOrNil(stateChange.Account),
}
- modelProgramTrace := make([]model.SimulationOpcodeTraceUnit, len(programTrace))
- for i := range programTrace {
- var spawnedInnersPtr *[]uint64
- if len(programTrace[i].SpawnedInners) > 0 {
- spawnedInners := make([]uint64, len(programTrace[i].SpawnedInners))
- for j, innerIndex := range programTrace[i].SpawnedInners {
- spawnedInners[j] = uint64(innerIndex)
- }
- spawnedInnersPtr = &spawnedInners
- }
- modelProgramTrace[i] = model.SimulationOpcodeTraceUnit{
- Pc: programTrace[i].PC,
- SpawnedInners: spawnedInnersPtr,
- StackAdditions: convertTealValueSliceToModel(programTrace[i].StackAdded),
- StackPopCount: omitEmpty(programTrace[i].StackPopCount),
- ScratchChanges: convertScratchChanges(programTrace[i].ScratchSlotChanges),
- }
+}
+
+func convertOpcodeTraceUnit(opcodeTraceUnit simulation.OpcodeTraceUnit) model.SimulationOpcodeTraceUnit {
+ return model.SimulationOpcodeTraceUnit{
+ Pc: opcodeTraceUnit.PC,
+ SpawnedInners: sliceOrNil(convertSlice(opcodeTraceUnit.SpawnedInners, func(v int) uint64 { return uint64(v) })),
+ StackAdditions: sliceOrNil(convertSlice(opcodeTraceUnit.StackAdded, convertToAVMValue)),
+ StackPopCount: omitEmpty(opcodeTraceUnit.StackPopCount),
+ ScratchChanges: sliceOrNil(convertSlice(opcodeTraceUnit.ScratchSlotChanges, convertScratchChange)),
+ StateChanges: sliceOrNil(convertSlice(opcodeTraceUnit.StateChanges, convertApplicationStateChange)),
}
- return &modelProgramTrace
}
func convertTxnTrace(txnTrace *simulation.TransactionTrace) *model.SimulationTransactionExecTrace {
if txnTrace == nil {
return nil
}
-
- execTraceModel := model.SimulationTransactionExecTrace{
- ApprovalProgramTrace: convertProgramTrace(txnTrace.ApprovalProgramTrace),
- ClearStateProgramTrace: convertProgramTrace(txnTrace.ClearStateProgramTrace),
- LogicSigTrace: convertProgramTrace(txnTrace.LogicSigTrace),
+ return &model.SimulationTransactionExecTrace{
+ ApprovalProgramTrace: sliceOrNil(convertSlice(txnTrace.ApprovalProgramTrace, convertOpcodeTraceUnit)),
+ ApprovalProgramHash: digestOrNil(txnTrace.ApprovalProgramHash),
+ ClearStateProgramTrace: sliceOrNil(convertSlice(txnTrace.ClearStateProgramTrace, convertOpcodeTraceUnit)),
+ ClearStateProgramHash: digestOrNil(txnTrace.ClearStateProgramHash),
+ LogicSigTrace: sliceOrNil(convertSlice(txnTrace.LogicSigTrace, convertOpcodeTraceUnit)),
+ LogicSigHash: digestOrNil(txnTrace.LogicSigHash),
+ InnerTrace: sliceOrNil(convertSlice(txnTrace.InnerTraces,
+ func(trace simulation.TransactionTrace) model.SimulationTransactionExecTrace {
+ return *convertTxnTrace(&trace)
+ }),
+ ),
}
-
- if len(txnTrace.InnerTraces) > 0 {
- innerTraces := make([]model.SimulationTransactionExecTrace, len(txnTrace.InnerTraces))
- for i := range txnTrace.InnerTraces {
- innerTraces[i] = *convertTxnTrace(&txnTrace.InnerTraces[i])
- }
- execTraceModel.InnerTrace = &innerTraces
- }
-
- return &execTraceModel
}
func convertTxnResult(txnResult simulation.TxnResult) PreEncodedSimulateTxnResult {
diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md
index 6f4124f048..735bdc45d4 100644
--- a/data/transactions/logic/README.md
+++ b/data/transactions/logic/README.md
@@ -618,6 +618,8 @@ Global fields are fields that are common to all the transactions in the group. I
| 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. |
| 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. |
| 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. |
+| 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. |
+| 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. |
**Asset Fields**
diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md
index 5a30ce35c7..1d5bba1461 100644
--- a/data/transactions/logic/TEAL_opcodes.md
+++ b/data/transactions/logic/TEAL_opcodes.md
@@ -465,6 +465,8 @@ Fields
| 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. |
| 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. |
| 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. |
+| 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. |
+| 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. |
## gtxn
diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go
index fa0bcc1338..1769cfa9fb 100644
--- a/data/transactions/logic/assembler_test.go
+++ b/data/transactions/logic/assembler_test.go
@@ -1676,6 +1676,8 @@ txn NumApprovalProgramPages
txna ApprovalProgramPages 0
txn NumClearStateProgramPages
txna ClearStateProgramPages 0
+global AssetCreateMinBalance
+global AssetOptInMinBalance
`, AssemblerMaxVersion)
for _, globalField := range GlobalFieldNames {
if !strings.Contains(text, globalField) {
diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go
index 4dc1290a49..871aa0399a 100644
--- a/data/transactions/logic/eval.go
+++ b/data/transactions/logic/eval.go
@@ -3630,6 +3630,10 @@ func (cx *EvalContext) globalFieldToValue(fs globalFieldSpec) (sv stackValue, er
} else {
sv.Bytes = zeroAddress[:]
}
+ case AssetCreateMinBalance:
+ sv.Uint = cx.Proto.MinBalance
+ case AssetOptInMinBalance:
+ sv.Uint = cx.Proto.MinBalance
default:
err = fmt.Errorf("invalid global field %d", fs.field)
}
diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go
index 2947fe6d4d..20479c6905 100644
--- a/data/transactions/logic/eval_test.go
+++ b/data/transactions/logic/eval_test.go
@@ -1226,7 +1226,8 @@ const globalV9TestProgram = globalV8TestProgram + `
`
const globalV10TestProgram = globalV9TestProgram + `
-// No new globals in v10
+global AssetCreateMinBalance; int 1001; ==; &&
+global AssetOptInMinBalance; int 1001; ==; &&
`
func TestGlobal(t *testing.T) {
@@ -1249,7 +1250,7 @@ func TestGlobal(t *testing.T) {
7: {CallerApplicationAddress, globalV7TestProgram},
8: {CallerApplicationAddress, globalV8TestProgram},
9: {CallerApplicationAddress, globalV9TestProgram},
- 10: {CallerApplicationAddress, globalV10TestProgram},
+ 10: {AssetOptInMinBalance, globalV10TestProgram},
}
// tests keys are versions so they must be in a range 1..AssemblerMaxVersion plus zero version
require.LessOrEqual(t, len(tests), AssemblerMaxVersion+1)
diff --git a/data/transactions/logic/fields.go b/data/transactions/logic/fields.go
index 40660f1f40..10bd93cb20 100644
--- a/data/transactions/logic/fields.go
+++ b/data/transactions/logic/fields.go
@@ -528,6 +528,13 @@ const (
// CallerApplicationAddress The Address of the caller app, else ZeroAddress
CallerApplicationAddress
+ // AssetCreateMinBalance is the additional minimum balance required to
+ // create an asset (which also opts an account into that asset)
+ AssetCreateMinBalance
+
+ // AssetOptInMinBalance is the additional minimum balance required to opt in to an asset
+ AssetOptInMinBalance
+
invalidGlobalField // compile-time constant for number of fields
)
@@ -588,6 +595,10 @@ var globalFieldSpecs = [...]globalFieldSpec{
"The application ID of the application that called this application. 0 if this application is at the top-level."},
{CallerApplicationAddress, StackAddress, ModeApp, 6,
"The application address of the application that called this application. ZeroAddress if this application is at the top-level."},
+ {AssetCreateMinBalance, StackUint64, modeAny, 10,
+ "The additional minimum balance required to create (and opt-in to) an asset."},
+ {AssetOptInMinBalance, StackUint64, modeAny, 10,
+ "The additional minimum balance required to opt-in to an asset."},
}
func globalFieldSpecByField(f GlobalField) (globalFieldSpec, bool) {
diff --git a/data/transactions/logic/fields_string.go b/data/transactions/logic/fields_string.go
index 44531c2bdf..5ff79cf396 100644
--- a/data/transactions/logic/fields_string.go
+++ b/data/transactions/logic/fields_string.go
@@ -108,12 +108,14 @@ func _() {
_ = x[OpcodeBudget-12]
_ = x[CallerApplicationID-13]
_ = x[CallerApplicationAddress-14]
- _ = x[invalidGlobalField-15]
+ _ = x[AssetCreateMinBalance-15]
+ _ = x[AssetOptInMinBalance-16]
+ _ = x[invalidGlobalField-17]
}
-const _GlobalField_name = "MinTxnFeeMinBalanceMaxTxnLifeZeroAddressGroupSizeLogicSigVersionRoundLatestTimestampCurrentApplicationIDCreatorAddressCurrentApplicationAddressGroupIDOpcodeBudgetCallerApplicationIDCallerApplicationAddressinvalidGlobalField"
+const _GlobalField_name = "MinTxnFeeMinBalanceMaxTxnLifeZeroAddressGroupSizeLogicSigVersionRoundLatestTimestampCurrentApplicationIDCreatorAddressCurrentApplicationAddressGroupIDOpcodeBudgetCallerApplicationIDCallerApplicationAddressAssetCreateMinBalanceAssetOptInMinBalanceinvalidGlobalField"
-var _GlobalField_index = [...]uint8{0, 9, 19, 29, 40, 49, 64, 69, 84, 104, 118, 143, 150, 162, 181, 205, 223}
+var _GlobalField_index = [...]uint16{0, 9, 19, 29, 40, 49, 64, 69, 84, 104, 118, 143, 150, 162, 181, 205, 226, 246, 264}
func (i GlobalField) String() string {
if i >= GlobalField(len(_GlobalField_index)-1) {
diff --git a/data/transactions/logic/langspec.json b/data/transactions/logic/langspec.json
index 1892aa42be..c8fdb8ea3f 100644
--- a/data/transactions/logic/langspec.json
+++ b/data/transactions/logic/langspec.json
@@ -1126,7 +1126,9 @@
"GroupID",
"OpcodeBudget",
"CallerApplicationID",
- "CallerApplicationAddress"
+ "CallerApplicationAddress",
+ "AssetCreateMinBalance",
+ "AssetOptInMinBalance"
],
"ArgEnumTypes": [
"uint64",
@@ -1143,7 +1145,9 @@
"[32]byte",
"uint64",
"uint64",
- "address"
+ "address",
+ "uint64",
+ "uint64"
],
"Doc": "global field F",
"ImmediateNote": [
diff --git a/data/transactions/logic/opcodeExplain.go b/data/transactions/logic/opcodeExplain.go
new file mode 100644
index 0000000000..ec95d97d1b
--- /dev/null
+++ b/data/transactions/logic/opcodeExplain.go
@@ -0,0 +1,274 @@
+// Copyright (C) 2019-2023 Algorand, Inc.
+// This file is part of go-algorand
+//
+// go-algorand is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// go-algorand is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with go-algorand. If not, see .
+
+package logic
+
+import "github.com/algorand/go-algorand/data/basics"
+
+// debugStackExplain explains the effect of an opcode over the stack
+// with 2 integers: deletions and additions, representing pops and inserts.
+// An opcode may delete a few variables from stack, then add a few to stack.
+type debugStackExplain func(*EvalContext) (int, int)
+
+// AppStateOpEnum stands for the operation enum to app state, should be one of create, write, read, delete.
+type AppStateOpEnum uint64
+
+const (
+ // AppStateWrite stands for writing to an app state.
+ AppStateWrite AppStateOpEnum = iota + 1
+
+ // AppStateDelete stands for deleting an app state.
+ AppStateDelete
+)
+
+// AppStateEnum stands for the enum of app state type, should be one of global/local/box.
+type AppStateEnum uint64
+
+const (
+ // GlobalState stands for global state of an app.
+ GlobalState AppStateEnum = iota + 1
+
+ // LocalState stands for local state of an app.
+ LocalState
+
+ // BoxState stands for box storage of an app.
+ BoxState
+)
+
+// stateChangeExplain explains how an opcode change the app's state with a quadruple:
+// AppStateEnum stands for which app state: local/global/box,
+// AppStateOpEnum stands for read/write/create/delete/check-existence,
+// together with key for touched state
+type stateChangeExplain func(ctx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string)
+
+func opPushIntsStackChange(cx *EvalContext) (deletions, additions int) {
+ // NOTE: WE ARE SWALLOWING THE ERROR HERE!
+ // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
+ intc, _, _ := parseIntImmArgs(cx.program, cx.pc+1)
+
+ additions = len(intc)
+ return
+}
+
+func opPushBytessStackChange(cx *EvalContext) (deletions, additions int) {
+ // NOTE: WE ARE SWALLOWING THE ERROR HERE!
+ // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
+ cbytess, _, _ := parseByteImmArgs(cx.program, cx.pc+1)
+
+ additions = len(cbytess)
+ return
+}
+
+func opReturnStackChange(cx *EvalContext) (deletions, additions int) {
+ deletions = len(cx.Stack)
+ additions = 1
+ return
+}
+
+func opBuryStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth
+ return
+}
+
+func opPopNStackChange(cx *EvalContext) (deletions, additions int) {
+ n := int(cx.program[cx.pc+1])
+
+ deletions = n
+ return
+}
+
+func opDupNStackChange(cx *EvalContext) (deletions, additions int) {
+ n := int(cx.program[cx.pc+1])
+
+ deletions = 1
+ additions = n + 1
+ return
+}
+
+func opDigStackChange(cx *EvalContext) (deletions, additions int) {
+ additions = 1
+ return
+}
+
+func opFrameDigStackChange(cx *EvalContext) (deletions, additions int) {
+ additions = 1
+ return
+}
+
+func opCoverStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth + 1
+ return
+}
+
+func opUncoverStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth + 1
+ return
+}
+
+func opRetSubStackChange(cx *EvalContext) (deletions, additions int) {
+ topFrame := cx.callstack[len(cx.callstack)-1]
+ // fast path, no proto case
+ if !topFrame.clear {
+ return
+ }
+
+ argStart := topFrame.height - topFrame.args
+ topStackIdx := len(cx.Stack) - 1
+
+ diff := topStackIdx - argStart + 1
+
+ deletions = diff
+ additions = topFrame.returns
+ return
+}
+
+func opFrameBuryStackChange(cx *EvalContext) (deletions, additions int) {
+ topFrame := cx.callstack[len(cx.callstack)-1]
+
+ immIndex := int8(cx.program[cx.pc+1])
+ idx := topFrame.height + int(immIndex)
+ topStackIdx := len(cx.Stack) - 1
+
+ diff := topStackIdx - idx + 1
+
+ deletions = diff
+ additions = diff - 1
+ return
+}
+
+func opMatchStackChange(cx *EvalContext) (deletions, additions int) {
+ labelNum := int(cx.program[cx.pc+1])
+
+ deletions = labelNum + 1
+ return
+}
+
+func opBoxCreateStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // size
+ prev := last - 1 // name
+
+ return BoxState, AppStateWrite, cx.appID, basics.Address{}, string(cx.Stack[prev].Bytes)
+}
+
+func opBoxReplaceStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // replacement
+ prev := last - 1 // start
+ pprev := prev - 1 // name
+
+ return BoxState, AppStateWrite, cx.appID, basics.Address{}, string(cx.Stack[pprev].Bytes)
+}
+
+func opBoxDelStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // name
+
+ return BoxState, AppStateDelete, cx.appID, basics.Address{}, string(cx.Stack[last].Bytes)
+}
+
+func opBoxPutStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // name
+
+ return BoxState, AppStateWrite, cx.appID, basics.Address{}, string(cx.Stack[last].Bytes)
+}
+
+func opAppLocalPutStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // value
+ prev := last - 1 // state key
+ pprev := prev - 1 // account
+
+ // NOTE: we swallow the error of finding account ref, for eventually it would error in execution time,
+ // and we don't have to complain here.
+ var addr basics.Address
+ addr, _, _ = cx.mutableAccountReference(cx.Stack[pprev])
+
+ return LocalState, AppStateWrite, cx.appID, addr, string(cx.Stack[prev].Bytes)
+}
+
+func opAppGlobalPutStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // value
+ prev := last - 1 // state key
+
+ return GlobalState, AppStateWrite, cx.appID, basics.Address{}, string(cx.Stack[prev].Bytes)
+}
+
+func opAppLocalDelStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // key
+ prev := last - 1 // account
+
+ // NOTE: we swallow the error of finding account ref, for eventually it would error in execution time,
+ // and we don't have to complain here.
+ var addr basics.Address
+ addr, _, _ = cx.mutableAccountReference(cx.Stack[prev])
+
+ return LocalState, AppStateDelete, cx.appID, addr, string(cx.Stack[last].Bytes)
+}
+
+func opAppGlobalDelStateChange(cx *EvalContext) (AppStateEnum, AppStateOpEnum, basics.AppIndex, basics.Address, string) {
+ last := len(cx.Stack) - 1 // key
+
+ return GlobalState, AppStateDelete, cx.appID, basics.Address{}, string(cx.Stack[last].Bytes)
+}
+
+// AppNewStateQuerying is used only for simulation endpoint exec trace export:
+// it reads *new* app state after opcode that writes to app-state.
+// Since it is collecting new/updated app state, we don't have to error again here,
+// and thus we omit the error or non-existence case, just returning empty TealValue.
+// Otherwise, we find the updated new state value, and wrap up with new TealValue.
+func AppNewStateQuerying(
+ cx *EvalContext,
+ appState AppStateEnum, stateOp AppStateOpEnum,
+ appID basics.AppIndex, account basics.Address, key string) basics.TealValue {
+ if stateOp != AppStateWrite {
+ return basics.TealValue{}
+ }
+ switch appState {
+ case BoxState:
+ boxBytes, exists, err := cx.Ledger.GetBox(appID, key)
+ if !exists || err != nil {
+ return basics.TealValue{}
+ }
+ return basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: string(boxBytes),
+ }
+ case GlobalState:
+ globalValue, exists, err := cx.Ledger.GetGlobal(appID, key)
+ if !exists || err != nil {
+ return basics.TealValue{}
+ }
+ return globalValue
+ case LocalState:
+ addr, acctID, err := cx.mutableAccountReference(stackValue{Bytes: account[:]})
+ if err != nil {
+ return basics.TealValue{}
+ }
+ localValue, exists, err := cx.Ledger.GetLocal(addr, appID, key, acctID)
+ if !exists || err != nil {
+ return basics.TealValue{}
+ }
+ return localValue
+ default:
+ return basics.TealValue{}
+ }
+}
diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go
index 0dd9bf8dfa..295b8ed512 100644
--- a/data/transactions/logic/opcodes.go
+++ b/data/transactions/logic/opcodes.go
@@ -356,11 +356,6 @@ type typedList struct {
Effects string
}
-// debugStackExplain explains the effect of an opcode over the stack
-// with 2 integers: deletions and additions, representing pops and inserts.
-// An opcode may delete a few variables from stack, then add a few to stack.
-type debugStackExplain func(*EvalContext) (int, int)
-
// Proto describes the "stack behavior" of an opcode, what it pops as arguments
// and pushes onto the stack as return values.
type Proto struct {
@@ -371,6 +366,11 @@ type Proto struct {
// - on default construction, Explain relies on Arg and Return count.
// - otherwise, we need to explicitly infer from EvalContext, by registering through explain function
Explain debugStackExplain
+
+ // StateExplain is the pointer to the function used for debugging in simulation:
+ // - for an opcode not touching app's local/global/box state, this pointer is nil.
+ // - otherwise, we call this method and check the operation of an opcode on app's state.
+ StateExplain stateChangeExplain
}
func (p Proto) stackExplain(e debugStackExplain) Proto {
@@ -378,6 +378,11 @@ func (p Proto) stackExplain(e debugStackExplain) Proto {
return p
}
+func (p Proto) stateExplain(s stateChangeExplain) Proto {
+ p.StateExplain = s
+ return p
+}
+
func defaultDebugExplain(argCount, retCount int) debugStackExplain {
return func(_ *EvalContext) (deletions, additions int) {
deletions = argCount
@@ -386,117 +391,6 @@ func defaultDebugExplain(argCount, retCount int) debugStackExplain {
}
}
-func opPushIntsStackChange(cx *EvalContext) (deletions, additions int) {
- // NOTE: WE ARE SWALLOWING THE ERROR HERE!
- // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
- intc, _, _ := parseIntImmArgs(cx.program, cx.pc+1)
-
- additions = len(intc)
- return
-}
-
-func opPushBytessStackChange(cx *EvalContext) (deletions, additions int) {
- // NOTE: WE ARE SWALLOWING THE ERROR HERE!
- // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
- cbytess, _, _ := parseByteImmArgs(cx.program, cx.pc+1)
-
- additions = len(cbytess)
- return
-}
-
-func opReturnStackChange(cx *EvalContext) (deletions, additions int) {
- deletions = len(cx.Stack)
- additions = 1
- return
-}
-
-func opBuryStackChange(cx *EvalContext) (deletions, additions int) {
- depth := int(cx.program[cx.pc+1])
-
- deletions = depth + 1
- additions = depth
- return
-}
-
-func opPopNStackChange(cx *EvalContext) (deletions, additions int) {
- n := int(cx.program[cx.pc+1])
-
- deletions = n
- return
-}
-
-func opDupNStackChange(cx *EvalContext) (deletions, additions int) {
- n := int(cx.program[cx.pc+1])
-
- deletions = 1
- additions = n + 1
- return
-}
-
-func opDigStackChange(cx *EvalContext) (deletions, additions int) {
- additions = 1
- return
-}
-
-func opFrameDigStackChange(cx *EvalContext) (deletions, additions int) {
- additions = 1
- return
-}
-
-func opCoverStackChange(cx *EvalContext) (deletions, additions int) {
- depth := int(cx.program[cx.pc+1])
-
- deletions = depth + 1
- additions = depth + 1
- return
-}
-
-func opUncoverStackChange(cx *EvalContext) (deletions, additions int) {
- depth := int(cx.program[cx.pc+1])
-
- deletions = depth + 1
- additions = depth + 1
- return
-}
-
-func opRetSubStackChange(cx *EvalContext) (deletions, additions int) {
- topFrame := cx.callstack[len(cx.callstack)-1]
- // fast path, no proto case
- if !topFrame.clear {
- return
- }
-
- argStart := topFrame.height - topFrame.args
- topStackIdx := len(cx.Stack) - 1
-
- diff := topStackIdx - argStart + 1
-
- deletions = diff
- additions = topFrame.returns
- return
-}
-
-func opFrameBuryStackChange(cx *EvalContext) (deletions, additions int) {
- topFrame := cx.callstack[len(cx.callstack)-1]
-
- immIndex := int8(cx.program[cx.pc+1])
- idx := topFrame.height + int(immIndex)
- topStackIdx := len(cx.Stack) - 1
-
- diff := topStackIdx - idx + 1
-
- deletions = diff
- additions = diff - 1
- return
-}
-
-func opMatchStackChange(cx *EvalContext) (deletions, additions int) {
- labelNum := int(cx.program[cx.pc+1])
-
- deletions = labelNum + 1
- return
-}
-
func proto(signature string, effects ...string) Proto {
parts := strings.Split(signature, ":")
if len(parts) != 2 {
@@ -695,12 +589,12 @@ var OpSpecs = []OpSpec{
{0x63, "app_local_get_ex", opAppLocalGetEx, proto("aib:aT"), directRefEnabledVersion, only(ModeApp)},
{0x64, "app_global_get", opAppGlobalGet, proto("b:a"), 2, only(ModeApp)},
{0x65, "app_global_get_ex", opAppGlobalGetEx, proto("ib:aT"), 2, only(ModeApp)},
- {0x66, "app_local_put", opAppLocalPut, proto("iba:"), 2, only(ModeApp)},
- {0x66, "app_local_put", opAppLocalPut, proto("aba:"), directRefEnabledVersion, only(ModeApp)},
- {0x67, "app_global_put", opAppGlobalPut, proto("ba:"), 2, only(ModeApp)},
- {0x68, "app_local_del", opAppLocalDel, proto("ib:"), 2, only(ModeApp)},
- {0x68, "app_local_del", opAppLocalDel, proto("ab:"), directRefEnabledVersion, only(ModeApp)},
- {0x69, "app_global_del", opAppGlobalDel, proto("b:"), 2, only(ModeApp)},
+ {0x66, "app_local_put", opAppLocalPut, proto("iba:").stateExplain(opAppLocalPutStateChange), 2, only(ModeApp)},
+ {0x66, "app_local_put", opAppLocalPut, proto("aba:").stateExplain(opAppLocalPutStateChange), directRefEnabledVersion, only(ModeApp)},
+ {0x67, "app_global_put", opAppGlobalPut, proto("ba:").stateExplain(opAppGlobalPutStateChange), 2, only(ModeApp)},
+ {0x68, "app_local_del", opAppLocalDel, proto("ib:").stateExplain(opAppLocalDelStateChange), 2, only(ModeApp)},
+ {0x68, "app_local_del", opAppLocalDel, proto("ab:").stateExplain(opAppLocalDelStateChange), directRefEnabledVersion, only(ModeApp)},
+ {0x69, "app_global_del", opAppGlobalDel, proto("b:").stateExplain(opAppGlobalDelStateChange), 2, only(ModeApp)},
{0x70, "asset_holding_get", opAssetHoldingGet, proto("ii:aT"), 2, field("f", &AssetHoldingFields).only(ModeApp)},
{0x70, "asset_holding_get", opAssetHoldingGet, proto("ai:aT"), directRefEnabledVersion, field("f", &AssetHoldingFields).only(ModeApp)},
{0x71, "asset_params_get", opAssetParamsGet, proto("i:aT"), 2, field("f", &AssetParamsFields).only(ModeApp)},
@@ -776,13 +670,13 @@ var OpSpecs = []OpSpec{
{0xb8, "gitxna", opGitxna, proto(":a"), 6, immediates("t", "f", "i").field("f", &TxnArrayFields).only(ModeApp)},
// Unlimited Global Storage - Boxes
- {0xb9, "box_create", opBoxCreate, proto("Ni:T"), boxVersion, only(ModeApp)},
+ {0xb9, "box_create", opBoxCreate, proto("Ni:T").stateExplain(opBoxCreateStateChange), boxVersion, only(ModeApp)},
{0xba, "box_extract", opBoxExtract, proto("Nii:b"), boxVersion, only(ModeApp)},
- {0xbb, "box_replace", opBoxReplace, proto("Nib:"), boxVersion, only(ModeApp)},
- {0xbc, "box_del", opBoxDel, proto("N:T"), boxVersion, only(ModeApp)},
+ {0xbb, "box_replace", opBoxReplace, proto("Nib:").stateExplain(opBoxReplaceStateChange), boxVersion, only(ModeApp)},
+ {0xbc, "box_del", opBoxDel, proto("N:T").stateExplain(opBoxDelStateChange), boxVersion, only(ModeApp)},
{0xbd, "box_len", opBoxLen, proto("N:iT"), boxVersion, only(ModeApp)},
{0xbe, "box_get", opBoxGet, proto("N:bT"), boxVersion, only(ModeApp)},
- {0xbf, "box_put", opBoxPut, proto("Nb:"), boxVersion, only(ModeApp)},
+ {0xbf, "box_put", opBoxPut, proto("Nb:").stateExplain(opBoxPutStateChange), boxVersion, only(ModeApp)},
// Dynamic indexing
{0xc0, "txnas", opTxnas, proto("i:a"), 5, field("f", &TxnArrayFields)},
diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json
index 59dc143681..ddacfaa422 100644
--- a/data/transactions/logic/teal.tmLanguage.json
+++ b/data/transactions/logic/teal.tmLanguage.json
@@ -112,7 +112,7 @@
},
{
"name": "variable.parameter.teal",
- "match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|NumAppArgs|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|NumAssets|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|NumApprovalProgramPages|NumClearStateProgramPages|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|ApplicationArgs|Accounts|Assets|Applications|Logs|ApprovalProgramPages|ClearStateProgramPages|URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr|AcctTotalNumUint|AcctTotalNumByteSlice|AcctTotalExtraAppPages|AcctTotalAppsCreated|AcctTotalAppsOptedIn|AcctTotalAssetsCreated|AcctTotalAssets|AcctTotalBoxes|AcctTotalBoxBytes|VrfAlgorand|BlkSeed|BlkTimestamp)\\b"
+ "match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|NumAppArgs|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|NumAssets|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|NumApprovalProgramPages|NumClearStateProgramPages|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|AssetCreateMinBalance|AssetOptInMinBalance|ApplicationArgs|Accounts|Assets|Applications|Logs|ApprovalProgramPages|ClearStateProgramPages|URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr|AcctTotalNumUint|AcctTotalNumByteSlice|AcctTotalExtraAppPages|AcctTotalAppsCreated|AcctTotalAppsOptedIn|AcctTotalAssetsCreated|AcctTotalAssets|AcctTotalBoxes|AcctTotalBoxBytes|VrfAlgorand|BlkSeed|BlkTimestamp)\\b"
}
]
},
diff --git a/data/txHandler_test.go b/data/txHandler_test.go
index f51290a374..486bd7c0f8 100644
--- a/data/txHandler_test.go
+++ b/data/txHandler_test.go
@@ -2439,7 +2439,7 @@ func TestTxHandlerRestartWithBacklogAndTxPool(t *testing.T) { //nolint:parallelt
data = append(data, protocol.Encode(&stxn)...)
}
encodedSignedTransactionGroups =
- append(encodedSignedTransactionGroups, network.IncomingMessage{Data: data})
+ append(encodedSignedTransactionGroups, network.IncomingMessage{Data: data, Sender: mockSender{}})
}
// start the handler
diff --git a/installer/config.json.example b/installer/config.json.example
index 6df0464f17..094c7ca7df 100644
--- a/installer/config.json.example
+++ b/installer/config.json.example
@@ -55,7 +55,7 @@
"EnableRequestLogger": false,
"EnableRuntimeMetrics": false,
"EnableTopAccountsReporting": false,
- "EnableTxBacklogRateLimiting": false,
+ "EnableTxBacklogRateLimiting": true,
"EnableTxnEvalTracer": false,
"EnableUsageLog": false,
"EnableVerbosedTransactionSyncLogging": false,
diff --git a/ledger/simulation/simulation_eval_test.go b/ledger/simulation/simulation_eval_test.go
index f888d0fad2..747494ea80 100644
--- a/ledger/simulation/simulation_eval_test.go
+++ b/ledger/simulation/simulation_eval_test.go
@@ -1029,6 +1029,9 @@ func TestAppCallWithExtraBudgetReturningPC(t *testing.T) {
ApprovalProgram: expensiveAppSource,
ClearStateProgram: "#pragma version 6\nint 1",
})
+ op, err := logic.AssembleString(createTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ approvalHash := crypto.Hash(op.Program)
// Expensive 700 repetition of int 1 and pop total cost 1404
expensiveTxn := env.TxnInfo.NewTxn(txntest.Txn{
Type: protocol.ApplicationCallTx,
@@ -1084,12 +1087,14 @@ func TestAppCallWithExtraBudgetReturningPC(t *testing.T) {
AppBudgetConsumed: 4,
Trace: &simulation.TransactionTrace{
ApprovalProgramTrace: firstTrace,
+ ApprovalProgramHash: approvalHash,
},
},
{
AppBudgetConsumed: 1404,
Trace: &simulation.TransactionTrace{
ApprovalProgramTrace: secondTrace,
+ ApprovalProgramHash: approvalHash,
},
},
},
@@ -1796,6 +1801,16 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
ClearStateProgram: "#pragma version 8\nint 1",
})
+ op, err := logic.AssembleString(maxDepthTealApproval)
+ require.NoError(t, err)
+ approvalProgramBytes := op.Program
+ approvalDigest := crypto.Hash(approvalProgramBytes)
+
+ op, err = logic.AssembleString("#pragma version 8\nint 1")
+ require.NoError(t, err)
+ clearStateProgramBytes := op.Program
+ clearStateDigest := crypto.Hash(clearStateProgramBytes)
+
MaxDepth := 2
MinBalance := env.TxnInfo.CurrentProtocolParams().MinBalance
MinFee := env.TxnInfo.CurrentProtocolParams().MinTxnFee
@@ -2024,6 +2039,7 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
AppBudgetConsumed: 7,
Trace: &simulation.TransactionTrace{
ApprovalProgramTrace: creationOpcodeTrace,
+ ApprovalProgramHash: approvalDigest,
},
},
{
@@ -2071,32 +2087,41 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
AppBudgetConsumed: 378,
Trace: &simulation.TransactionTrace{
ApprovalProgramTrace: recursiveLongOpcodeTrace,
+ ApprovalProgramHash: approvalDigest,
InnerTraces: []simulation.TransactionTrace{
{
ApprovalProgramTrace: creationOpcodeTrace,
+ ApprovalProgramHash: approvalDigest,
},
{},
{
ApprovalProgramTrace: optInTrace,
+ ApprovalProgramHash: approvalDigest,
},
{
ClearStateProgramTrace: clearStateOpcodeTrace,
+ ClearStateProgramHash: clearStateDigest,
},
{
ApprovalProgramTrace: recursiveLongOpcodeTrace,
+ ApprovalProgramHash: approvalDigest,
InnerTraces: []simulation.TransactionTrace{
{
ApprovalProgramTrace: creationOpcodeTrace,
+ ApprovalProgramHash: approvalDigest,
},
{},
{
ApprovalProgramTrace: optInTrace,
+ ApprovalProgramHash: approvalDigest,
},
{
ClearStateProgramTrace: clearStateOpcodeTrace,
+ ClearStateProgramHash: clearStateDigest,
},
{
ApprovalProgramTrace: finalDepthTrace,
+ ApprovalProgramHash: approvalDigest,
},
},
},
@@ -2177,6 +2202,7 @@ func TestLogicSigPCandStackExposure(t *testing.T) {
`, 2) + `int 1`)
require.NoError(t, err)
program := logic.Program(op.Program)
+ logicHash := crypto.Hash(program)
lsigAddr := basics.Address(crypto.HashObj(&program))
simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
@@ -2196,6 +2222,10 @@ byte "hello"; log; int 1`,
ClearStateProgram: "#pragma version 8\n int 1",
})
+ op, err = logic.AssembleString(appCallTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ approvalHash := crypto.Hash(op.Program)
+
txntest.Group(&payTxn, &appCallTxn)
signedPayTxn := payTxn.Txn().Sign(sender.Sk)
@@ -2252,6 +2282,7 @@ byte "hello"; log; int 1`,
StackAdded: goValuesToTealValues(1),
},
},
+ ApprovalProgramHash: approvalHash,
LogicSigTrace: []simulation.OpcodeTraceUnit{
{
PC: 1,
@@ -2287,6 +2318,7 @@ byte "hello"; log; int 1`,
StackAdded: goValuesToTealValues(1),
},
},
+ LogicSigHash: logicHash,
},
},
},
@@ -2307,8 +2339,9 @@ func TestFailingLogicSigPCandStack(t *testing.T) {
` + strings.Repeat(`byte "a"; keccak256; pop
`, 2) + `int 0; int 1; -`)
require.NoError(t, err)
- program := logic.Program(op.Program)
- lsigAddr := basics.Address(crypto.HashObj(&program))
+ logicSigProg := logic.Program(op.Program)
+ logicSigHash := crypto.Hash(logicSigProg)
+ lsigAddr := basics.Address(crypto.HashObj(&logicSigProg))
simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
sender := env.Accounts[0]
@@ -2331,7 +2364,7 @@ byte "hello"; log; int 1`,
signedPayTxn := payTxn.Txn().Sign(sender.Sk)
signedAppCallTxn := appCallTxn.SignedTxn()
- signedAppCallTxn.Lsig = transactions.LogicSig{Logic: program}
+ signedAppCallTxn.Lsig = transactions.LogicSig{Logic: logicSigProg}
keccakBytes := ":\xc2%\x16\x8d\xf5B\x12\xa2\\\x1c\x01\xfd5\xbe\xbf\xea@\x8f\xda\xc2\xe3\x1d\xddo\x80\xa4\xbb\xf9\xa5\xf1\xcb"
@@ -2408,6 +2441,7 @@ byte "hello"; log; int 1`,
StackPopCount: 2,
},
},
+ LogicSigHash: logicSigHash,
},
},
},
@@ -2426,8 +2460,9 @@ func TestFailingApp(t *testing.T) {
` + strings.Repeat(`byte "a"; keccak256; pop
`, 2) + `int 1`)
require.NoError(t, err)
- program := logic.Program(op.Program)
- lsigAddr := basics.Address(crypto.HashObj(&program))
+ logicSigProg := logic.Program(op.Program)
+ logicSigHash := crypto.Hash(logicSigProg)
+ lsigAddr := basics.Address(crypto.HashObj(&logicSigProg))
simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
sender := env.Accounts[0]
@@ -2446,11 +2481,15 @@ byte "hello"; log; int 0`,
ClearStateProgram: "#pragma version 8\n int 1",
})
+ approvalOp, err := logic.AssembleString(appCallTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ approvalHash := crypto.Hash(approvalOp.Program)
+
txntest.Group(&payTxn, &appCallTxn)
signedPayTxn := payTxn.Txn().Sign(sender.Sk)
signedAppCallTxn := appCallTxn.SignedTxn()
- signedAppCallTxn.Lsig = transactions.LogicSig{Logic: program}
+ signedAppCallTxn.Lsig = transactions.LogicSig{Logic: logicSigProg}
return simulationTestCase{
input: simulation.Request{
@@ -2491,6 +2530,7 @@ byte "hello"; log; int 0`,
{PC: 8},
{PC: 9},
},
+ ApprovalProgramHash: approvalHash,
LogicSigTrace: []simulation.OpcodeTraceUnit{
{PC: 1},
{PC: 5},
@@ -2501,6 +2541,7 @@ byte "hello"; log; int 0`,
{PC: 10},
{PC: 11},
},
+ LogicSigHash: logicSigHash,
},
},
},
@@ -2564,6 +2605,10 @@ func TestFrameBuryDigStackTrace(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
+ op, err := logic.AssembleString(FrameBuryDigProgram)
+ require.NoError(t, err)
+ hash := crypto.Hash(op.Program)
+
simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
sender := env.Accounts[0]
@@ -2650,6 +2695,7 @@ int 1`,
StackPopCount: 1,
},
},
+ ApprovalProgramHash: hash,
},
},
{
@@ -2886,6 +2932,7 @@ int 1`,
StackPopCount: 1,
},
},
+ ApprovalProgramHash: hash,
},
},
},
@@ -2898,6 +2945,1419 @@ int 1`,
})
}
+func TestBoxChangeExecTrace(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
+ sender := env.Accounts[0]
+
+ futureAppID := basics.AppIndex(1001)
+ boxContent := []byte("boxWriteContent")
+
+ boxStateChangeTraceTemplate := func(opName string, units ...simulation.OpcodeTraceUnit) []simulation.OpcodeTraceUnit {
+ begin := []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 3,
+ StackPopCount: 1,
+ },
+ {
+ PC: 6,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "create",
+ },
+ },
+ },
+ {
+ PC: 14,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "delete",
+ },
+ },
+ },
+ {
+ PC: 22,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "read",
+ },
+ },
+ },
+ {
+ PC: 28,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "write",
+ },
+ },
+ },
+ {
+ PC: 35,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: opName,
+ },
+ },
+ },
+ {
+ PC: 38,
+ StackPopCount: 5,
+ },
+ }
+ end := []simulation.OpcodeTraceUnit{
+ {
+ PC: 87,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ }
+ result := append(begin, units...)
+ result = append(result, end...)
+ return result
+ }
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ ApprovalProgram: fmt.Sprintf(boxTestProgram, 8),
+ ClearStateProgram: `#pragma version 8
+int 1`,
+ })
+
+ op, err := logic.AssembleString(createTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ progHash := crypto.Hash(op.Program)
+
+ payment := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.PaymentTx,
+ Sender: sender.Addr,
+ Receiver: futureAppID.Address(),
+ Amount: env.TxnInfo.CurrentProtocolParams().MinBalance * 2,
+ })
+ createBoxTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: boxOperation{
+ op: logic.BoxCreateOperation,
+ name: "A",
+ createSize: uint64(len(boxContent)),
+ }.appArgs(),
+ Boxes: []transactions.BoxRef{
+ {Name: []byte("A")},
+ },
+ })
+ writeBoxTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: boxOperation{
+ op: logic.BoxWriteOperation,
+ name: "A",
+ contents: boxContent,
+ }.appArgs(),
+ Boxes: []transactions.BoxRef{
+ {Name: []byte("A")},
+ },
+ })
+ delBoxTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: boxOperation{
+ op: logic.BoxDeleteOperation,
+ name: "A",
+ }.appArgs(),
+ Boxes: []transactions.BoxRef{
+ {Name: []byte("A")},
+ },
+ })
+ txntest.Group(&createTxn, &payment, &createBoxTxn, &writeBoxTxn, &delBoxTxn)
+
+ signedCreate := createTxn.Txn().Sign(sender.Sk)
+ signedPay := payment.Txn().Sign(sender.Sk)
+ signedCreateBox := createBoxTxn.Txn().Sign(sender.Sk)
+ signedWriteBox := writeBoxTxn.Txn().Sign(sender.Sk)
+ signedDelBox := delBoxTxn.Txn().Sign(sender.Sk)
+
+ return simulationTestCase{
+ input: simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreate, signedPay, signedCreateBox, signedWriteBox, signedDelBox},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ },
+ developerAPI: true,
+ expected: simulation.Result{
+ Version: simulation.ResultLatestVersion,
+ LastRound: env.TxnInfo.LatestRound(),
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ TxnGroups: []simulation.TxnGroupResult{
+ {
+ Txns: []simulation.TxnResult{
+ // App creation
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ ApplicationID: futureAppID,
+ },
+ },
+ AppBudgetConsumed: 3,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 3,
+ StackPopCount: 1,
+ },
+ {
+ PC: 87,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Payment
+ {
+ Trace: &simulation.TransactionTrace{},
+ },
+ // BoxCreation
+ {
+ AppBudgetConsumed: 15,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: boxStateChangeTraceTemplate("create",
+ simulation.OpcodeTraceUnit{
+ PC: 49,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "A",
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 52,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: string(uint64ToBytes(uint64(len(boxContent)))),
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 55,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(len(boxContent)),
+ },
+ },
+ StackPopCount: 1,
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 56,
+ StackPopCount: 2,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.BoxState,
+ AppID: futureAppID,
+ Key: "A",
+ NewValue: basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: string(make([]byte, len(boxContent))),
+ },
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 57,
+ StackPopCount: 1,
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 58,
+ },
+ ),
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // BoxWrite
+ {
+ AppBudgetConsumed: 13,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: boxStateChangeTraceTemplate("write",
+ simulation.OpcodeTraceUnit{
+ PC: 78,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "A",
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 81,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 83,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: string(boxContent),
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 86,
+ StackPopCount: 3,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.BoxState,
+ AppID: futureAppID,
+ Key: "A",
+ NewValue: basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: string(boxContent),
+ },
+ },
+ },
+ },
+ ),
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // BoxDelete
+ {
+ AppBudgetConsumed: 13,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: boxStateChangeTraceTemplate("delete",
+ simulation.OpcodeTraceUnit{
+ PC: 61,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "A",
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 64,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ StackPopCount: 1,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateDelete,
+ AppState: logic.BoxState,
+ AppID: futureAppID,
+ Key: "A",
+ },
+ },
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 65,
+ StackPopCount: 1,
+ },
+ simulation.OpcodeTraceUnit{
+ PC: 66,
+ },
+ ),
+ ApprovalProgramHash: progHash,
+ },
+ },
+ },
+ AppBudgetAdded: 2800,
+ AppBudgetConsumed: 44,
+ },
+ },
+ },
+ }
+ })
+}
+
+func TestAppLocalGlobalStateChange(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
+ sender := env.Accounts[0]
+
+ futureAppID := basics.AppIndex(1001)
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ GlobalStateSchema: basics.StateSchema{NumUint: 1, NumByteSlice: 1},
+ LocalStateSchema: basics.StateSchema{NumUint: 1, NumByteSlice: 1},
+ ApprovalProgram: `#pragma version 8
+txn ApplicationID
+bz end // Do nothing during create
+
+txn OnCompletion
+int OptIn
+==
+bnz end // Always allow optin
+
+byte "local"
+byte "global"
+txn ApplicationArgs 0
+match local global
+err // Unknown command
+
+local:
+ txn Sender
+ byte "local-int-key"
+ int 0xcafeb0ba
+ app_local_put
+ int 0
+ byte "local-bytes-key"
+ byte "xqcL"
+ app_local_put
+ b end
+
+global:
+ byte "global-int-key"
+ int 0xdeadbeef
+ app_global_put
+ byte "global-bytes-key"
+ byte "welt am draht"
+ app_global_put
+ b end
+
+end:
+ int 1
+`,
+ ClearStateProgram: `#pragma version 8
+int 1`,
+ })
+
+ op, err := logic.AssembleString(createTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ progHash := crypto.Hash(op.Program)
+
+ optIn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ OnCompletion: transactions.OptInOC,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ })
+
+ globalStateCall := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: [][]byte{[]byte("global")},
+ })
+
+ localStateCall := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: [][]byte{[]byte("local")},
+ })
+
+ txntest.Group(&createTxn, &optIn, &globalStateCall, &localStateCall)
+
+ signedCreate := createTxn.Txn().Sign(sender.Sk)
+ signedOptin := optIn.Txn().Sign(sender.Sk)
+ signedGlobalStateCall := globalStateCall.Txn().Sign(sender.Sk)
+ signedLocalStateCall := localStateCall.Txn().Sign(sender.Sk)
+
+ return simulationTestCase{
+ input: simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreate, signedOptin, signedGlobalStateCall, signedLocalStateCall},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ },
+ developerAPI: true,
+ expected: simulation.Result{
+ Version: simulation.ResultLatestVersion,
+ LastRound: env.TxnInfo.LatestRound(),
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ TxnGroups: []simulation.TxnGroupResult{
+ {
+ Txns: []simulation.TxnResult{
+ // App creation
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ ApplicationID: futureAppID,
+ },
+ },
+ AppBudgetConsumed: 4,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 154,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Optin
+ {
+ AppBudgetConsumed: 8,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 9,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ {
+ PC: 11,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ {
+ PC: 12,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ StackPopCount: 2,
+ },
+ {
+ PC: 13,
+ StackPopCount: 1,
+ },
+ {
+ PC: 154,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Global
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ EvalDelta: transactions.EvalDelta{
+ GlobalDelta: basics.StateDelta{
+ "global-bytes-key": basics.ValueDelta{
+ Bytes: "welt am draht",
+ Action: basics.SetBytesAction,
+ },
+ "global-int-key": basics.ValueDelta{
+ Uint: 0xdeadbeef,
+ Action: basics.SetUintAction,
+ },
+ },
+ },
+ },
+ },
+ AppBudgetConsumed: 19,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 9,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 11,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ {
+ PC: 12,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ StackPopCount: 2,
+ },
+ {
+ PC: 13,
+ StackPopCount: 1,
+ },
+ {
+ PC: 16,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "local",
+ },
+ },
+ },
+ {
+ PC: 23,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global",
+ },
+ },
+ },
+ {
+ PC: 31,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global",
+ },
+ },
+ },
+ {
+ PC: 34,
+ StackPopCount: 3,
+ },
+ {
+ PC: 94,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global-int-key",
+ },
+ },
+ },
+ {
+ PC: 110,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 0xdeadbeef,
+ },
+ },
+ },
+ {
+ PC: 116,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.GlobalState,
+ AppID: futureAppID,
+ Key: "global-int-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: 0xdeadbeef,
+ },
+ },
+ },
+ StackPopCount: 2,
+ },
+ {
+ PC: 117,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global-bytes-key",
+ },
+ },
+ },
+ {
+ PC: 135,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "welt am draht",
+ },
+ },
+ },
+ {
+ PC: 150,
+ StackPopCount: 2,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.GlobalState,
+ AppID: futureAppID,
+ Key: "global-bytes-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: "welt am draht",
+ },
+ },
+ },
+ },
+ {PC: 151},
+ {
+ PC: 154,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Local
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ EvalDelta: transactions.EvalDelta{
+ LocalDeltas: map[uint64]basics.StateDelta{
+ 0: {
+ "local-bytes-key": basics.ValueDelta{
+ Bytes: "xqcL",
+ Action: basics.SetBytesAction,
+ },
+ "local-int-key": basics.ValueDelta{
+ Uint: 0xcafeb0ba,
+ Action: basics.SetUintAction,
+ },
+ },
+ },
+ },
+ },
+ },
+ AppBudgetConsumed: 21,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 9,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 11,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ {
+ PC: 12,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ StackPopCount: 2,
+ },
+ {
+ PC: 13,
+ StackPopCount: 1,
+ },
+ {
+ PC: 16,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "local",
+ },
+ },
+ },
+ {
+ PC: 23,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global",
+ },
+ },
+ },
+ {
+ PC: 31,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "local",
+ },
+ },
+ },
+ {
+ PC: 34,
+ StackPopCount: 3,
+ },
+ {
+ PC: 41,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: string(sender.Addr[:]),
+ },
+ },
+ },
+ {
+ PC: 43,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "local-int-key",
+ },
+ },
+ },
+ {
+ PC: 58,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 0xcafeb0ba,
+ },
+ },
+ },
+ {
+ PC: 64,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.LocalState,
+ AppID: futureAppID,
+ Key: "local-int-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: 0xcafeb0ba,
+ },
+ Account: sender.Addr,
+ },
+ },
+ StackPopCount: 3,
+ },
+ {
+ PC: 65,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 67,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "local-bytes-key",
+ },
+ },
+ },
+ {
+ PC: 84,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "xqcL",
+ },
+ },
+ },
+ {
+ PC: 90,
+ StackPopCount: 3,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.LocalState,
+ AppID: futureAppID,
+ Key: "local-bytes-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: "xqcL",
+ },
+ Account: sender.Addr,
+ },
+ },
+ },
+ {PC: 91},
+ {
+ PC: 154,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ },
+ AppBudgetAdded: 2800,
+ AppBudgetConsumed: 52,
+ },
+ },
+ },
+ }
+ })
+}
+
+func TestGlobalStateTypeChange(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
+ sender := env.Accounts[0]
+
+ futureAppID := basics.AppIndex(1001)
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ GlobalStateSchema: basics.StateSchema{NumUint: 1, NumByteSlice: 1},
+ ApprovalProgram: `#pragma version 8
+txn ApplicationID
+bz end // Do nothing during create
+
+byte "global-key"
+int 0xdecaf
+app_global_put
+byte "global-key"
+byte "welt am draht"
+app_global_put
+
+end:
+ int 1
+`,
+ ClearStateProgram: `#pragma version 8
+int 1`,
+ })
+
+ op, err := logic.AssembleString(createTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ progHash := crypto.Hash(op.Program)
+
+ globalStateCall := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ })
+
+ txntest.Group(&createTxn, &globalStateCall)
+
+ signedCreate := createTxn.Txn().Sign(sender.Sk)
+ signedGlobalStateCall := globalStateCall.Txn().Sign(sender.Sk)
+
+ return simulationTestCase{
+ input: simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreate, signedGlobalStateCall},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ },
+ developerAPI: true,
+ expected: simulation.Result{
+ Version: simulation.ResultLatestVersion,
+ LastRound: env.TxnInfo.LatestRound(),
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ TxnGroups: []simulation.TxnGroupResult{
+ {
+ Txns: []simulation.TxnResult{
+ // App creation
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ ApplicationID: futureAppID,
+ },
+ },
+ AppBudgetConsumed: 4,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 14,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 16,
+ StackPopCount: 1,
+ },
+ {
+ PC: 42,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Global
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ EvalDelta: transactions.EvalDelta{
+ GlobalDelta: basics.StateDelta{
+ "global-key": basics.ValueDelta{
+ Bytes: "welt am draht",
+ Action: basics.SetBytesAction,
+ },
+ },
+ },
+ },
+ },
+ AppBudgetConsumed: 10,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 14,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 16,
+ StackPopCount: 1,
+ },
+ {
+ PC: 19,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global-key",
+ },
+ },
+ },
+ {
+ PC: 20,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 0xdecaf,
+ },
+ },
+ },
+ {
+ PC: 24,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.GlobalState,
+ AppID: futureAppID,
+ Key: "global-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: 0xdecaf,
+ },
+ },
+ },
+ StackPopCount: 2,
+ },
+ {
+ PC: 25,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global-key",
+ },
+ },
+ },
+ {
+ PC: 26,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "welt am draht",
+ },
+ },
+ },
+ {
+ PC: 41,
+ StackPopCount: 2,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.GlobalState,
+ AppID: futureAppID,
+ Key: "global-key",
+ NewValue: basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: "welt am draht",
+ },
+ },
+ },
+ },
+ {
+ PC: 42,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ },
+ AppBudgetAdded: 1400,
+ AppBudgetConsumed: 14,
+ },
+ },
+ },
+ }
+ })
+}
+
+func TestGlobalStateTypeChangeFailure(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
+ sender := env.Accounts[0]
+
+ futureAppID := basics.AppIndex(1001)
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ GlobalStateSchema: basics.StateSchema{NumUint: 1},
+ ApprovalProgram: `#pragma version 8
+txn ApplicationID
+bz end // Do nothing during create
+
+byte "global-key"
+byte "I pretend myself as an uint"
+app_global_put
+
+end:
+ int 1
+`,
+ ClearStateProgram: `#pragma version 8
+int 1`,
+ })
+
+ op, err := logic.AssembleString(createTxn.ApprovalProgram.(string))
+ require.NoError(t, err)
+ progHash := crypto.Hash(op.Program)
+
+ globalStateCall := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ })
+
+ txntest.Group(&createTxn, &globalStateCall)
+
+ signedCreate := createTxn.Txn().Sign(sender.Sk)
+ signedGlobalStateCall := globalStateCall.Txn().Sign(sender.Sk)
+
+ return simulationTestCase{
+ input: simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreate, signedGlobalStateCall},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ },
+ developerAPI: true,
+ expectedError: "store bytes count 1 exceeds schema bytes count 0.",
+ expected: simulation.Result{
+ Version: simulation.ResultLatestVersion,
+ LastRound: env.TxnInfo.LatestRound(),
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ State: true,
+ },
+ TxnGroups: []simulation.TxnGroupResult{
+ {
+ FailedAt: simulation.TxnPath{1},
+ Txns: []simulation.TxnResult{
+ // App creation
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ ApplicationID: futureAppID,
+ },
+ },
+ AppBudgetConsumed: 3,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ },
+ },
+ },
+ {
+ PC: 3,
+ StackPopCount: 1,
+ },
+ {
+ PC: 48,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: 1,
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ // Global
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ EvalDelta: transactions.EvalDelta{
+ GlobalDelta: basics.StateDelta{
+ "global-key": basics.ValueDelta{
+ Bytes: "I pretend myself as an uint",
+ Action: basics.SetBytesAction,
+ },
+ },
+ },
+ },
+ },
+ AppBudgetConsumed: 5,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealUintType,
+ Uint: uint64(futureAppID),
+ },
+ },
+ },
+ {
+ PC: 3,
+ StackPopCount: 1,
+ },
+ {
+ PC: 6,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "global-key",
+ },
+ },
+ },
+ {
+ PC: 18,
+ StackAdded: []basics.TealValue{
+ {
+ Type: basics.TealBytesType,
+ Bytes: "I pretend myself as an uint",
+ },
+ },
+ },
+ {
+ PC: 47,
+ StackPopCount: 2,
+ StateChanges: []simulation.StateOperation{
+ {
+ AppStateOp: logic.AppStateWrite,
+ AppState: logic.GlobalState,
+ AppID: futureAppID,
+ Key: "global-key",
+ },
+ },
+ },
+ },
+ ApprovalProgramHash: progHash,
+ },
+ },
+ },
+ AppBudgetAdded: 1400,
+ AppBudgetConsumed: 8,
+ },
+ },
+ },
+ }
+ })
+}
+
// TestBalanceChangesWithApp sends a payment transaction to a new account and confirms its balance
// within a subsequent app call
func TestBalanceChangesWithApp(t *testing.T) {
diff --git a/ledger/simulation/trace.go b/ledger/simulation/trace.go
index ab3ba732fa..7861292830 100644
--- a/ledger/simulation/trace.go
+++ b/ledger/simulation/trace.go
@@ -20,6 +20,7 @@ import (
"fmt"
"github.com/algorand/go-algorand/config"
+ "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
@@ -129,6 +130,7 @@ type ExecTraceConfig struct {
Enable bool `codec:"enable"`
Stack bool `codec:"stack-change"`
Scratch bool `codec:"scratch-change"`
+ State bool `codec:"state-change"`
}
// Result contains the result from a call to Simulator.Simulate
@@ -152,6 +154,9 @@ func (r Result) ReturnStackChange() bool { return r.TraceConfig.Stack }
// ReturnScratchChange tells if the simulation runs with scratch-change enabled.
func (r Result) ReturnScratchChange() bool { return r.TraceConfig.Scratch }
+// ReturnStateChange tells if the simulation runs with state-change enabled.
+func (r Result) ReturnStateChange() bool { return r.TraceConfig.State }
+
// validateSimulateRequest first checks relation between request and config variables, including developerAPI:
// if `developerAPI` provided is turned off, this method would:
// - error on asking for exec trace
@@ -178,6 +183,13 @@ func validateSimulateRequest(request Request, developerAPI bool) error {
},
}
}
+ if request.TraceConfig.State {
+ return InvalidRequestError{
+ SimulatorError{
+ err: fmt.Errorf("basic trace must be enabled when enabling app state change tracing"),
+ },
+ }
+ }
}
return nil
}
@@ -217,6 +229,29 @@ type ScratchChange struct {
NewValue basics.TealValue
}
+// StateOperation represents an operation into an app local/global/box state
+type StateOperation struct {
+ // AppStateOp is one of logic.AppStateOpEnum, standing for either write or delete.
+ AppStateOp logic.AppStateOpEnum
+
+ // AppState is one of logic.AppStateEnum, standing for one of global/local/box.
+ AppState logic.AppStateEnum
+
+ // AppID is the current app's ID.
+ AppID basics.AppIndex
+
+ // Key is the app state kv-pair's key, directly casting byte slice to string.
+ Key string
+
+ // NewValue is the value write to the app's state.
+ // NOTE: if the current app state operation is del, then this value is basics.TealValue{}.
+ NewValue basics.TealValue
+
+ // Account is the account associated to the local state an app writes to.
+ // NOTE: if the current app state is not local, then this value is basics.Address{}.
+ Account basics.Address
+}
+
// OpcodeTraceUnit contains the trace effects of a single opcode evaluation.
type OpcodeTraceUnit struct {
// The PC of the opcode being evaluated
@@ -235,16 +270,25 @@ type OpcodeTraceUnit struct {
// ScratchSlotChanges stands for write operations into scratch slots
ScratchSlotChanges []ScratchChange
+
+ // StateChanges stands for the creation/reading/writing/deletion operations to app's state
+ StateChanges []StateOperation
}
// TransactionTrace contains the trace effects of a single transaction evaluation (including its inners)
type TransactionTrace struct {
// ApprovalProgramTrace stands for a slice of OpcodeTraceUnit over application call on approval program
ApprovalProgramTrace []OpcodeTraceUnit
+ // ApprovalProgramHash stands for the hash digest of approval program bytecode executed during simulation
+ ApprovalProgramHash crypto.Digest
// ClearStateProgramTrace stands for a slice of OpcodeTraceUnit over application call on clear-state program
ClearStateProgramTrace []OpcodeTraceUnit
+ // ClearStateProgramHash stands for the hash digest of clear state program bytecode executed during simulation
+ ClearStateProgramHash crypto.Digest
// LogicSigTrace contains the trace for a logicsig evaluation, if the transaction is approved by a logicsig.
LogicSigTrace []OpcodeTraceUnit
+ // LogicSigHash stands for the hash digest of logic sig bytecode executed during simulation
+ LogicSigHash crypto.Digest
// programTraceRef points to one of ApprovalProgramTrace, ClearStateProgramTrace, and LogicSigTrace during simulation.
programTraceRef *[]OpcodeTraceUnit
// InnerTraces contains the traces for inner transactions, if this transaction spawned any. This
diff --git a/ledger/simulation/tracer.go b/ledger/simulation/tracer.go
index 22406fed1e..0d5f2eb5c1 100644
--- a/ledger/simulation/tracer.go
+++ b/ledger/simulation/tracer.go
@@ -19,6 +19,7 @@ package simulation
import (
"fmt"
+ "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
@@ -306,6 +307,9 @@ func (tracer *evalTracer) BeforeOpcode(cx *logic.EvalContext) {
if tracer.result.ReturnScratchChange() {
tracer.recordChangedScratchSlots(cx)
}
+ if tracer.result.ReturnStateChange() {
+ latestOpcodeTraceUnit.appendStateOperations(cx)
+ }
}
}
@@ -320,6 +324,20 @@ func (o *OpcodeTraceUnit) appendAddedStackValue(cx *logic.EvalContext, tracer *e
}
}
+func (o *OpcodeTraceUnit) appendStateOperations(cx *logic.EvalContext) {
+ if cx.GetOpSpec().StateExplain == nil {
+ return
+ }
+ appState, stateOp, appID, acctAddr, stateKey := cx.GetOpSpec().StateExplain(cx)
+ o.StateChanges = append(o.StateChanges, StateOperation{
+ AppStateOp: stateOp,
+ AppState: appState,
+ AppID: appID,
+ Key: stateKey,
+ Account: acctAddr,
+ })
+}
+
func (tracer *evalTracer) recordChangedScratchSlots(cx *logic.EvalContext) {
currentOpcodeName := cx.GetOpSpec().Name
last := len(cx.Stack) - 1
@@ -356,11 +374,18 @@ func (tracer *evalTracer) recordUpdatedScratchVars(cx *logic.EvalContext) []Scra
return changes
}
+func (o *OpcodeTraceUnit) updateNewStateValues(cx *logic.EvalContext) {
+ for i, sc := range o.StateChanges {
+ o.StateChanges[i].NewValue = logic.AppNewStateQuerying(
+ cx, sc.AppState, sc.AppStateOp, sc.AppID, sc.Account, sc.Key)
+ }
+}
+
func (tracer *evalTracer) AfterOpcode(cx *logic.EvalContext, evalError error) {
groupIndex := cx.GroupIndex()
// NOTE: only when we have no evalError on current opcode,
- // we can proceed for recording stack chaange
+ // we can proceed for recording stack change
if evalError == nil && tracer.result.ReturnTrace() {
var txnTrace *TransactionTrace
if cx.RunMode() == logic.ModeSig {
@@ -376,6 +401,9 @@ func (tracer *evalTracer) AfterOpcode(cx *logic.EvalContext, evalError error) {
if tracer.result.ReturnScratchChange() {
latestOpcodeTraceUnit.ScratchSlotChanges = tracer.recordUpdatedScratchVars(cx)
}
+ if tracer.result.ReturnStateChange() {
+ latestOpcodeTraceUnit.updateNewStateValues(cx)
+ }
}
if cx.RunMode() == logic.ModeApp {
@@ -396,33 +424,48 @@ func (tracer *evalTracer) AfterOpcode(cx *logic.EvalContext, evalError error) {
func (tracer *evalTracer) BeforeProgram(cx *logic.EvalContext) {
groupIndex := cx.GroupIndex()
- // Before Program, activated for logic sig, happens before txn group execution
- // we should create trace object for this txn result
- if cx.RunMode() == logic.ModeSig {
+ switch cx.RunMode() {
+ case logic.ModeSig:
+ // Before Program, activated for logic sig, happens before txn group execution
+ // we should create trace object for this txn result
if tracer.result.ReturnTrace() {
tracer.result.TxnGroups[0].Txns[groupIndex].Trace = &TransactionTrace{}
traceRef := tracer.result.TxnGroups[0].Txns[groupIndex].Trace
traceRef.programTraceRef = &traceRef.LogicSigTrace
+ traceRef.LogicSigHash = crypto.Hash(cx.GetProgram())
}
- }
+ case logic.ModeApp:
+ if tracer.result.ReturnTrace() {
+ txnTraceStackElem := tracer.execTraceStack[len(tracer.execTraceStack)-1]
+ currentTxn := cx.EvalParams.TxnGroup[groupIndex]
+ programHash := crypto.Hash(cx.GetProgram())
- if cx.RunMode() == logic.ModeApp && tracer.unnamedResourcePolicy != nil {
- globalSharing := false
- for iter := cx; iter != nil; iter = iter.GetCaller() {
- if iter.ProgramVersion() >= 9 {
- // If some caller in the app callstack allows global sharing, global resources can
- // be accessed here. Otherwise the top-level txn must declare all resources locally.
- globalSharing = true
- break
+ switch currentTxn.Txn.ApplicationCallTxnFields.OnCompletion {
+ case transactions.ClearStateOC:
+ txnTraceStackElem.ClearStateProgramHash = programHash
+ default:
+ txnTraceStackElem.ApprovalProgramHash = programHash
}
}
- tracer.unnamedResourcePolicy.globalSharing = globalSharing
- tracer.unnamedResourcePolicy.programVersion = cx.ProgramVersion()
- if tracer.unnamedResourcePolicy.initialBoxSurplusReadBudget == nil {
- s := cx.SurplusReadBudget
- tracer.unnamedResourcePolicy.initialBoxSurplusReadBudget = &s
+
+ if tracer.unnamedResourcePolicy != nil {
+ globalSharing := false
+ for iter := cx; iter != nil; iter = iter.GetCaller() {
+ if iter.ProgramVersion() >= 9 {
+ // If some caller in the app callstack allows global sharing, global resources can
+ // be accessed here. Otherwise the top-level txn must declare all resources locally.
+ globalSharing = true
+ break
+ }
+ }
+ tracer.unnamedResourcePolicy.globalSharing = globalSharing
+ tracer.unnamedResourcePolicy.programVersion = cx.ProgramVersion()
+ if tracer.unnamedResourcePolicy.initialBoxSurplusReadBudget == nil {
+ s := cx.SurplusReadBudget
+ tracer.unnamedResourcePolicy.initialBoxSurplusReadBudget = &s
+ }
+ cx.SetIOBudget(tracer.unnamedResourcePolicy.tracker.maxPossibleBoxIOBudget(cx.Proto.BytesPerBoxReference))
}
- cx.SetIOBudget(tracer.unnamedResourcePolicy.tracker.maxPossibleBoxIOBudget(cx.Proto.BytesPerBoxReference))
}
}
diff --git a/ledger/store/trackerdb/pebbledbdriver/pebbledriver.go b/ledger/store/trackerdb/pebbledbdriver/pebbledriver.go
index ebef106db2..514dc0ee58 100644
--- a/ledger/store/trackerdb/pebbledbdriver/pebbledriver.go
+++ b/ledger/store/trackerdb/pebbledbdriver/pebbledriver.go
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand. If not, see .
+//go:build !arm
+
package pebbledbdriver
import (
diff --git a/ledger/store/trackerdb/pebbledbdriver/pebbledriver_arm.go b/ledger/store/trackerdb/pebbledbdriver/pebbledriver_arm.go
new file mode 100644
index 0000000000..cd17555aea
--- /dev/null
+++ b/ledger/store/trackerdb/pebbledbdriver/pebbledriver_arm.go
@@ -0,0 +1,30 @@
+// Copyright (C) 2019-2023 Algorand, Inc.
+// This file is part of go-algorand
+//
+// go-algorand is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// go-algorand is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with go-algorand. If not, see .
+
+// go:build arm
+package pebbledbdriver
+
+import (
+ "errors"
+
+ "github.com/algorand/go-algorand/config"
+ "github.com/algorand/go-algorand/ledger/store/trackerdb"
+ "github.com/algorand/go-algorand/logging"
+)
+
+func Open(dbdir string, inMem bool, proto config.ConsensusParams, log logging.Logger) (trackerdb.Store, error) {
+ return nil, errors.New("pebbledb storage backend not supported on arm32")
+}
diff --git a/ledger/tracker_test.go b/ledger/tracker_test.go
index 87646f24a6..709d123d9e 100644
--- a/ledger/tracker_test.go
+++ b/ledger/tracker_test.go
@@ -20,6 +20,7 @@ import (
"bytes"
"context"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -376,9 +377,9 @@ func TestCommitRoundIOError(t *testing.T) {
// flip the flag when the exit handler is called,
// which happens when Fatal logging is called
- flag := false
+ var flag atomic.Bool
logging.RegisterExitHandler(func() {
- flag = true
+ flag.Store(true)
})
io := &ioErrorTracker{}
@@ -404,7 +405,7 @@ func TestCommitRoundIOError(t *testing.T) {
// confirm that after 100 blocks, the scheduled commit generated an error
// which triggered Fatal logging (and would therefore call any registered exit handlers)
- a.True(flag)
+ a.True(flag.Load())
}
func TestAccountUpdatesLedgerEvaluatorNoBlockHdr(t *testing.T) {
diff --git a/logging/log_test.go b/logging/log_test.go
index bf6db060c7..e16d62d733 100644
--- a/logging/log_test.go
+++ b/logging/log_test.go
@@ -19,6 +19,7 @@ package logging
import (
"bytes"
"encoding/json"
+ "sync/atomic"
"testing"
"github.com/algorand/go-algorand/test/partitiontest"
@@ -129,13 +130,13 @@ func TestFatalExitHandler(t *testing.T) {
nl := TestingLogWithoutFatalExit(t)
// Make an exit handler that sets a flag to demonstrate it was called
- flag := false
+ var flag atomic.Bool
RegisterExitHandler(func() {
- flag = true
+ flag.Store(true)
})
nl.Fatal("OH NO")
// Check that the exit handler was called
- require.True(t, flag)
+ require.True(t, flag.Load())
}
diff --git a/node/node.go b/node/node.go
index 0e10be7be2..a7e8132e1c 100644
--- a/node/node.go
+++ b/node/node.go
@@ -254,11 +254,11 @@ func MakeFull(log logging.Logger, rootDir string, cfg config.Local, phonebookAdd
blockValidator := blockValidatorImpl{l: node.ledger, verificationPool: node.highPriorityCryptoVerificationPool}
agreementLedger := makeAgreementLedger(node.ledger, node.net)
- var agreementClock timers.Clock
+ var agreementClock timers.Clock[agreement.TimeoutType]
if node.devMode {
- agreementClock = timers.MakeFrozenClock()
+ agreementClock = timers.MakeFrozenClock[agreement.TimeoutType]()
} else {
- agreementClock = timers.MakeMonotonicClock(time.Now())
+ agreementClock = timers.MakeMonotonicClock[agreement.TimeoutType](time.Now())
}
agreementParameters := agreement.Parameters{
Logger: log,
diff --git a/test/e2e-go/restAPI/restClient_test.go b/test/e2e-go/restAPI/restClient_test.go
index bc8218120f..94441d92c6 100644
--- a/test/e2e-go/restAPI/restClient_test.go
+++ b/test/e2e-go/restAPI/restClient_test.go
@@ -2242,6 +2242,7 @@ func TestMaxDepthAppWithPCandStackTrace(t *testing.T) {
ops, err := logic.AssembleString(maxDepthTealApproval)
a.NoError(err)
approval := ops.Program
+ approvalHash := crypto.Hash(approval)
ops, err = logic.AssembleString("#pragma version 8\nint 1")
a.NoError(err)
clearState := ops.Program
@@ -2268,9 +2269,9 @@ func TestMaxDepthAppWithPCandStackTrace(t *testing.T) {
futureAppID := basics.AppIndex(*submittedAppCreateTxn.ApplicationIndex)
// fund app account
- appFundTxn, err := testClient.SendPaymentFromWallet(
- wh, nil, senderAddress, futureAppID.Address().String(),
- 0, MinBalance*uint64(MaxDepth+1), nil, "", 0, 0,
+ appFundTxn, err := testClient.ConstructPayment(
+ senderAddress, futureAppID.Address().String(),
+ 0, MinBalance*uint64(MaxDepth+1), nil, "", [32]byte{}, 0, 0,
)
a.NoError(err)
@@ -3019,15 +3020,26 @@ func TestMaxDepthAppWithPCandStackTrace(t *testing.T) {
expectedTraceSecondTxn := &model.SimulationTransactionExecTrace{
ApprovalProgramTrace: recursiveLongOpcodeTrace(futureAppID, 0),
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
InnerTrace: &[]model.SimulationTransactionExecTrace{
- {ApprovalProgramTrace: &creationOpcodeTrace},
+ {
+ ApprovalProgramTrace: &creationOpcodeTrace,
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
+ },
{},
{
ApprovalProgramTrace: recursiveLongOpcodeTrace(futureAppID+3, 1),
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
InnerTrace: &[]model.SimulationTransactionExecTrace{
- {ApprovalProgramTrace: &creationOpcodeTrace},
+ {
+ ApprovalProgramTrace: &creationOpcodeTrace,
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
+ },
{},
- {ApprovalProgramTrace: finalDepthTrace(futureAppID+6, 2)},
+ {
+ ApprovalProgramTrace: finalDepthTrace(futureAppID+6, 2),
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
+ },
},
},
},
@@ -3079,6 +3091,7 @@ func TestSimulateScratchSlotChange(t *testing.T) {
int 1`)
a.NoError(err)
approval := ops.Program
+ approvalHash := crypto.Hash(approval)
ops, err = logic.AssembleString("#pragma version 8\nint 1")
a.NoError(err)
clearState := ops.Program
@@ -3104,7 +3117,7 @@ func TestSimulateScratchSlotChange(t *testing.T) {
futureAppID := basics.AppIndex(*submittedAppCreateTxn.ApplicationIndex)
// fund app account
- appFundTxn, err := testClient.SendPaymentFromWallet(
+ _, err = testClient.SendPaymentFromWallet(
wh, nil, senderAddress, futureAppID.Address().String(),
0, MinBalance, nil, "", 0, 0,
)
@@ -3118,14 +3131,6 @@ func TestSimulateScratchSlotChange(t *testing.T) {
appCallTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee, appCallTxn)
a.NoError(err)
- // Group the transactions
- gid, err := testClient.GroupID([]transactions.Transaction{appFundTxn, appCallTxn})
- a.NoError(err)
- appFundTxn.Group = gid
- appCallTxn.Group = gid
-
- appFundTxnSigned, err := testClient.SignTransactionWithWallet(wh, nil, appFundTxn)
- a.NoError(err)
appCallTxnSigned, err := testClient.SignTransactionWithWallet(wh, nil, appCallTxn)
a.NoError(err)
@@ -3136,7 +3141,7 @@ func TestSimulateScratchSlotChange(t *testing.T) {
}
simulateRequest := v2.PreEncodedSimulateRequest{
TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
- {Txns: []transactions.SignedTxn{appFundTxnSigned, appCallTxnSigned}},
+ {Txns: []transactions.SignedTxn{appCallTxnSigned}},
},
ExecTraceConfig: execTraceConfig,
}
@@ -3154,7 +3159,7 @@ func TestSimulateScratchSlotChange(t *testing.T) {
// simulate with wrong config (not enabled trace), see expected error
_, err = testClient.SimulateTransactions(v2.PreEncodedSimulateRequest{
TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
- {Txns: []transactions.SignedTxn{appFundTxnSigned, appCallTxnSigned}},
+ {Txns: []transactions.SignedTxn{appCallTxnSigned}},
},
ExecTraceConfig: simulation.ExecTraceConfig{Scratch: true},
})
@@ -3166,9 +3171,8 @@ func TestSimulateScratchSlotChange(t *testing.T) {
// check if resp match expected result
a.Equal(execTraceConfig, resp.ExecTraceConfig)
- a.Len(resp.TxnGroups[0].Txns, 2)
- a.Nil(resp.TxnGroups[0].Txns[0].TransactionTrace)
- a.NotNil(resp.TxnGroups[0].Txns[1].TransactionTrace)
+ a.Len(resp.TxnGroups[0].Txns, 1)
+ a.NotNil(resp.TxnGroups[0].Txns[0].TransactionTrace)
expectedTraceSecondTxn := &model.SimulationTransactionExecTrace{
ApprovalProgramTrace: &[]model.SimulationOpcodeTraceUnit{
@@ -3204,8 +3208,292 @@ func TestSimulateScratchSlotChange(t *testing.T) {
},
{Pc: 16},
},
+ ApprovalProgramHash: toPtr(approvalHash.ToSlice()),
}
- a.Equal(expectedTraceSecondTxn, resp.TxnGroups[0].Txns[1].TransactionTrace)
+ a.Equal(expectedTraceSecondTxn, resp.TxnGroups[0].Txns[0].TransactionTrace)
+}
+
+func TestSimulateExecTraceStateChange(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ a := require.New(fixtures.SynchronizedTest(t))
+ var localFixture fixtures.RestClientFixture
+ localFixture.SetupNoStart(t, filepath.Join("nettemplates", "OneNodeFuture.json"))
+
+ // Get primary node
+ primaryNode, err := fixture.GetNodeController("Primary")
+ a.NoError(err)
+
+ fixture.Start()
+ defer primaryNode.FullStop()
+
+ // get lib goal client
+ testClient := fixture.LibGoalFixture.GetLibGoalClientFromNodeController(primaryNode)
+
+ _, err = testClient.WaitForRound(1)
+ a.NoError(err)
+
+ wh, err := testClient.GetUnencryptedWalletHandle()
+ a.NoError(err)
+ addresses, err := testClient.ListAddresses(wh)
+ a.NoError(err)
+ _, senderAddress := getMaxBalAddr(t, testClient, addresses)
+ a.NotEmpty(senderAddress, "no addr with funds")
+
+ addressDigest, err := basics.UnmarshalChecksumAddress(senderAddress)
+ a.NoError(err)
+
+ ops, err := logic.AssembleString(
+ `#pragma version 8
+txn ApplicationID
+bz end // Do nothing during create
+
+txn OnCompletion
+int OptIn
+==
+bnz end // Always allow optin
+
+byte "local"
+byte "global"
+txn ApplicationArgs 0
+match local global
+err // Unknown command
+
+local:
+ txn Sender
+ byte "local-int-key"
+ int 0xcafeb0ba
+ app_local_put
+ int 0
+ byte "local-bytes-key"
+ byte "xqcL"
+ app_local_put
+ b end
+
+global:
+ byte "global-int-key"
+ int 0xdeadbeef
+ app_global_put
+ byte "global-bytes-key"
+ byte "welt am draht"
+ app_global_put
+ b end
+
+end:
+ int 1`)
+ a.NoError(err)
+ approval := ops.Program
+ approvalHash := crypto.Hash(approval)
+
+ ops, err = logic.AssembleString("#pragma version 8\nint 1")
+ a.NoError(err)
+ clearState := ops.Program
+
+ gl := basics.StateSchema{NumByteSlice: 1, NumUint: 1}
+ lc := basics.StateSchema{NumByteSlice: 1, NumUint: 1}
+
+ MinFee := config.Consensus[protocol.ConsensusFuture].MinTxnFee
+ MinBalance := config.Consensus[protocol.ConsensusFuture].MinBalance
+
+ // create app and get the application ID
+ appCreateTxn, err := testClient.MakeUnsignedAppCreateTx(
+ transactions.NoOpOC, approval, clearState, gl,
+ lc, nil, nil, nil, nil, nil, 0)
+ a.NoError(err)
+ appCreateTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, 0, appCreateTxn)
+ a.NoError(err)
+
+ appCreateTxID, err := testClient.SignAndBroadcastTransaction(wh, nil, appCreateTxn)
+ a.NoError(err)
+ submittedAppCreateTxn, err := waitForTransaction(t, testClient, senderAddress, appCreateTxID, 30*time.Second)
+ a.NoError(err)
+ futureAppID := basics.AppIndex(*submittedAppCreateTxn.ApplicationIndex)
+
+ // fund app account
+ _, err = testClient.ConstructPayment(
+ senderAddress, futureAppID.Address().String(),
+ 0, MinBalance*2, nil, "", [32]byte{}, 0, 0,
+ )
+ a.NoError(err)
+
+ // construct app call "global"
+ appCallGlobalTxn, err := testClient.MakeUnsignedAppNoOpTx(
+ uint64(futureAppID), [][]byte{[]byte("global")}, nil, nil, nil, nil,
+ )
+ a.NoError(err)
+ appCallGlobalTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee, appCallGlobalTxn)
+ a.NoError(err)
+ // construct app optin
+ appOptInTxn, err := testClient.MakeUnsignedAppOptInTx(uint64(futureAppID), nil, nil, nil, nil, nil)
+ a.NoError(err)
+ appOptInTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee, appOptInTxn)
+ // construct app call "global"
+ appCallLocalTxn, err := testClient.MakeUnsignedAppNoOpTx(
+ uint64(futureAppID), [][]byte{[]byte("local")}, nil, nil, nil, nil,
+ )
+ a.NoError(err)
+ appCallLocalTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee, appCallLocalTxn)
+ a.NoError(err)
+
+ gid, err := testClient.GroupID([]transactions.Transaction{appCallGlobalTxn, appOptInTxn, appCallLocalTxn})
+ a.NoError(err)
+ appCallGlobalTxn.Group = gid
+ appOptInTxn.Group = gid
+ appCallLocalTxn.Group = gid
+
+ appCallTxnGlobalSigned, err := testClient.SignTransactionWithWallet(wh, nil, appCallGlobalTxn)
+ a.NoError(err)
+ appOptInSigned, err := testClient.SignTransactionWithWallet(wh, nil, appOptInTxn)
+ a.NoError(err)
+ appCallTxnLocalSigned, err := testClient.SignTransactionWithWallet(wh, nil, appCallLocalTxn)
+ a.NoError(err)
+
+ // construct simulation request, with state change enabled
+ execTraceConfig := simulation.ExecTraceConfig{
+ Enable: true,
+ State: true,
+ }
+ simulateRequest := v2.PreEncodedSimulateRequest{
+ TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
+ {Txns: []transactions.SignedTxn{appCallTxnGlobalSigned, appOptInSigned, appCallTxnLocalSigned}},
+ },
+ ExecTraceConfig: execTraceConfig,
+ }
+
+ // update the configuration file to enable EnableDeveloperAPI
+ err = primaryNode.FullStop()
+ a.NoError(err)
+ cfg, err := config.LoadConfigFromDisk(primaryNode.GetDataDir())
+ a.NoError(err)
+ cfg.EnableDeveloperAPI = true
+ err = cfg.SaveToDisk(primaryNode.GetDataDir())
+ require.NoError(t, err)
+ fixture.Start()
+
+ // start real simulating
+ resp, err := testClient.SimulateTransactions(simulateRequest)
+ a.NoError(err)
+
+ // assertions
+ a.Len(resp.TxnGroups, 1)
+ a.Nil(resp.TxnGroups[0].FailureMessage)
+ a.Len(resp.TxnGroups[0].Txns, 3)
+
+ for i := 0; i < 3; i++ {
+ a.NotNil(resp.TxnGroups[0].Txns[i].TransactionTrace.ApprovalProgramHash)
+ a.Equal(approvalHash.ToSlice(), *resp.TxnGroups[0].Txns[i].TransactionTrace.ApprovalProgramHash)
+ }
+
+ a.Equal([]model.SimulationOpcodeTraceUnit{
+ {Pc: 1},
+ {Pc: 4},
+ {Pc: 6},
+ {Pc: 9},
+ {Pc: 11},
+ {Pc: 12},
+ {Pc: 13},
+ {Pc: 16},
+ {Pc: 23},
+ {Pc: 31},
+ {Pc: 34},
+ {Pc: 94},
+ {Pc: 110},
+ {
+ Pc: 116,
+ StateChanges: &[]model.ApplicationStateOperation{
+ {
+ Operation: "w",
+ AppStateType: "g",
+ Key: []byte("global-int-key"),
+ NewValue: &model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: toPtr[uint64](0xdeadbeef),
+ },
+ },
+ },
+ },
+ {Pc: 117},
+ {Pc: 135},
+ {
+ Pc: 150,
+ StateChanges: &[]model.ApplicationStateOperation{
+ {
+ Operation: "w",
+ AppStateType: "g",
+ Key: []byte("global-bytes-key"),
+ NewValue: &model.AvmValue{
+ Type: uint64(basics.TealBytesType),
+ Bytes: toPtr([]byte("welt am draht")),
+ },
+ },
+ },
+ },
+ {Pc: 151},
+ {Pc: 154},
+ }, *resp.TxnGroups[0].Txns[0].TransactionTrace.ApprovalProgramTrace)
+ a.NotNil(resp.TxnGroups[0].Txns[1].TransactionTrace.ApprovalProgramHash)
+ a.Equal([]model.SimulationOpcodeTraceUnit{
+ {Pc: 1},
+ {Pc: 4},
+ {Pc: 6},
+ {Pc: 9},
+ {Pc: 11},
+ {Pc: 12},
+ {Pc: 13},
+ {Pc: 154},
+ }, *resp.TxnGroups[0].Txns[1].TransactionTrace.ApprovalProgramTrace)
+ a.Equal([]model.SimulationOpcodeTraceUnit{
+ {Pc: 1},
+ {Pc: 4},
+ {Pc: 6},
+ {Pc: 9},
+ {Pc: 11},
+ {Pc: 12},
+ {Pc: 13},
+ {Pc: 16},
+ {Pc: 23},
+ {Pc: 31},
+ {Pc: 34},
+ {Pc: 41},
+ {Pc: 43},
+ {Pc: 58},
+ {
+ Pc: 64,
+ StateChanges: &[]model.ApplicationStateOperation{
+ {
+ Operation: "w",
+ AppStateType: "l",
+ Key: []byte("local-int-key"),
+ NewValue: &model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: toPtr[uint64](0xcafeb0ba),
+ },
+ Account: toPtr(addressDigest.String()),
+ },
+ },
+ },
+ {Pc: 65},
+ {Pc: 67},
+ {Pc: 84},
+ {
+ Pc: 90,
+ StateChanges: &[]model.ApplicationStateOperation{
+ {
+ Operation: "w",
+ AppStateType: "l",
+ Key: []byte("local-bytes-key"),
+ NewValue: &model.AvmValue{
+ Type: uint64(basics.TealBytesType),
+ Bytes: toPtr([]byte("xqcL")),
+ },
+ Account: toPtr(addressDigest.String()),
+ },
+ },
+ },
+ {Pc: 91},
+ {Pc: 154},
+ }, *resp.TxnGroups[0].Txns[2].TransactionTrace.ApprovalProgramTrace)
}
func TestSimulateWithUnnamedResources(t *testing.T) {
diff --git a/test/framework/fixtures/libgoalFixture.go b/test/framework/fixtures/libgoalFixture.go
index c0527fdd62..dbeb3c1f8f 100644
--- a/test/framework/fixtures/libgoalFixture.go
+++ b/test/framework/fixtures/libgoalFixture.go
@@ -314,8 +314,12 @@ func (f *LibGoalFixture) ShutdownImpl(preserveData bool) {
if preserveData {
f.network.Stop(f.binDir)
f.dumpLogs(filepath.Join(f.PrimaryDataDir(), "node.log"))
+ f.dumpLogs(filepath.Join(f.PrimaryDataDir(), "algod-err.log"))
+ f.dumpLogs(filepath.Join(f.PrimaryDataDir(), "algod-out.log"))
for _, nodeDir := range f.NodeDataDirs() {
f.dumpLogs(filepath.Join(nodeDir, "node.log"))
+ f.dumpLogs(filepath.Join(nodeDir, "algod-err.log"))
+ f.dumpLogs(filepath.Join(nodeDir, "algod-out.log"))
}
} else {
f.network.Delete(f.binDir)
diff --git a/test/testdata/configs/config-v30.json b/test/testdata/configs/config-v30.json
index 6df0464f17..094c7ca7df 100644
--- a/test/testdata/configs/config-v30.json
+++ b/test/testdata/configs/config-v30.json
@@ -55,7 +55,7 @@
"EnableRequestLogger": false,
"EnableRuntimeMetrics": false,
"EnableTopAccountsReporting": false,
- "EnableTxBacklogRateLimiting": false,
+ "EnableTxBacklogRateLimiting": true,
"EnableTxnEvalTracer": false,
"EnableUsageLog": false,
"EnableVerbosedTransactionSyncLogging": false,
diff --git a/util/timers/frozen.go b/util/timers/frozen.go
index e6487b1a8a..f4400c3a82 100644
--- a/util/timers/frozen.go
+++ b/util/timers/frozen.go
@@ -21,42 +21,42 @@ import (
)
// Frozen is a dummy frozen clock that never fires.
-type Frozen struct {
+type Frozen[TimeoutType comparable] struct {
timeoutCh chan time.Time
}
// MakeFrozenClock creates a new frozen clock.
-func MakeFrozenClock() Clock {
- return &Frozen{
+func MakeFrozenClock[TimeoutType comparable]() Clock[TimeoutType] {
+ return &Frozen[TimeoutType]{
timeoutCh: make(chan time.Time, 1),
}
}
// Zero returns a new Clock reset to the current time.
-func (m *Frozen) Zero() Clock {
- return MakeFrozenClock()
+func (m *Frozen[TimeoutType]) Zero() Clock[TimeoutType] {
+ return MakeFrozenClock[TimeoutType]()
}
// TimeoutAt returns a channel that will signal when the duration has elapsed.
-func (m *Frozen) TimeoutAt(delta time.Duration) <-chan time.Time {
+func (m *Frozen[TimeoutType]) TimeoutAt(delta time.Duration, timeoutType TimeoutType) <-chan time.Time {
return m.timeoutCh
}
// Encode implements Clock.Encode.
-func (m *Frozen) Encode() []byte {
+func (m *Frozen[TimeoutType]) Encode() []byte {
return []byte{}
}
// Decode implements Clock.Decode.
-func (m *Frozen) Decode([]byte) (Clock, error) {
- return MakeFrozenClock(), nil
+func (m *Frozen[TimeoutType]) Decode([]byte) (Clock[TimeoutType], error) {
+ return MakeFrozenClock[TimeoutType](), nil
}
-func (m *Frozen) String() string {
+func (m *Frozen[TimeoutType]) String() string {
return ""
}
// Since implements the Clock interface.
-func (m *Frozen) Since() time.Duration {
+func (m *Frozen[TimeoutType]) Since() time.Duration {
return 0
}
diff --git a/util/timers/interface.go b/util/timers/interface.go
index e96aced757..d217437e9e 100644
--- a/util/timers/interface.go
+++ b/util/timers/interface.go
@@ -22,20 +22,23 @@ import (
)
// Clock provides timeout events which fire at some point after a point in time.
-type Clock interface {
+type Clock[TimeoutType comparable] interface {
// Zero returns a reset Clock. TimeoutAt channels will use the point
// at which Zero was called as their reference point.
- Zero() Clock
+ Zero() Clock[TimeoutType]
// Since returns the time spent between the last time the clock was zeroed out and the current
// wall clock time.
Since() time.Duration
// TimeoutAt returns a channel that fires delta time after Zero was called.
+ // timeoutType is specifies the reason for this timeout. If there are two
+ // timeouts of the same type at the same time, then only one of them fires.
// If delta has already passed, it returns a closed channel.
//
- // TimeoutAt must be called after Zero; otherwise, the channel's behavior is undefined.
- TimeoutAt(delta time.Duration) <-chan time.Time
+ // TimeoutAt must be called after Zero; otherwise, the channel's behavior is
+ // undefined.
+ TimeoutAt(delta time.Duration, timeoutType TimeoutType) <-chan time.Time
// Encode serializes the Clock into a byte slice.
Encode() []byte
@@ -43,5 +46,5 @@ type Clock interface {
// Decode deserializes the Clock from a byte slice.
// A Clock which has been Decoded from an Encoded Clock should produce
// the same timeouts as the original Clock.
- Decode([]byte) (Clock, error)
+ Decode([]byte) (Clock[TimeoutType], error)
}
diff --git a/util/timers/monotonic.go b/util/timers/monotonic.go
index 70db87da3e..96207f3950 100644
--- a/util/timers/monotonic.go
+++ b/util/timers/monotonic.go
@@ -23,56 +23,66 @@ import (
"github.com/algorand/go-algorand/protocol"
)
+type timeout struct {
+ delta time.Duration
+ ch <-chan time.Time
+}
+
// Monotonic uses the system's monotonic clock to emit timeouts.
-type Monotonic struct {
+type Monotonic[TimeoutType comparable] struct {
zero time.Time
- timeouts map[time.Duration]<-chan time.Time
+ timeouts map[TimeoutType]timeout
}
// MakeMonotonicClock creates a new monotonic clock with a given zero point.
-func MakeMonotonicClock(zero time.Time) Clock {
- return &Monotonic{
+func MakeMonotonicClock[TimeoutType comparable](zero time.Time) Clock[TimeoutType] {
+ return &Monotonic[TimeoutType]{
zero: zero,
}
}
// Zero returns a new Clock reset to the current time.
-func (m *Monotonic) Zero() Clock {
+func (m *Monotonic[TimeoutType]) Zero() Clock[TimeoutType] {
z := time.Now()
logging.Base().Debugf("Clock zeroed to %v", z)
- return MakeMonotonicClock(z)
+ return MakeMonotonicClock[TimeoutType](z)
}
// TimeoutAt returns a channel that will signal when the duration has elapsed.
-func (m *Monotonic) TimeoutAt(delta time.Duration) <-chan time.Time {
+func (m *Monotonic[TimeoutType]) TimeoutAt(delta time.Duration, timeoutType TimeoutType) <-chan time.Time {
if m.timeouts == nil {
- m.timeouts = make(map[time.Duration]<-chan time.Time)
+ m.timeouts = make(map[TimeoutType]timeout)
}
- timeoutCh, ok := m.timeouts[delta]
- if ok {
- return timeoutCh
+
+ tmt, ok := m.timeouts[timeoutType]
+ if ok && tmt.delta == delta {
+ // if the new timeout is the same as the current one for that type,
+ // return the existing channel.
+ return tmt.ch
}
+ tmt = timeout{delta: delta}
+
target := m.zero.Add(delta)
left := target.Sub(time.Now())
if left < 0 {
- timeout := make(chan time.Time)
- close(timeout)
- timeoutCh = timeout
+ ch := make(chan time.Time)
+ close(ch)
+ tmt.ch = ch
} else {
- timeoutCh = time.After(left)
+ tmt.ch = time.After(left)
}
- m.timeouts[delta] = timeoutCh
- return timeoutCh
+ m.timeouts[timeoutType] = tmt
+ return tmt.ch
}
// Encode implements Clock.Encode.
-func (m *Monotonic) Encode() []byte {
+func (m *Monotonic[TimeoutType]) Encode() []byte {
return protocol.EncodeReflect(m.zero)
}
// Decode implements Clock.Decode.
-func (m *Monotonic) Decode(data []byte) (Clock, error) {
+func (m *Monotonic[TimeoutType]) Decode(data []byte) (Clock[TimeoutType], error) {
var zero time.Time
err := protocol.DecodeReflect(data, &zero)
if err == nil {
@@ -80,14 +90,14 @@ func (m *Monotonic) Decode(data []byte) (Clock, error) {
} else {
logging.Base().Errorf("Clock decoded with zero at %v (err: %v)", zero, err)
}
- return MakeMonotonicClock(zero), err
+ return MakeMonotonicClock[TimeoutType](zero), err
}
-func (m *Monotonic) String() string {
+func (m *Monotonic[TimeoutType]) String() string {
return time.Time(m.zero).String()
}
// Since returns the time that has passed between the time the clock was last zeroed out and now
-func (m *Monotonic) Since() time.Duration {
+func (m *Monotonic[TimeoutType]) Since() time.Duration {
return time.Since(m.zero)
}
diff --git a/util/timers/monotonic_test.go b/util/timers/monotonic_test.go
index f8821b300b..912f1b8425 100644
--- a/util/timers/monotonic_test.go
+++ b/util/timers/monotonic_test.go
@@ -17,10 +17,11 @@
package timers
import (
- "github.com/algorand/go-algorand/test/partitiontest"
"math/rand"
"testing"
"time"
+
+ "github.com/algorand/go-algorand/test/partitiontest"
)
func polled(ch <-chan time.Time) bool {
@@ -35,14 +36,14 @@ func polled(ch <-chan time.Time) bool {
func TestMonotonicDelta(t *testing.T) {
partitiontest.PartitionTest(t)
- var m Monotonic
- var c Clock
+ var m Monotonic[int]
+ var c Clock[int]
var ch <-chan time.Time
d := time.Millisecond * 100
c = m.Zero()
- ch = c.TimeoutAt(d)
+ ch = c.TimeoutAt(d, 0)
if polled(ch) {
t.Errorf("channel fired ~100ms early")
}
@@ -52,7 +53,7 @@ func TestMonotonicDelta(t *testing.T) {
t.Errorf("channel failed to fire at 100ms")
}
- ch = c.TimeoutAt(d / 2)
+ ch = c.TimeoutAt(d/2, 0)
if !polled(ch) {
t.Errorf("channel failed to fire at 50ms")
}
@@ -61,12 +62,12 @@ func TestMonotonicDelta(t *testing.T) {
func TestMonotonicZeroDelta(t *testing.T) {
partitiontest.PartitionTest(t)
- var m Monotonic
- var c Clock
+ var m Monotonic[int]
+ var c Clock[int]
var ch <-chan time.Time
c = m.Zero()
- ch = c.TimeoutAt(0)
+ ch = c.TimeoutAt(0, 0)
if !polled(ch) {
t.Errorf("read failed on channel at zero timeout")
}
@@ -75,12 +76,12 @@ func TestMonotonicZeroDelta(t *testing.T) {
func TestMonotonicNegativeDelta(t *testing.T) {
partitiontest.PartitionTest(t)
- var m Monotonic
- var c Clock
+ var m Monotonic[int]
+ var c Clock[int]
var ch <-chan time.Time
c = m.Zero()
- ch = c.TimeoutAt(-time.Second)
+ ch = c.TimeoutAt(-time.Second, 0)
if !polled(ch) {
t.Errorf("read failed on channel at negative timeout")
}
@@ -89,14 +90,14 @@ func TestMonotonicNegativeDelta(t *testing.T) {
func TestMonotonicZeroTwice(t *testing.T) {
partitiontest.PartitionTest(t)
- var m Monotonic
- var c Clock
+ var m Monotonic[int]
+ var c Clock[int]
var ch <-chan time.Time
d := time.Millisecond * 100
c = m.Zero()
- ch = c.TimeoutAt(d)
+ ch = c.TimeoutAt(d, 0)
if polled(ch) {
t.Errorf("channel fired ~100ms early")
}
@@ -107,7 +108,7 @@ func TestMonotonicZeroTwice(t *testing.T) {
}
c = c.Zero()
- ch = c.TimeoutAt(d)
+ ch = c.TimeoutAt(d, 0)
if polled(ch) {
t.Errorf("channel fired ~100ms early after call to Zero")
}
@@ -121,21 +122,21 @@ func TestMonotonicZeroTwice(t *testing.T) {
func TestMonotonicEncodeDecode(t *testing.T) {
partitiontest.PartitionTest(t)
- singleTest := func(c Clock, descr string) {
+ singleTest := func(c Clock[int], descr string) {
data := c.Encode()
c0, err := c.Decode(data)
if err != nil {
t.Errorf("decoding error: %v", err)
}
- if !time.Time(c.(*Monotonic).zero).Equal(time.Time(c0.(*Monotonic).zero)) {
+ if !time.Time(c.(*Monotonic[int]).zero).Equal(time.Time(c0.(*Monotonic[int]).zero)) {
t.Errorf("%v clock not encoded properly: %v != %v", descr, c, c0)
}
}
- var c Clock
- var m Monotonic
+ var c Clock[int]
+ var m Monotonic[int]
- c = Clock(&m)
+ c = Clock[int](&m)
singleTest(c, "empty")
c = c.Zero()
@@ -144,11 +145,51 @@ func TestMonotonicEncodeDecode(t *testing.T) {
now := time.Now()
for i := 0; i < 100; i++ {
r := time.Duration(rand.Int63())
- c = Clock(
- &Monotonic{
+ c = Clock[int](
+ &Monotonic[int]{
zero: now.Add(r),
},
)
singleTest(c, "random")
}
}
+
+func TestTimeoutTypes(t *testing.T) {
+ partitiontest.PartitionTest(t)
+
+ var m Monotonic[int]
+ var c Clock[int]
+
+ d := time.Millisecond * 100
+
+ c = m.Zero()
+ ch1 := c.TimeoutAt(d, 0)
+ ch2 := c.TimeoutAt(d, 1)
+ if polled(ch1) {
+ t.Errorf("channel fired ~100ms early")
+ }
+ if polled(ch2) {
+ t.Errorf("channel fired ~100ms early")
+ }
+
+ if ch1 == ch2 {
+ t.Errorf("equal channels for different timeout types")
+ }
+
+ <-time.After(d * 2)
+ if !polled(ch1) {
+ t.Errorf("channel failed to fire at 100ms")
+ }
+ if !polled(ch2) {
+ t.Errorf("channel failed to fire at 100ms")
+ }
+
+ ch1 = c.TimeoutAt(d/2, 0)
+ if !polled(ch1) {
+ t.Errorf("channel failed to fire at 50ms")
+ }
+ ch2 = c.TimeoutAt(d/2, 0)
+ if !polled(ch2) {
+ t.Errorf("channel failed to fire at 50ms")
+ }
+}