Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1269 read only execute sc #1273

Merged
merged 4 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/swagger/server/restapi/resource/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ paths:
maxGas:
$ref: "#/definitions/Amount"
description: Maximum number of gas unit that a operation will be able consume.
default: 700000000 # DefaultGasLimit
coins:
#$ref: "#/definitions/Amount"
description: Set the coin amount that will be transferred to the smartContract.
Expand Down
2 changes: 1 addition & 1 deletion api/test/robot_tests/cmd/cmd.robot
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ POST /cmd/executeFunction with invalid address
Should Be Equal ${response.json()["code"]} Execute-0001
Should Contain
... ${response.json()["message"]}
... Error: callSC failed: calling EstimateGasCost for function
... Error: callSC failed: estimating Call SC gas cost for function
Should Contain
... ${response.json()["message"]}
... receiving execute_read_only_call with
Expand Down
5 changes: 2 additions & 3 deletions int/api/cmd/execute_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,15 @@ func (e *executeFunction) Handle(params operations.CmdExecuteFunctionParams) mid
fee = parsedFee
}

// convert maxGas to uint64
maxGas := uint64(sendOperation.DefaultGasLimitCallSC)
maxGas := uint64(0)

if string(params.Body.MaxGas) != "" {
parsedMaxGas, err := strconv.ParseUint(string(params.Body.MaxGas), 10, 64)
if err != nil {
return operations.NewCmdExecuteFunctionBadRequest().WithPayload(
&models.Error{
Code: errorInvalidMaxGas,
Message: "Error during amount conversion: " + err.Error(),
Message: "Error during max gas conversion: " + err.Error(),
})
}

Expand Down
17 changes: 11 additions & 6 deletions pkg/node/sendoperation/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"fmt"
)

// ReadOnlyCallParams is the struct used to send a read only callSC to the node.
type ReadOnlyCallParams struct {
MaxGas int `json:"max_gas"`
Coins string `json:"coins"`
Expand All @@ -15,13 +16,17 @@
CallerAddress string `json:"caller_address"`
}

