Skip to content

Commit

Permalink
Merge pull request #393 from multiversx/vm_query_with_coordinates
Browse files Browse the repository at this point in the history
Block coordinates on vm query
  • Loading branch information
sstanculeanu authored Aug 25, 2023
2 parents dd0b54b + 5b2454a commit af6ea27
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 69 deletions.
45 changes: 33 additions & 12 deletions api/groups/baseVmValuesGroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/data/vm"
apiErrors "github.com/multiversx/mx-chain-proxy-go/api/errors"
"github.com/multiversx/mx-chain-proxy-go/api/shared"
"github.com/multiversx/mx-chain-proxy-go/common"
"github.com/multiversx/mx-chain-proxy-go/data"
)

Expand Down Expand Up @@ -67,7 +69,7 @@ func (group *vmValuesGroup) getInt(context *gin.Context) {
}

func (group *vmValuesGroup) doGetVMValue(context *gin.Context, asType vm.ReturnDataKind) {
vmOutput, err := group.doExecuteQuery(context)
vmOutput, blockInfo, err := group.doExecuteQuery(context)

if err != nil {
returnBadRequest(context, "doGetVMValue", err)
Expand All @@ -80,38 +82,43 @@ func (group *vmValuesGroup) doGetVMValue(context *gin.Context, asType vm.ReturnD
return
}

returnOkResponse(context, returnData)
returnOkResponse(context, returnData, blockInfo)
}

// executeQuery returns the data as string
func (group *vmValuesGroup) executeQuery(context *gin.Context) {
vmOutput, err := group.doExecuteQuery(context)
vmOutput, blockInfo, err := group.doExecuteQuery(context)
if err != nil {
returnBadRequest(context, "executeQuery", err)
return
}

returnOkResponse(context, vmOutput)
returnOkResponse(context, vmOutput, blockInfo)
}

func (group *vmValuesGroup) doExecuteQuery(context *gin.Context) (*vm.VMOutputApi, error) {
func (group *vmValuesGroup) doExecuteQuery(context *gin.Context) (*vm.VMOutputApi, data.BlockInfo, error) {
request := VMValueRequest{}
err := context.ShouldBindJSON(&request)
if err != nil {
return nil, apiErrors.ErrInvalidJSONRequest
return nil, data.BlockInfo{}, apiErrors.ErrInvalidJSONRequest
}

command, err := createSCQuery(&request)
if err != nil {
return nil, err
return nil, data.BlockInfo{}, err
}

vmOutput, err := group.facade.ExecuteSCQuery(command)
command.BlockNonce, command.BlockHash, err = extractBlockCoordinates(context)
if err != nil {
return nil, err
return nil, data.BlockInfo{}, err
}

return vmOutput, nil
vmOutput, blockInfo, err := group.facade.ExecuteSCQuery(command)
if err != nil {
return nil, data.BlockInfo{}, err
}

return vmOutput, blockInfo, nil
}

func createSCQuery(request *VMValueRequest) (*data.SCQuery, error) {
Expand All @@ -136,11 +143,25 @@ func createSCQuery(request *VMValueRequest) (*data.SCQuery, error) {
}, nil
}

func extractBlockCoordinates(context *gin.Context) (core.OptionalUint64, []byte, error) {
blockNonce, err := parseUint64UrlParam(context, common.UrlParameterBlockNonce)
if err != nil {
return core.OptionalUint64{}, nil, fmt.Errorf("%w for block nonce", err)
}

blockHash, err := parseHexBytesUrlParam(context, common.UrlParameterBlockHash)
if err != nil {
return core.OptionalUint64{}, nil, fmt.Errorf("%w for block hash", err)
}

return blockNonce, blockHash, nil
}

func returnBadRequest(context *gin.Context, errScope string, err error) {
message := fmt.Sprintf("%s: %s", errScope, err)
shared.RespondWith(context, http.StatusBadRequest, nil, message, data.ReturnCodeRequestError)
}

func returnOkResponse(context *gin.Context, dataToReturn interface{}) {
shared.RespondWith(context, http.StatusOK, gin.H{"data": dataToReturn}, "", data.ReturnCodeSuccess)
func returnOkResponse(context *gin.Context, dataToReturn interface{}, blockInfo interface{}) {
shared.RespondWith(context, http.StatusOK, gin.H{"data": dataToReturn, "blockInfo": blockInfo}, "", data.ReturnCodeSuccess)
}
73 changes: 54 additions & 19 deletions api/groups/baseVmValuesGroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"math/big"
"net/http"
"net/http/httptest"
"strconv"
"testing"

"github.com/multiversx/mx-chain-core-go/data/vm"
Expand All @@ -29,7 +30,8 @@ type simpleResponse struct {
}

type vmOutputResponse struct {
Data *vm.VMOutputApi `json:"data"`
Data *vm.VMOutputApi `json:"data"`
BlockInfo data.BlockInfo `json:"blockInfo"`
}

type vmOutputGenericResponse struct {
Expand All @@ -53,10 +55,10 @@ func TestGetHex_ShouldWork(t *testing.T) {
valueBuff, _ := hex.DecodeString("DEADBEEF")

facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return &vm.VMOutputApi{
ReturnData: [][]byte{valueBuff},
}, nil
}, data.BlockInfo{}, nil
},
}

Expand All @@ -80,10 +82,10 @@ func TestGetString_ShouldWork(t *testing.T) {
valueBuff := "DEADBEEF"

facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return &vm.VMOutputApi{
ReturnData: [][]byte{[]byte(valueBuff)},
}, nil
}, data.BlockInfo{}, nil
},
}

