diff options
Diffstat (limited to 'daemon/algod/api/server/v2/dryrun_test.go')
-rw-r--r-- | daemon/algod/api/server/v2/dryrun_test.go | 292 |
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) + } +} |