// Read only call response (chatgpt4 generated).
type ReadOnlyCallResponse struct {
JSONRPC string `json:"jsonrpc"`
Result []ReadOnlyCallResult `json:"result"`
// ReadOnlyExecuteParams is the struct used to send a read only executeSC to the node.
type ReadOnlyExecuteParams struct {
MaxGas int `json:"max_gas"`
Coins string `json:"coins"`
Fee string `json:"fee"`
Address string `json:"address"`
Bytecode JSONableSlice `json:"bytecode"`
OperationDatastore JSONableSlice `json:"operation_datastore"`
}

type ReadOnlyCallResult struct {
type ReadOnlyResult struct {
ExecutedAt Timestamp `json:"executed_at"`
Result Result `json:"result"`
OutputEvents []Event `json:"output_events"`
Expand Down Expand Up @@ -66,7 +71,7 @@
return nil
}

return nil // Or return an error if neither key is present
return nil

Check warning on line 74 in pkg/node/sendoperation/interfaces.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/interfaces.go#L74

Added line #L74 was not covered by tests
}

type Timestamp struct {
Expand Down
95 changes: 93 additions & 2 deletions pkg/node/sendoperation/readonlycall.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
fee string,
callerAddr string,
client *node.Client,
) (*ReadOnlyCallResult, error) {
) (*ReadOnlyResult, error) {

Check warning on line 66 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L66

Added line #L66 was not covered by tests
readOnlyCallParams := [][]ReadOnlyCallParams{
{
ReadOnlyCallParams{
Expand Down Expand Up @@ -95,7 +95,7 @@
)
}

var resp []ReadOnlyCallResult
var resp []ReadOnlyResult

Check warning on line 98 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L98

Added line #L98 was not covered by tests

err = rawResponse.GetObject(&resp)
if err != nil {
Expand All @@ -109,3 +109,94 @@

return &resp[0], nil
}

func EstimateGasCostExecuteSC(
nickname string,
contract []byte,
datastore []byte,
maxCoins uint64,
fee uint64,
client *node.Client,
) (uint64, error) {
acc, err := wallet.Fetch(nickname)
if err != nil {
return 0, fmt.Errorf("loading wallet '%s': %w", nickname, err)
}

Check warning on line 124 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L120-L124

Added lines #L120 - L124 were not covered by tests

coinsString, err := NanoToMas(maxCoins)
if err != nil {
return 0, fmt.Errorf("converting maxCoins to mas: %w", err)
}

Check warning on line 129 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L126-L129

Added lines #L126 - L129 were not covered by tests

feeString, err := NanoToMas(fee)
if err != nil {
return 0, fmt.Errorf("converting fee to mas: %w", err)
}

Check warning on line 134 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L131-L134

Added lines #L131 - L134 were not covered by tests

result, err := ReadOnlyExecuteSC(contract, datastore, coinsString, feeString, acc.Address, client)
if err != nil {
return 0, fmt.Errorf("ReadOnlyExecuteSC error: %w, caller address is %s", err, acc.Address)
}

Check warning on line 139 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L136-L139

Added lines #L136 - L139 were not covered by tests

estimatedGasCost := uint64(result.GasCost)

return addXPercentage(estimatedGasCost, PercentageGasLimit), nil

Check warning on line 143 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L141-L143

Added lines #L141 - L143 were not covered by tests
}

// ReadOnlyExecuteSC calls execute_read_only_bytecode jsonrpc method.
// coins and fee must be in MAS.
func ReadOnlyExecuteSC(
contract []byte,
datastore []byte,
coins string,
fee string,
callerAddr string,
client *node.Client,
) (*ReadOnlyResult, error) {
if datastore == nil {
datastore = []byte{0}
}

Check warning on line 158 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L155-L158

Added lines #L155 - L158 were not covered by tests

readOnlyExecuteParams := [][]ReadOnlyExecuteParams{
{
ReadOnlyExecuteParams{
Coins: coins,
MaxGas: MaxGasAllowedExecuteSC,
Fee: fee,
Address: callerAddr,
Bytecode: contract,
OperationDatastore: datastore,
},
},
}

rawResponse, err := client.RPCClient.Call(
context.Background(),
"execute_read_only_bytecode",
readOnlyExecuteParams,
)
if err != nil {
return nil, fmt.Errorf("calling execute_read_only_bytecode jsonrpc: %w", err)
}

Check warning on line 180 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L160-L180

Added lines #L160 - L180 were not covered by tests

if rawResponse.Error != nil {
return nil, fmt.Errorf(
"receiving execute_read_only_bytecode response: %w, %v",
rawResponse.Error,
fmt.Sprint(rawResponse.Error.Data),
)
}

Check warning on line 188 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L182-L188

Added lines #L182 - L188 were not covered by tests

var resp []ReadOnlyResult

err = rawResponse.GetObject(&resp)
if err != nil {
return nil, fmt.Errorf("parsing execute_read_only_bytecode jsonrpc response '%+v': %w", rawResponse, err)
}

Check warning on line 195 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L190-L195

Added lines #L190 - L195 were not covered by tests

if resp[0].Result.Error != "" {
return nil, fmt.Errorf("ReadOnlyExecuteSC error: %s, caller address is %s", resp[0].Result.Error, callerAddr)
}

Check warning on line 199 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L197-L199

Added lines #L197 - L199 were not covered by tests

return &resp[0], nil

Check warning on line 201 in pkg/node/sendoperation/readonlycall.go

View check run for this annotation

Codecov / codecov/patch

pkg/node/sendoperation/readonlycall.go#L201

Added line #L201 was not covered by tests
}
3 changes: 1 addition & 2 deletions pkg/node/sendoperation/sendoperation.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import (
)

const (
DefaultGasLimitExecuteSC = 1_000_000_000
MaxGasAllowedExecuteSC = 3_980_167_295
MaxGasAllowedCallSC = 4_294_167_295
DefaultGasLimitCallSC = 700_000_000
DefaultExpiryInSlot = 3
DefaultFee = 0
accountCreationStorageCost = 1_000_000
Expand Down
2 changes: 1 addition & 1 deletion pkg/onchain/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func SetRecord(
"dns1_setResolver",
rec,
sendoperation.DefaultFee,
sendoperation.DefaultGasLimitCallSC,
0,
sendoperation.OneMassa,
sendoperation.DefaultExpiryInSlot,
false,
Expand Down
21 changes: 14 additions & 7 deletions pkg/onchain/sc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"regexp"
"strings"

"github.com/massalabs/station/pkg/logger"
"github.com/massalabs/station/pkg/node"
sendOperation "github.com/massalabs/station/pkg/node/sendoperation"
"github.com/massalabs/station/pkg/node/sendoperation/callsc"
Expand Down Expand Up @@ -37,14 +36,12 @@ func CallFunction(
description string,
) (*OperationWithEventResponse, error) {
// Calibrate max_gas
if maxGas == sendOperation.DefaultGasLimitCallSC || maxGas == 0 {
if maxGas == 0 {
estimatedGasCost, err := sendOperation.EstimateGasCostCallSC(nickname, addr, function, parameter, coins, fee, client)
if err != nil {
return nil, fmt.Errorf("calling EstimateGasCost for function '%s' at '%s': %w", function, addr, err)
return nil, fmt.Errorf("estimating Call SC gas cost for function '%s' at '%s': %w", function, addr, err)
}

logger.Debugf("Estimated gas cost for %s at %s: %d", function, addr, estimatedGasCost)

maxGas = estimatedGasCost
}

Expand Down Expand Up @@ -109,7 +106,7 @@ func CallFunctionSuccess(
// The smart contract is deployed with the given account nickname.
func DeploySC(client *node.Client,
nickname string,
gasLimit uint64,
maxGas uint64,
maxCoins uint64,
fee uint64,
expiry uint64,
Expand All @@ -119,9 +116,19 @@ func DeploySC(client *node.Client,
signer signer.Signer,
description string,
) (*sendOperation.OperationResponse, []node.Event, error) {
// Calibrate max_gas
if maxGas == 0 {
estimatedGasCost, err := sendOperation.EstimateGasCostExecuteSC(nickname, contract, datastore, maxCoins, fee, client)
if err != nil {
return nil, nil, fmt.Errorf("estimating Execute SC gas cost: %w", err)
}

maxGas = estimatedGasCost
}

exeSC := executesc.New(
contract,
gasLimit,
maxGas,
maxCoins,
datastore)

Expand Down
6 changes: 3 additions & 3 deletions pkg/onchain/website/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func PrepareForUpload(
operationResponse, events, err := onchain.DeploySC(
client,
nickname,
sendOperation.DefaultGasLimitExecuteSC,
0,
uint64(totalStorageCost),
sendOperation.DefaultFee,
sendOperation.DefaultExpiryInSlot,
Expand Down Expand Up @@ -189,7 +189,7 @@ func upload(
"appendBytesToWebsite",
params,
sendOperation.DefaultFee,
sendOperation.DefaultGasLimitCallSC,
0,
uint64(uploadCost),
sendOperation.DefaultExpiryInSlot,
false,
Expand Down Expand Up @@ -287,7 +287,7 @@ func uploadMissedChunks(
"appendBytesToWebsite",
params,
sendOperation.DefaultFee,
sendOperation.DefaultGasLimitCallSC,
0,
uint64(uploadCost),
sendOperation.DefaultExpiryInSlot,
false,
Expand Down
Loading