Expand All @@ -107,12 +109,12 @@ func TestGetInt_ShouldWork(t *testing.T) {
value := "1234567"

facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
returnData := big.NewInt(0)
returnData.SetString(value, 10)
return &vm.VMOutputApi{
ReturnData: [][]byte{returnData.Bytes()},
}, nil
}, data.BlockInfo{}, nil
},
}

Expand All @@ -134,11 +136,11 @@ func TestQuery_ShouldWork(t *testing.T) {
t.Parallel()

facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {

return &vm.VMOutputApi{
ReturnData: [][]byte{big.NewInt(42).Bytes()},
}, nil
}, data.BlockInfo{}, nil
},
}

Expand All @@ -156,6 +158,39 @@ func TestQuery_ShouldWork(t *testing.T) {
require.Equal(t, int64(42), big.NewInt(0).SetBytes(response.Data.Data.ReturnData[0]).Int64())
}

func TestQuery_ShouldWorkWithCoordinates(t *testing.T) {
t.Parallel()

providedNonce := uint64(123)
providedBlockInfo := data.BlockInfo{
Nonce: providedNonce,
Hash: "block hash",
RootHash: "block rootHash",
}
facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
require.Equal(t, providedNonce, query.BlockNonce.Value)
return &vm.VMOutputApi{
ReturnData: [][]byte{big.NewInt(42).Bytes()},
}, providedBlockInfo, nil
},
}

request := groups.VMValueRequest{
ScAddress: DummyScAddress,
FuncName: "function",
Args: []string{},
}

response := vmOutputGenericResponse{}
statusCode := doPost(t, facade, "/vm-values/query?blockNonce="+strconv.FormatUint(providedNonce, 10), request, &response)

require.Equal(t, http.StatusOK, statusCode)
require.Equal(t, "", response.Error)
require.Equal(t, int64(42), big.NewInt(0).SetBytes(response.Data.Data.ReturnData[0]).Int64())
require.Equal(t, providedBlockInfo, response.Data.BlockInfo)
}

func TestCreateSCQuery_ArgumentIsNotHexShouldErr(t *testing.T) {
request := groups.VMValueRequest{
ScAddress: DummyScAddress,
Expand All @@ -173,8 +208,8 @@ func TestAllRoutes_FacadeErrorsShouldErr(t *testing.T) {

errExpected := errors.New("some random error")
facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
return nil, errExpected
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return nil, data.BlockInfo{}, errExpected
},
}

Expand All @@ -192,8 +227,8 @@ func TestAllRoutes_WhenBadArgumentsShouldErr(t *testing.T) {

errExpected := errors.New("not a valid hex string")
facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
return &vm.VMOutputApi{}, nil
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return &vm.VMOutputApi{}, data.BlockInfo{}, nil
},
}

Expand All @@ -211,8 +246,8 @@ func TestAllRoutes_WhenNoVMReturnDataShouldErr(t *testing.T) {

errExpected := errors.New("no return data")
facade := mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
return &vm.VMOutputApi{}, nil
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return &vm.VMOutputApi{}, data.BlockInfo{}, nil
},
}

Expand All @@ -229,8 +264,8 @@ func TestAllRoutes_WhenBadJsonShouldErr(t *testing.T) {
t.Parallel()

facade := mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
return &vm.VMOutputApi{}, nil
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
return &vm.VMOutputApi{}, data.BlockInfo{}, nil
},
}

