Skip to content

Commit

Permalink
add serialized datastore and clean executeSC.message() method
Browse files Browse the repository at this point in the history
  • Loading branch information
pivilartisant committed Nov 29, 2024
1 parent 2de2485 commit 027ba18
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 232 deletions.
16 changes: 1 addition & 15 deletions int/api/cmd/deploySC.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,14 @@ func (d *deploySC) Handle(params operations.CmdDeploySCParams) middleware.Respon
Message: err.Error(),
})
}

// smartr contract dataStore parameters
_parameters, err := base64.StdEncoding.DecodeString(params.Body.Parameters)
parametersReader := bytes.NewReader(_parameters)
parameters, err := io.ReadAll(parametersReader)
if err != nil {
return operations.NewCmdDeploySCBadRequest().
WithPayload(
&models.Error{
Code: err.Error(),
Message: err.Error(),
})
}

operationResponse, events, err := onchain.DeploySC(
d.networkInfos,
params.Body.Nickname,
sendoperation.MaxGasAllowedExecuteSC,
*params.Body.MaxCoins, // maxCoins
*params.Body.Coins, // smart contract deployment cost
sendoperation.DefaultExpiryInSlot,
parameters,
[]byte{}, // TODO add smart contract parameters
smartContractByteCode,
deployerByteCode,
sendoperation.OperationBatch{NewBatch: false, CorrelationID: ""},
Expand Down
2 changes: 1 addition & 1 deletion pkg/convert/byteConverter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const (
)

// Encode uint64 to byte array.
func U64ToBytes(nb int) (bytes []byte) {
func U64ToBytes(nb uint64) (bytes []byte) {
u64 := uint64(nb)

Check failure on line 17 in pkg/convert/byteConverter.go

View workflow job for this annotation

GitHub Actions / lint

unnecessary conversion (unconvert)
bytes = make([]byte, BytesPerUint64)
binary.LittleEndian.PutUint64(bytes, u64)
Expand Down
20 changes: 1 addition & 19 deletions pkg/node/sendoperation/executesc/executesc.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@ func (e *ExecuteSC) Content() (interface{}, error) {
}, nil
}

// To date the datastore sent by the deploySC endpoint is always serialized.
// However the web on chain features make use of a non-serialized, nil datastore.
// Hence here we check that if datastore is not nil (and it means it comes from the deploySC endpoint)
// we do not encode it further but rather send it as is to the node.

Check failure on line 63 in pkg/node/sendoperation/executesc/executesc.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default (gci)
func (e *ExecuteSC) Message() []byte {
msg := make([]byte, 0)
buf := make([]byte, binary.MaxVarintLen64)
Expand All @@ -84,24 +81,9 @@ func (e *ExecuteSC) Message() []byte {
msg = append(msg, buf[:nbBytes]...)
msg = append(msg, e.data...)

// datastore
// If the datastore is not nil, no need to serialize it.
if e.dataStore != nil {
msg = append(msg, e.dataStore...)

return msg
}

Check failure on line 84 in pkg/node/sendoperation/executesc/executesc.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default (gci)
// If the datastore is nil, we need to serialize it.
// Number of entries in the datastore.
nbBytes = binary.PutUvarint(buf, uint64(len(e.dataStore)))
msg = append(msg, buf[:nbBytes]...)
msg = append(msg, e.dataStore...)

Check failure on line 86 in pkg/node/sendoperation/executesc/executesc.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
for key, value := range e.dataStore {
compactAndAppendBytes(&msg, key)
compactAndAppendBytes(&msg, value)
}

Check failure on line 87 in pkg/node/sendoperation/executesc/executesc.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default (gci)
return msg
}
Expand Down
1 change: 0 additions & 1 deletion pkg/node/sendoperation/sendoperation.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ func Call(
}

content := createOperationContent(operationBatch, description, msgB64, chainID)
// logger.Infof("Operation content: %s", content)

res, err := signer.Sign(nickname, []byte(content))
if err != nil {
Expand Down
225 changes: 45 additions & 180 deletions pkg/onchain/datastore.go
Original file line number Diff line number Diff line change
@@ -1,207 +1,72 @@
package onchain

import (
"fmt"
"strings"
"bytes"
"encoding/binary"

"github.com/massalabs/station/pkg/convert"
)

/**
------------------------------------------------------------------------------------------------------------------------
TYPES
------------------------------------------------------------------------------------------------------------------------
*/
type DatastoreContract struct {
Data []byte
Args []byte
Coins uint64
}

type JSONableSliceMap []byte


type DatastoreSCEntry struct {
Entry DatastoreData `json:"entry"`
Bytes DatastoreData `json:"bytes"`
}

type DatastoreData struct {
Entry JSONableSliceMap `json:"entry"`
Bytes JSONableSliceMap `json:"bytes"`
type datastoreEntry struct {
Key []byte
Value []byte
}

func (u JSONableSliceMap) MarshalJSON() ([]byte, error) {
var result string
if u == nil {
result = "null"
} else {
result = strings.Join(strings.Fields(fmt.Sprintf("%d", u)), ",")
}
// populateDatastore creates and serializes a datastore for the given contract.
func populateDatastore(contract DatastoreContract) ([]byte, error) {
var datastore []datastoreEntry
numberOfContracts := convert.U64ToBytes(1)
datastore = append(datastore, datastoreEntry{Key: []byte{0}, Value: numberOfContracts})

return []byte(result), nil
}
contractKey := []byte{1}
datastore = append(datastore, datastoreEntry{Key: contractKey, Value: contract.Data})

/**
------------------------------------------------------------------------------------------------------------------------
UTILITY FUNCTIONS
------------------------------------------------------------------------------------------------------------------------
*/
argsKey := []byte{2}
datastore = append(datastore, datastoreEntry{Key: argsKey, Value: contract.Args})

/**
* Used to create a new datastore entry object.
*/
func NewDeployScDatastoreData(entry []byte, bytes []byte) DatastoreData {
return DatastoreData{
Entry: entry,
Bytes: bytes,
}
}
coinsKey := []byte{3}
datastore = append(datastore, datastoreEntry{Key: coinsKey, Value: convert.U64ToBytes(contract.Coins)})

/**
use to create a map of each datastore entry
*/
func NewDeployScDatastoreEntry(entry DatastoreData, bytes DatastoreData) DatastoreSCEntry {
return DatastoreSCEntry{
Entry: entry,
Bytes: bytes,
// Serialize the datastore
serializedDatastore, err := SerializeDatastore(datastore)
if err != nil {
return nil, err
}
}

/**
------------------------------------------------------------------------------------------------------------------------
KEY GENERATION FUNCTIONS
------------------------------------------------------------------------------------------------------------------------
*/

/**
* Generates a key for coin data in the datastore.
*
* @param offset - The offset to use when generating the key.
* @returns A Uint8Array representing the key.
*/
func coinsKey(offset int) []byte {
return convert.U64ToBytes(offset+1)
}

/**
* Generates a key for args data in the datastore.
*
* @param offset - The offset to use when generating the key.
* @returns A Uint8Array representing the key.
*/
func argsKey(offset int) []byte {
return convert.U64ToBytes(offset+1)
return serializedDatastore, nil
}

/**
* Generates a key for contract data in the datastore.
*
* @param offset - The offset to use when generating the key.
* @returns A Uint8Array representing the key.
*/
func contractKey(offset int) []byte {
return convert.U64ToBytes(offset+1)
}


/**
------------------------------------------------------------------------------------------------------------------------
POPULATE DATASTORE FUNCTION
------------------------------------------------------------------------------------------------------------------------
--- Datastore Format ---
[[key],[value]]
// SerializeDatastore serializes the datastore into a []byte array.
func SerializeDatastore(datastore []datastoreEntry) ([]byte, error) {
var buffer bytes.Buffer

===
[
[
[KEY_BYTE_ARRAY_LENGTH], [KEY_BYTE_ARRAY_DATA]]
],
[
[VALUE_BYTE_ARRAY_LENGTH], [VALUE_BYTE_ARRAY_DATA]
]
]
*/

/**
* Populates the datastore with the contracts.
*
* @remarks
* This function is to be used in conjunction with the deployer smart contract.
* The deployer smart contract expects to have an execution datastore in a specific state.
* This function populates the datastore according to that expectation.
*
* @param contracts - The contracts to populate the datastore with.
*
* @returns The populated datastore.
*/
func populateDatastore(contract DatastoreContract) ([]DatastoreSCEntry, error) {
//TODO bug -> four empty datastore entries

// IMPORTANT we assume ATM that there is only one contract to deploy

// number of entries in the datastore: number of contracts, and the contract data, args, and coins
datastore := []DatastoreSCEntry{}
buf := make([]byte, binary.MaxVarintLen64)
// Encode the number of key-value pairs
datastoreSize := uint64(len(datastore))
uDatastoreSize := binary.PutUvarint(buf, datastoreSize)

// contractsNumberKey := []byte{0}
contractlength := convert.U64ToBytes(1) // assuming there is one contract to deploy

//number of contracts to deploy
numberOfContracts := NewDeployScDatastoreEntry(
NewDeployScDatastoreData(
convert.U64ToBytes(len(convert.U64ToBytes(1))), // length of the key
convert.U64ToBytes(1)), // value in bytes
NewDeployScDatastoreData(
convert.U64ToBytes(len(contractlength)),
convert.U64ToBytes(1),
))

_dataStore := append(datastore, numberOfContracts)

//byteCode of the smartContract to be appended to the deployer
contractData := NewDeployScDatastoreEntry(
NewDeployScDatastoreData(
convert.U64ToBytes(len(contractKey(0))),
contractKey(0),
),
NewDeployScDatastoreData(
convert.U64ToBytes(len(contract.Data)),
contract.Data,
),
)

_dataStore = append(_dataStore, contractData)


contractArgs := NewDeployScDatastoreEntry(
NewDeployScDatastoreData(
convert.U64ToBytes(len(argsKey(0))),
argsKey(0),
),
NewDeployScDatastoreData(
convert.U64ToBytes(len(contract.Args)),
contract.Args,
),
)

_dataStore = append(_dataStore, contractArgs)

contractCoins := NewDeployScDatastoreEntry(
NewDeployScDatastoreData(
convert.U64ToBytes(len(coinsKey(0))),
coinsKey(0),
),
NewDeployScDatastoreData(
convert.U64ToBytes(len(convert.U64ToBytes(int(contract.Coins)))),
convert.U64ToBytes(int(contract.Coins)),
),
)

_dataStore = append(_dataStore, contractCoins)
buffer.Write(buf[:uDatastoreSize])

// Encode each key-value pair
for _, entry := range datastore {
// Encode key
keyLength := uint64(len(entry.Key))
uKeyLength := binary.PutUvarint(buf, keyLength)
buffer.Write(buf[:uKeyLength])
buffer.Write(entry.Key)

// Encode value
valueLength := uint64(len(entry.Value))
uValueLength := binary.PutUvarint(buf, valueLength)
buffer.Write(buf[:uValueLength])
buffer.Write(entry.Value)
}

return _dataStore, nil
return buffer.Bytes(), nil
}

Loading

0 comments on commit 027ba18

Please sign in to comment.