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

Create and pass emulator config as an object + benchmark #287

Merged
merged 1 commit into from
Aug 13, 2024
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
23 changes: 22 additions & 1 deletion lib/emulator-extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ extern "C" {
*/
EMULATOR_EXPORT void *transaction_emulator_create(const char *config_params_boc, int vm_log_verbosity);

/**
* @brief Creates Config object from base64 encoded BoC
* @param config_params_boc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
* @return Pointer to Config object or nullptr in case of error
*/
EMULATOR_EXPORT void *emulator_config_create(const char *config_params_boc);

/**
* @brief Set unixtime for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
Expand Down Expand Up @@ -50,7 +57,7 @@ EMULATOR_EXPORT bool transaction_emulator_set_rand_seed(void *transaction_emulat
EMULATOR_EXPORT bool transaction_emulator_set_ignore_chksig(void *transaction_emulator, bool ignore_chksig);

/**
* @brief Set unixtime for emulation
* @brief Set config for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param config_boc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
* @return true in case of success, false in case of error
Expand Down Expand Up @@ -127,6 +134,14 @@ EMULATOR_EXPORT bool tvm_emulator_set_libraries(void *tvm_emulator, const char *
*/
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);

/**
* @brief Set config for TVM emulator
* @param tvm_emulator Pointer to TVM emulator
* @param config Pointer to Config object
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool tvm_emulator_set_config_object(void* tvm_emulator, void* config);

/**
* @brief Set TVM gas limit
* @param tvm_emulator Pointer to TVM emulator
Expand Down Expand Up @@ -212,6 +227,12 @@ EMULATOR_EXPORT const char *tvm_emulator_send_internal_message(void *tvm_emulato
*/
EMULATOR_EXPORT void tvm_emulator_destroy(void *tvm_emulator);

/**
* @brief Destroy Config object
* @param tvm_emulator Pointer to Config object
*/
EMULATOR_EXPORT void emulator_config_destroy(void *config);

#ifdef __cplusplus
} // extern "C"
#endif
50 changes: 47 additions & 3 deletions tvm/tvmExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type Emulator struct {
ignoreLibraryCells bool
}

type Config struct {
data unsafe.Pointer
}

type Options struct {
verbosityLevel txemulator.VerbosityLevel
balance int64
Expand All @@ -46,6 +50,7 @@ type Options struct {
lazyC7 bool
libResolver libResolver
ignoreLibraryCells bool
config *Config
}

type Option func(o *Options)
Expand All @@ -63,6 +68,12 @@ func WithBalance(balance int64) Option {
}
}

func WithConfig(config *Config) Option {
return func(o *Options) {
o.config = config
}
}

// WithLibrariesBase64 provides a list of available libraries as a base64 string.
// Take a look at LibrariesToBase64() to convert a map with libraries to such a string.
func WithLibrariesBase64(libraries string) Option {
Expand Down Expand Up @@ -115,9 +126,12 @@ func NewEmulator(code, data, config *boc.Cell, opts ...Option) (*Emulator, error
if err != nil {
return nil, err
}
configBoc, err := config.ToBocBase64()
if err != nil {
return nil, err
configBoc := ""
if config != nil {
configBoc, err = config.ToBocBase64()
if err != nil {
return nil, err
}
}
return NewEmulatorFromBOCsBase64(codeBoc, dataBoc, configBoc, opts...)
}
Expand Down Expand Up @@ -153,6 +167,11 @@ func NewEmulatorFromBOCsBase64(code, data, config string, opts ...Option) (*Emul
return nil, err
}
}
if options.config != nil {
if err := e.setConfig(options.config); err != nil {
return nil, err
}
}
runtime.SetFinalizer(&e, destroy)
return &e, nil
}
Expand All @@ -179,6 +198,20 @@ func SetVerbosityLevel(level int) error {
return nil
}

func createConfig(configRaw string) (*Config, error) {
config := C.emulator_config_create(C.CString(configRaw))
if config == nil {
return nil, fmt.Errorf("failed to create config")
}
c := Config{data: config}
runtime.SetFinalizer(&c, destroyConfig)
return &c, nil
}

func destroyConfig(c *Config) {
C.emulator_config_destroy(c.data)
}