Expand All @@ -241,10 +276,10 @@ func TestAllRoutes_WithSameScStateAndShouldBySyncedFilled(t *testing.T) {
t.Parallel()

facade := &mock.FacadeStub{
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, e error) {
ExecuteSCQueryHandler: func(query *data.SCQuery) (vmOutput *vm.VMOutputApi, blockInfo data.BlockInfo, e error) {
require.True(t, query.ShouldBeSynced)
require.True(t, query.SameScState)
return &vm.VMOutputApi{}, nil
return &vm.VMOutputApi{}, data.BlockInfo{}, nil
},
}

Expand Down
2 changes: 1 addition & 1 deletion api/groups/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type ValidatorFacadeHandler interface {

// VmValuesFacadeHandler interface defines methods that can be used from the facade
type VmValuesFacadeHandler interface {
ExecuteSCQuery(*data.SCQuery) (*vm.VMOutputApi, error)
ExecuteSCQuery(*data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error)
}

// ActionsFacadeHandler interface defines methods that can be used from the facade
Expand Down
4 changes: 2 additions & 2 deletions api/mock/facadeStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type FacadeStub struct {
SendMultipleTransactionsHandler func(txs []*data.Transaction) (data.MultipleTransactionsResponseData, error)
SimulateTransactionHandler func(tx *data.Transaction, checkSignature bool) (*data.GenericAPIResponse, error)
SendUserFundsCalled func(receiver string, value *big.Int) error
ExecuteSCQueryHandler func(query *data.SCQuery) (*vm.VMOutputApi, error)
ExecuteSCQueryHandler func(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error)
GetHeartbeatDataHandler func() (*data.HeartbeatResponse, error)
ValidatorStatisticsHandler func() (map[string]*data.ValidatorApiResponse, error)
TransactionCostRequestHandler func(tx *data.Transaction) (*data.TxCostResponseData, error)
Expand Down Expand Up @@ -413,7 +413,7 @@ func (f *FacadeStub) SendUserFunds(receiver string, value *big.Int) error {
}

// ExecuteSCQuery -
func (f *FacadeStub) ExecuteSCQuery(query *data.SCQuery) (*vm.VMOutputApi, error) {
func (f *FacadeStub) ExecuteSCQuery(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error) {
return f.ExecuteSCQueryHandler(query)
}

Expand Down
6 changes: 5 additions & 1 deletion data/vmValues.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package data

import (
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/data/vm"
)

// VmValuesResponseData follows the format of the data field in an API response for a VM values query
type VmValuesResponseData struct {
Data *vm.VMOutputApi `json:"data"`
Data *vm.VMOutputApi `json:"data"`
BlockInfo BlockInfo `json:"blockInfo"`
}

// ResponseVmValue defines a wrapper over string containing returned data in hex format
Expand Down Expand Up @@ -36,4 +38,6 @@ type SCQuery struct {
SameScState bool `json:"sameScState"`
ShouldBeSynced bool `json:"shouldBeSynced"`
Arguments [][]byte
BlockNonce core.OptionalUint64
BlockHash []byte
}
2 changes: 1 addition & 1 deletion facade/baseFacade.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func (epf *ProxyFacade) getNetworkConfig() (*data.NetworkConfig, error) {
}

// ExecuteSCQuery retrieves data from existing SC trie through the use of a VM
func (epf *ProxyFacade) ExecuteSCQuery(query *data.SCQuery) (*vm.VMOutputApi, error) {
func (epf *ProxyFacade) ExecuteSCQuery(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error) {
return epf.scQueryService.ExecuteQuery(query)
}

Expand Down
6 changes: 3 additions & 3 deletions facade/baseFacade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,9 +570,9 @@ func TestProxyFacade_GetDataValue(t *testing.T) {
&mock.AccountProcessorStub{},
&mock.TransactionProcessorStub{},
&mock.SCQueryServiceStub{
ExecuteQueryCalled: func(query *data.SCQuery) (*vm.VMOutputApi, error) {
ExecuteQueryCalled: func(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error) {
wasCalled = true
return &vm.VMOutputApi{}, nil
return &vm.VMOutputApi{}, data.BlockInfo{}, nil
},
},
&mock.NodeGroupProcessorStub{},
Expand All @@ -588,7 +588,7 @@ func TestProxyFacade_GetDataValue(t *testing.T) {
&mock.AboutInfoProcessorStub{},
)

_, _ = epf.ExecuteSCQuery(nil)
_, _, _ = epf.ExecuteSCQuery(nil)

assert.True(t, wasCalled)
}
Expand Down
2 changes: 1 addition & 1 deletion facade/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type ProofProcessor interface {

// SCQueryService defines how data should be get from a SC account
type SCQueryService interface {
ExecuteQuery(query *data.SCQuery) (*vm.VMOutputApi, error)
ExecuteQuery(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error)
}

// NodeGroupProcessor defines what a node group processor should do
Expand Down
4 changes: 2 additions & 2 deletions facade/mock/scQueryServiceStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (

// SCQueryServiceStub -
type SCQueryServiceStub struct {
ExecuteQueryCalled func(*data.SCQuery) (*vm.VMOutputApi, error)
ExecuteQueryCalled func(*data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error)
}

// ExecuteQuery -
func (serviceStub *SCQueryServiceStub) ExecuteQuery(query *data.SCQuery) (*vm.VMOutputApi, error) {
func (serviceStub *SCQueryServiceStub) ExecuteQuery(query *data.SCQuery) (*vm.VMOutputApi, data.BlockInfo, error) {
return serviceStub.ExecuteQueryCalled(query)
}
2 changes: 1 addition & 1 deletion process/esdtSupplyProcessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (esp *esdtSupplyProcessor) getInitialSupplyFromMeta(token string) (*big.Int
Arguments: [][]byte{[]byte(token)},
}

res, err := esp.scQueryProc.ExecuteQuery(scQuery)
res, _, err := esp.scQueryProc.ExecuteQuery(scQuery)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit af6ea27

Please sign in to comment.