diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go index 047985b8bc..6498c575c7 100644 --- a/daemon/algod/api/server/v2/utils.go +++ b/daemon/algod/api/server/v2/utils.go @@ -301,12 +301,12 @@ func convertLogs(txn node.TxnWithStatus) *[][]byte { func convertInners(txn *node.TxnWithStatus) *[]preEncodedTxInfo { inner := make([]preEncodedTxInfo, len(txn.ApplyData.EvalDelta.InnerTxns)) for i, itxn := range txn.ApplyData.EvalDelta.InnerTxns { - inner[i] = convertTxn(&itxn) + inner[i] = convertInnerTxn(&itxn) } return &inner } -func convertTxn(txn *transactions.SignedTxnWithAD) preEncodedTxInfo { +func convertInnerTxn(txn *transactions.SignedTxnWithAD) preEncodedTxInfo { // This copies from handlers.PendingTransactionInformation, with // simplifications because we have a SignedTxnWithAD rather than // TxnWithStatus, and we know this txn has committed. @@ -319,8 +319,10 @@ func convertTxn(txn *transactions.SignedTxnWithAD) preEncodedTxInfo { response.ReceiverRewards = &txn.ApplyData.ReceiverRewards.Raw response.CloseRewards = &txn.ApplyData.CloseRewards.Raw - response.AssetIndex = (*uint64)(&txn.ApplyData.ConfigAsset) - response.ApplicationIndex = (*uint64)(&txn.ApplyData.ApplicationID) + // Since this is an inner txn, we know these indexes will be populated. No + // need to search payset for IDs + response.AssetIndex = numOrNil(uint64(txn.ApplyData.ConfigAsset)) + response.ApplicationIndex = numOrNil(uint64(txn.ApplyData.ApplicationID)) // Deltas, Logs, and Inners can not be set until we allow appl // response.LocalStateDelta, response.GlobalStateDelta = convertToDeltas(txn) diff --git a/test/e2e-go/restAPI/restClient_test.go b/test/e2e-go/restAPI/restClient_test.go index ccef6741b3..091385fb54 100644 --- a/test/e2e-go/restAPI/restClient_test.go +++ b/test/e2e-go/restAPI/restClient_test.go @@ -18,6 +18,7 @@ package restapi import ( "context" + "encoding/hex" "errors" "flag" "math" @@ -1030,3 +1031,121 @@ return } } + +func TestPendingTransactionInfoInnerTxnAssetCreate(t *testing.T) { + partitiontest.PartitionTest(t) + + a := require.New(fixtures.SynchronizedTest(t)) + var localFixture fixtures.RestClientFixture + localFixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachFuture.json")) + defer localFixture.Shutdown() + + testClient := localFixture.LibGoalClient + + testClient.WaitForRound(1) + + testClient.SetAPIVersionAffinity(algodclient.APIVersionV2, kmdclient.APIVersionV1) + + wh, err := testClient.GetUnencryptedWalletHandle() + a.NoError(err) + addresses, err := testClient.ListAddresses(wh) + a.NoError(err) + _, someAddress := getMaxBalAddr(t, testClient, addresses) + if someAddress == "" { + t.Error("no addr with funds") + } + a.NoError(err) + + prog := `#pragma version 5 +txn ApplicationID +bz end +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 +end: +int 1 +return +` + ops, err := logic.AssembleString(prog) + approv := ops.Program + ops, err = logic.AssembleString("#pragma version 5 \nint 1") + clst := ops.Program + + gl := basics.StateSchema{} + lc := basics.StateSchema{} + + // create app + appCreateTxn, err := testClient.MakeUnsignedApplicationCallTx(0, nil, nil, nil, nil, transactions.NoOpOC, approv, clst, gl, lc, 0) + a.NoError(err) + appCreateTxn, err = testClient.FillUnsignedTxTemplate(someAddress, 0, 0, 0, appCreateTxn) + a.NoError(err) + appCreateTxID, err := testClient.SignAndBroadcastTransaction(wh, nil, appCreateTxn) + a.NoError(err) + _, err = waitForTransaction(t, testClient, someAddress, appCreateTxID, 30*time.Second) + a.NoError(err) + + // get app ID + submittedAppCreateTxn, err := testClient.PendingTransactionInformationV2(appCreateTxID) + a.NoError(err) + a.NotNil(submittedAppCreateTxn.ApplicationIndex) + createdAppID := basics.AppIndex(*submittedAppCreateTxn.ApplicationIndex) + a.Greater(uint64(createdAppID), uint64(0)) + + // fund app account + appFundTxn, err := testClient.SendPaymentFromWallet(wh, nil, someAddress, createdAppID.Address().String(), 0, 1_000_000, nil, "", 0, 0) + a.NoError(err) + appFundTxID := appFundTxn.ID() + _, err = waitForTransaction(t, testClient, someAddress, appFundTxID.String(), 30*time.Second) + a.NoError(err) + + // call app, which will issue an ASA create inner txn + appCallTxn, err := testClient.MakeUnsignedAppNoOpTx(uint64(createdAppID), nil, nil, nil, nil) + a.NoError(err) + appCallTxn, err = testClient.FillUnsignedTxTemplate(someAddress, 0, 0, 0, appCallTxn) + a.NoError(err) + appCallTxnTxID, err := testClient.SignAndBroadcastTransaction(wh, nil, appCallTxn) + a.NoError(err) + _, err = waitForTransaction(t, testClient, someAddress, appCallTxnTxID, 30*time.Second) + a.NoError(err) + + // verify pending txn info of outer txn + submittedAppCallTxn, err := testClient.PendingTransactionInformationV2(appCallTxnTxID) + a.NoError(err) + a.Nil(submittedAppCallTxn.ApplicationIndex) + a.Nil(submittedAppCallTxn.AssetIndex) + a.NotNil(submittedAppCallTxn.InnerTxns) + a.Len(*submittedAppCallTxn.InnerTxns, 1) + + // verify pending txn info of inner txn + innerTxn := (*submittedAppCallTxn.InnerTxns)[0] + a.Nil(innerTxn.ApplicationIndex) + a.NotNil(innerTxn.AssetIndex) + createdAssetID := *innerTxn.AssetIndex + a.Greater(createdAssetID, uint64(0)) + + createdAssetInfo, err := testClient.AssetInformationV2(createdAssetID) + a.NoError(err) + a.Equal(createdAssetID, createdAssetInfo.Index) + a.Equal(createdAppID.Address().String(), createdAssetInfo.Params.Creator) + a.Equal(uint64(1000000), createdAssetInfo.Params.Total) + a.Equal(uint64(3), createdAssetInfo.Params.Decimals) + a.Equal("oz", *createdAssetInfo.Params.UnitName) + a.Equal("Gold", *createdAssetInfo.Params.Name) + a.Equal("https://gold.rush/", *createdAssetInfo.Params.Url) + expectedMetadata, err := hex.DecodeString("67f0cd61653bd34316160bc3f5cd3763c85b114d50d38e1f4e72c3b994411e7b") + a.NoError(err) + a.Equal(expectedMetadata, *createdAssetInfo.Params.MetadataHash) +}