func (e *Emulator) SetBalance(balance int64) {
e.balance = uint64(balance)
}
Expand Down Expand Up @@ -209,13 +242,24 @@ func (e *Emulator) SetGasLimit(gasLimit int64) error {
return nil
}

func (e *Emulator) setConfig(config *Config) error {
ok := C.tvm_emulator_set_config_object(e.emulator, config.data)
if !ok {
return fmt.Errorf("set config error")
}
return nil
}

func (e *Emulator) setC7(address string, unixTime uint32) error {
var seed [32]byte
_, err := rand.Read(seed[:])
if err != nil {
return err
}
cConfigStr := C.CString(e.config)
if e.config == "" {
cConfigStr = nil
}
defer C.free(unsafe.Pointer(cConfigStr))
cAddressStr := C.CString(address)
defer C.free(unsafe.Pointer(cAddressStr))
Expand Down
110 changes: 110 additions & 0 deletions tvm/tvmExecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"fmt"
"math/big"
"testing"
"time"

"github.com/tonkeeper/tongo/boc"
codePkg "github.com/tonkeeper/tongo/code"
"github.com/tonkeeper/tongo/liteapi"
"github.com/tonkeeper/tongo/tlb"
"github.com/tonkeeper/tongo/ton"
)
Expand Down Expand Up @@ -130,3 +132,111 @@ func TestEmulator_WithLibraries(t *testing.T) {
t.Fatalf("expected exit code: 9, got: %v", code)
}
}

func TestGet_Benchmark(t *testing.T) {
acc := "EQCq_bZJPkPoAxScGRqVfzCalamT3yYdQUURNDdjKkEvQ1yq"
methods := []string{"get_collection_data"}

client, err := liteapi.NewClientWithDefaultMainnet()
if err != nil {
panic(err)
}
config, err := client.GetConfigAll(context.Background(), 0)
if err != nil {
panic(err)
}
account, err := client.GetAccountState(context.Background(), ton.MustParseAccountID(acc))
if err != nil {
panic(err)
}
configCell := boc.NewCell()
err = tlb.Marshal(configCell, config.Config)
if err != nil {
panic(err)
}

init := account.Account.Account.Storage.State.AccountActive.StateInit
e, err := NewEmulator(&init.Code.Value.Value, &init.Data.Value.Value, configCell)
if err != nil {
panic(err)
}
if e == nil {
panic(err)
}

l, err := configCell.ToBocBase64()
fmt.Printf("conf size: %d\n", len(l))
l2, err := (&init.Data.Value.Value).ToBocBase64()
fmt.Printf("data size: %d\n", len(l2))
if err != nil {
panic(err)
}

num := 1000

start := time.Now()
for i := 0; i < num; i++ {
for _, method := range methods {
exit, _, err := e.RunSmcMethod(context.Background(), ton.MustParseAccountID(acc), method, nil)
if err != nil {
fmt.Println(err)
}
if exit != 0 {
fmt.Println(exit)
}
}
}
duration := time.Since(start)
fmt.Printf("Time 1 emulator: %v\n", duration)

start = time.Now()
for i := 0; i < num; i++ {
for _, method := range methods {
e, err := NewEmulator(&init.Code.Value.Value, &init.Data.Value.Value, configCell)
if err != nil {
panic(err)
}
exit, _, err := e.RunSmcMethod(context.Background(), ton.MustParseAccountID(acc), method, nil)
if err != nil {
fmt.Println(err)
}
if exit != 0 {
fmt.Println(exit)
}
}
}
duration = time.Since(start)
fmt.Printf("Time (config as string): %v\n", duration)

// reuse config
conf, err := configCell.ToBocBase64()
if err != nil {
fmt.Println(err)
}
c, err := createConfig(conf)
if err != nil {
fmt.Println(err)
}
if c == nil {
fmt.Println("Config object not created")
}

start = time.Now()
for i := 0; i < num; i++ {
for _, method := range methods {
e, err := NewEmulator(&init.Code.Value.Value, &init.Data.Value.Value, nil, WithConfig(c))
if err != nil {
panic(err)
}
exit, _, err := e.RunSmcMethod(context.Background(), ton.MustParseAccountID(acc), method, nil)
if err != nil {
fmt.Println(err)
}
if exit != 0 {
fmt.Println(exit)
}
}
}
duration = time.Since(start)
fmt.Printf("Time (config as object): %v\n", duration)
}
Loading