summaryrefslogtreecommitdiff
path: root/daemon/algod/api/server/v2/dryrun_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/algod/api/server/v2/dryrun_test.go')
-rw-r--r--daemon/algod/api/server/v2/dryrun_test.go292
1 files changed, 288 insertions, 4 deletions
diff --git a/daemon/algod/api/server/v2/dryrun_test.go b/daemon/algod/api/server/v2/dryrun_test.go
index c926934dd..abb28143d 100644
--- a/daemon/algod/api/server/v2/dryrun_test.go
+++ b/daemon/algod/api/server/v2/dryrun_test.go
@@ -34,6 +34,7 @@ import (
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/protocol"
+ "github.com/algorand/go-algorand/test/partitiontest"
)
func unB64(x string) []byte {
@@ -126,9 +127,11 @@ func logResponse(t *testing.T, response *generated.DryrunResponse) {
}
}
-var dryrunProtoVersion protocol.ConsensusVersion = "dryrunTestProto"
+var dryrunProtoVersion protocol.ConsensusVersion = protocol.ConsensusFuture
+var dryrunMakeLedgerProto protocol.ConsensusVersion = "dryrunMakeLedgerProto"
func TestDryrunLogicSig(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -153,6 +156,7 @@ func TestDryrunLogicSig(t *testing.T) {
}
func TestDryrunLogicSigSource(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -353,7 +357,7 @@ func init() {
proto.MaxAppBytesValueLen = 64
proto.MaxAppSumKeyValueLens = 128
- config.Consensus[dryrunProtoVersion] = proto
+ config.Consensus[dryrunMakeLedgerProto] = proto
}
func checkLogicSigPass(t *testing.T, response *generated.DryrunResponse) {
@@ -384,6 +388,7 @@ func checkAppCallPass(t *testing.T, response *generated.DryrunResponse) {
}
func TestDryrunGlobal1(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -432,6 +437,7 @@ func TestDryrunGlobal1(t *testing.T) {
}
func TestDryrunGlobal2(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -484,6 +490,7 @@ func TestDryrunGlobal2(t *testing.T) {
}
func TestDryrunLocal1(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -557,6 +564,7 @@ func TestDryrunLocal1(t *testing.T) {
}
func TestDryrunLocal1A(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
@@ -637,6 +645,7 @@ func TestDryrunLocal1A(t *testing.T) {
}
func TestDryrunLocalCheck(t *testing.T) {
+ partitiontest.PartitionTest(t)
// {"txns":[{"lsig":{"l":"AiABASI="},"txn":{}}]}
t.Parallel()
var dr DryrunRequest
@@ -691,6 +700,7 @@ func TestDryrunLocalCheck(t *testing.T) {
}
func TestDryrunMultipleTxns(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
var dr DryrunRequest
@@ -738,6 +748,7 @@ func TestDryrunMultipleTxns(t *testing.T) {
}
func TestDryrunEncodeDecode(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
var gdr generated.DryrunRequest
@@ -819,6 +830,7 @@ func TestDryrunEncodeDecode(t *testing.T) {
dr1, err := DryrunRequestFromGenerated(&gdr)
require.NoError(t, err)
encoded, err = encode(protocol.CodecHandle, &dr)
+ require.NoError(t, err)
encoded2 := protocol.EncodeReflect(&dr)
require.Equal(t, encoded, encoded2)
@@ -829,7 +841,6 @@ func TestDryrunEncodeDecode(t *testing.T) {
require.NoError(t, err)
require.Equal(t, dr1, dr2)
- dec = protocol.NewDecoder(buf)
dr2 = DryrunRequest{}
err = decode(protocol.CodecHandle, encoded, &dr2)
require.NoError(t, err)
@@ -842,6 +853,7 @@ func TestDryrunEncodeDecode(t *testing.T) {
}
func TestDryrunMakeLedger(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
var dr DryrunRequest
@@ -954,6 +966,7 @@ var dataJSON = []byte(`{
}`)
func TestDryrunRequestJSON(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
var gdr generated.DryrunRequest
@@ -980,6 +993,7 @@ func TestDryrunRequestJSON(t *testing.T) {
}
func TestStateDeltaToStateDelta(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
sd := basics.StateDelta{
"byteskey": {
@@ -1030,6 +1044,7 @@ func randomAddress() basics.Address {
}
func TestDryrunOptIn(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
ops, err := logic.AssembleString(`#pragma version 2
@@ -1093,6 +1108,7 @@ int 1`)
}
func TestDryrunLogs(t *testing.T) {
+ partitiontest.PartitionTest(t)
t.Parallel()
ops, err := logic.AssembleString(`
@@ -1120,6 +1136,7 @@ return
require.NoError(t, err)
approval := ops.Program
ops, err = logic.AssembleString("int 1")
+ require.NoError(t, err)
clst := ops.Program
ops, err = logic.AssembleString("#pragma version 5 \nint 1")
approv := ops.Program
@@ -1191,7 +1208,7 @@ return
logs := *response.Txns[0].Logs
assert.Equal(t, 32, len(logs))
for i, m := range logs {
- assert.Equal(t, base64.StdEncoding.EncodeToString([]byte(string(rune('B'+i)))), m.Value)
+ assert.Equal(t, []byte(string(rune('B'+i))), m)
}
encoded := string(protocol.EncodeJSON(response.Txns[0]))
assert.Contains(t, encoded, "logs")
@@ -1201,3 +1218,270 @@ return
assert.NotContains(t, encoded, "logs")
}
+
+func TestDryrunCost(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ var tests = []struct {
+ msg string
+ numHashes int
+ }{
+ {"REJECT", 12},
+ {"PASS", 5},
+ }
+
+ for _, test := range tests {
+ t.Run(test.msg, func(t *testing.T) {
+ costs := make([]uint64, 2)
+
+ ops, err := logic.AssembleString("#pragma version 5\nbyte 0x41\n" + strings.Repeat("keccak256\n", test.numHashes) + "pop\nint 1\n")
+ require.NoError(t, err)
+ approval := ops.Program
+ costs[0] = 3 + uint64(test.numHashes)*130
+
+ ops, err = logic.AssembleString("int 1")
+ require.NoError(t, err)
+ clst := ops.Program
+
+ ops, err = logic.AssembleString("#pragma version 5 \nint 1 \nint 2 \npop")
+ require.NoError(t, err)
+ approv := ops.Program
+ costs[1] = 3
+
+ var appIdx basics.AppIndex = 1
+ creator := randomAddress()
+ sender := randomAddress()
+ dr := DryrunRequest{
+ Txns: []transactions.SignedTxn{
+ {
+ Txn: transactions.Transaction{
+ Header: transactions.Header{Sender: sender},
+ Type: protocol.ApplicationCallTx,
+ ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{
+ ApplicationID: appIdx,
+ OnCompletion: transactions.OptInOC,
+ },
+ },
+ },
+ {
+ Txn: transactions.Transaction{
+ Header: transactions.Header{Sender: sender},
+ Type: protocol.ApplicationCallTx,
+ ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{
+ ApplicationID: appIdx + 1,
+ OnCompletion: transactions.OptInOC,
+ },
+ },
+ },
+ },
+ Apps: []generated.Application{
+ {
+ Id: uint64(appIdx),
+ Params: generated.ApplicationParams{
+ Creator: creator.String(),
+ ApprovalProgram: approval,
+ ClearStateProgram: clst,
+ LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1},
+ },
+ },
+ {
+ Id: uint64(appIdx + 1),
+ Params: generated.ApplicationParams{
+ Creator: creator.String(),
+ ApprovalProgram: approv,
+ ClearStateProgram: clst,
+ LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1},
+ },
+ },
+ },
+ Accounts: []generated.Account{
+ {
+ Address: sender.String(),
+ Status: "Online",
+ Amount: 10000000,
+ },
+ },
+ }
+ dr.ProtocolVersion = string(dryrunProtoVersion)
+ var response generated.DryrunResponse
+ doDryrunRequest(&dr, &response)
+ require.Empty(t, response.Error)
+ require.Equal(t, 2, len(response.Txns))
+
+ for i, txn := range response.Txns {
+ messages := *txn.AppCallMessages
+ require.GreaterOrEqual(t, len(messages), 1)
+ require.NotNil(t, *txn.Cost)
+ require.Equal(t, costs[i], *txn.Cost)
+ statusMatches := false
+ costExceedFound := false
+ for _, msg := range messages {
+ if strings.Contains(msg, "cost budget exceeded") {
+ costExceedFound = true
+ }
+ if msg == test.msg {
+ statusMatches = true
+ }
+ }
+ if test.msg == "REJECT" {
+ require.True(t, costExceedFound, "budget error not found in messages")
+ }
+ require.True(t, statusMatches, "expected status not found in messages")
+ }
+ })
+ }
+}
+
+func TestDebugTxSubmit(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ a := require.New(t)
+ source := `#pragma version 5
+itxn_begin
+int acfg
+itxn_field TypeEnum
+int 1000000
+itxn_field ConfigAssetTotal
+int 3
+itxn_field ConfigAssetDecimals
+byte "oz"
+itxn_field ConfigAssetUnitName
+byte "Gold"
+itxn_field ConfigAssetName
+byte "https://gold.rush/"
+itxn_field ConfigAssetURL
+byte 0x67f0cd61653bd34316160bc3f5cd3763c85b114d50d38e1f4e72c3b994411e7b
+itxn_field ConfigAssetMetadataHash
+itxn_submit
+int 1`
+
+ ops, err := logic.AssembleString(source)
+ require.NoError(t, err)
+ approval := ops.Program
+
+ ops, err = logic.AssembleString("int 1")
+ clst := ops.Program
+ require.NoError(t, err)
+
+ sender, err := basics.UnmarshalChecksumAddress("47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU")
+ a.NoError(err)
+ app, err := basics.UnmarshalChecksumAddress("6BPQU5WNZMTO4X72A2THZCGNJNTTE7YL6AWCYSUUTZEIYMJSEPJCQQ6DQI")
+ a.NoError(err)
+
+ // make balance records
+ appIdx := basics.AppIndex(100)
+ dr := DryrunRequest{
+ Txns: []transactions.SignedTxn{{
+ Txn: transactions.Transaction{
+ Type: protocol.ApplicationCallTx,
+ Header: transactions.Header{
+ Sender: sender,
+ Fee: basics.MicroAlgos{Raw: 100},
+ Note: []byte{1, 2, 3},
+ },
+ ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{
+ ApplicationID: appIdx,
+ },
+ },
+ }},
+ Apps: []generated.Application{
+ {
+ Id: uint64(appIdx),
+ Params: generated.ApplicationParams{
+ Creator: sender.String(),
+ ApprovalProgram: approval,
+ ClearStateProgram: clst,
+ },
+ },
+ },
+ Accounts: []generated.Account{
+ {
+ Address: sender.String(),
+ Status: "Online",
+ Amount: 10000000,
+ AmountWithoutPendingRewards: 10000000,
+ },
+ {
+ Address: app.String(),
+ Status: "Offline",
+ Amount: 10000000,
+ AmountWithoutPendingRewards: 10000000,
+ },
+ {
+ Address: basics.Address{}.String(),
+ Status: "Offline",
+ },
+ },
+ }
+
+ dr.ProtocolVersion = string(dryrunProtoVersion)
+
+ var response generated.DryrunResponse
+ doDryrunRequest(&dr, &response)
+ require.NoError(t, err)
+ checkAppCallPass(t, &response)
+ if t.Failed() {
+ logResponse(t, &response)
+ }
+}
+
+func TestDryrunBalanceWithReward(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ ops, err := logic.AssembleString(`#pragma version 5
+int 0
+balance
+int 0
+>`)
+ require.NoError(t, err)
+ approval := ops.Program
+ ops, err = logic.AssembleString("int 1")
+ clst := ops.Program
+ require.NoError(t, err)
+ var appIdx basics.AppIndex = 1
+ creator := randomAddress()
+ rewardBase := uint64(10000000)
+ dr := DryrunRequest{
+ Txns: []transactions.SignedTxn{
+ {
+ Txn: transactions.Transaction{
+ Header: transactions.Header{Sender: creator},
+ Type: protocol.ApplicationCallTx,
+ ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{
+ ApplicationID: appIdx,
+ },
+ },
+ },
+ },
+ Apps: []generated.Application{
+ {
+ Id: uint64(appIdx),
+ Params: generated.ApplicationParams{
+ Creator: creator.String(),
+ ApprovalProgram: approval,
+ ClearStateProgram: clst,
+ LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1},
+ },
+ },
+ },
+ Accounts: []generated.Account{
+ {
+ Address: creator.String(),
+ Status: "Online",
+ Amount: 10000000,
+ AmountWithoutPendingRewards: 10000000,
+ RewardBase: &rewardBase,
+ },
+ },
+ }
+ dr.ProtocolVersion = string(dryrunProtoVersion)
+
+ var response generated.DryrunResponse
+ doDryrunRequest(&dr, &response)
+ require.NoError(t, err)
+ checkAppCallPass(t, &response)
+ if t.Failed() {
+ logResponse(t, &response)
+ }
+}