Skip to content

Commit

Permalink
Merge pull request #74 from multiversx/esdt-construction-01
Browse files Browse the repository at this point in the history
Implement construction of ESDT transfers (2)
  • Loading branch information
andreibancioiu authored Aug 7, 2024
2 parents f0d8572 + e8b4d17 commit 280364a
Show file tree
Hide file tree
Showing 32 changed files with 831 additions and 164 deletions.
14 changes: 10 additions & 4 deletions .github/workflows/check_with_mesh_cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ jobs:
cd $GITHUB_WORKSPACE/cmd/rosetta && go build .
cd $GITHUB_WORKSPACE/systemtests && go build ./proxyToObserverAdapter.go
- name: check:data
- name: check:construction (native)
run: |
PYTHONPATH=. python3 ./systemtests/check_with_mesh_cli.py --mode=data --network=testnet
PYTHONPATH=. python3 ./systemtests/check_with_mesh_cli.py --mode=construction-native --network=testnet
sleep 30
- name: check:construction (custom)
run: |
PYTHONPATH=. python3 ./systemtests/check_with_mesh_cli.py --mode=construction-custom --network=testnet
sleep 30
- name: check:construction
- name: check:data
run: |
PYTHONPATH=. python3 ./systemtests/check_with_mesh_cli.py --mode=construction --network=testnet
PYTHONPATH=. python3 ./systemtests/check_with_mesh_cli.py --mode=data --network=testnet
14 changes: 7 additions & 7 deletions cmd/rosetta/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ VERSION:
Required: true,
}

cliFlagCustomCurrenciesSymbols = cli.StringSliceFlag{
Name: "custom-currencies",
Usage: "Specifies the symbols of enabled custom currencies (i.e. ESDT identifiers).",
Value: &cli.StringSlice{},
cliFlagConfigFileCustomCurrencies = cli.StringFlag{
Name: "config-custom-currencies",
Usage: "Specifies the configuration file for custom currencies.",
Required: false,
}
)

Expand Down Expand Up @@ -187,7 +187,7 @@ func getAllCliFlags() []cli.Flag {
cliFlagNativeCurrencySymbol,
cliFlagFirstHistoricalEpoch,
cliFlagNumHistoricalEpochs,
cliFlagCustomCurrenciesSymbols,
cliFlagConfigFileCustomCurrencies,
}
}

Expand Down Expand Up @@ -215,7 +215,7 @@ type parsedCliFlags struct {
nativeCurrencySymbol string
firstHistoricalEpoch uint32
numHistoricalEpochs uint32
customCurrenciesSymbols []string
configFileCustomCurrencies string
}

func getParsedCliFlags(ctx *cli.Context) parsedCliFlags {
Expand Down Expand Up @@ -243,6 +243,6 @@ func getParsedCliFlags(ctx *cli.Context) parsedCliFlags {
nativeCurrencySymbol: ctx.GlobalString(cliFlagNativeCurrencySymbol.Name),
firstHistoricalEpoch: uint32(ctx.GlobalUint(cliFlagFirstHistoricalEpoch.Name)),
numHistoricalEpochs: uint32(ctx.GlobalUint(cliFlagNumHistoricalEpochs.Name)),
customCurrenciesSymbols: ctx.GlobalStringSlice(cliFlagCustomCurrenciesSymbols.Name),
configFileCustomCurrencies: ctx.GlobalString(cliFlagConfigFileCustomCurrencies.Name),
}
}
24 changes: 24 additions & 0 deletions cmd/rosetta/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"encoding/json"
"os"

"github.com/multiversx/mx-chain-rosetta/server/resources"
)

func loadConfigOfCustomCurrencies(configFile string) ([]resources.Currency, error) {
fileContent, err := os.ReadFile(configFile)
if err != nil {
return nil, err
}

var customCurrencies []resources.Currency

err = json.Unmarshal(fileContent, &customCurrencies)
if err != nil {
return nil, err
}

return customCurrencies, nil
}
36 changes: 36 additions & 0 deletions cmd/rosetta/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"testing"

"github.com/multiversx/mx-chain-rosetta/server/resources"
"github.com/stretchr/testify/require"
)

func TestLoadConfigOfCustomCurrencies(t *testing.T) {
t.Run("with success", func(t *testing.T) {
customCurrencies, err := loadConfigOfCustomCurrencies("testdata/custom-currencies.json")
require.NoError(t, err)
require.NoError(t, err)
require.Equal(t, []resources.Currency{
{
Symbol: "WEGLD-bd4d79",
Decimals: 18,
},
{
Symbol: "USDC-c76f1f",
Decimals: 6,
},
}, customCurrencies)
})

t.Run("with error (missing file)", func(t *testing.T) {
_, err := loadConfigOfCustomCurrencies("testdata/missing-file.json")
require.Error(t, err)
})

t.Run("with error (invalid file)", func(t *testing.T) {
_, err := loadConfigOfCustomCurrencies("testdata/custom-currencies-bad.json")
require.Error(t, err)
})
}
7 changes: 6 additions & 1 deletion cmd/rosetta/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func startRosetta(ctx *cli.Context) error {
return err
}

customCurrencies, err := loadConfigOfCustomCurrencies(cliFlags.configFileCustomCurrencies)
if err != nil {
return err
}

log.Info("Starting Rosetta...", "middleware", version.RosettaMiddlewareVersion, "specification", version.RosettaVersion)

networkProvider, err := factory.CreateNetworkProvider(factory.ArgsCreateNetworkProvider{
Expand All @@ -72,7 +77,7 @@ func startRosetta(ctx *cli.Context) error {
MinGasLimit: cliFlags.minGasLimit,
ExtraGasLimitGuardedTx: cliFlags.extraGasLimitGuardedTx,
NativeCurrencySymbol: cliFlags.nativeCurrencySymbol,
CustomCurrenciesSymbols: cliFlags.customCurrenciesSymbols,
CustomCurrencies: customCurrencies,
GenesisBlockHash: cliFlags.genesisBlock,
FirstHistoricalEpoch: cliFlags.firstHistoricalEpoch,
NumHistoricalEpochs: cliFlags.numHistoricalEpochs,
Expand Down
1 change: 1 addition & 0 deletions cmd/rosetta/testdata/custom-currencies-bad.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
10 changes: 10 additions & 0 deletions cmd/rosetta/testdata/custom-currencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"symbol": "WEGLD-bd4d79",
"decimals": 18
},
{
"symbol": "USDC-c76f1f",
"decimals": 6
}
]
5 changes: 3 additions & 2 deletions server/factory/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
processFactory "github.com/multiversx/mx-chain-proxy-go/process/factory"
"github.com/multiversx/mx-chain-rosetta/server/factory/components"
"github.com/multiversx/mx-chain-rosetta/server/provider"
"github.com/multiversx/mx-chain-rosetta/server/resources"
)

const (
Expand Down Expand Up @@ -41,7 +42,7 @@ type ArgsCreateNetworkProvider struct {
MinGasLimit uint64
ExtraGasLimitGuardedTx uint64
NativeCurrencySymbol string
CustomCurrenciesSymbols []string
CustomCurrencies []resources.Currency
GenesisBlockHash string
GenesisTimestamp int64
FirstHistoricalEpoch uint32
Expand Down Expand Up @@ -131,7 +132,7 @@ func CreateNetworkProvider(args ArgsCreateNetworkProvider) (NetworkProvider, err
MinGasLimit: args.MinGasLimit,
ExtraGasLimitGuardedTx: args.ExtraGasLimitGuardedTx,
NativeCurrencySymbol: args.NativeCurrencySymbol,
CustomCurrenciesSymbols: args.CustomCurrenciesSymbols,
CustomCurrencies: args.CustomCurrencies,
GenesisBlockHash: args.GenesisBlockHash,
GenesisTimestamp: args.GenesisTimestamp,
FirstHistoricalEpoch: args.FirstHistoricalEpoch,
Expand Down
19 changes: 9 additions & 10 deletions server/provider/currenciesProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,19 @@ type currenciesProvider struct {

// In the future, we might extract this to a standalone component (separate sub-package).
// For the moment, we keep it as a simple structure, with unexported (future-to-be exported) member functions.
func newCurrenciesProvider(nativeCurrencySymbol string, customCurrenciesSymbols []string) *currenciesProvider {
customCurrencies := make([]resources.Currency, 0, len(customCurrenciesSymbols))
func newCurrenciesProvider(nativeCurrencySymbol string, customCurrencies []resources.Currency) (*currenciesProvider, error) {
customCurrenciesBySymbol := make(map[string]resources.Currency)
customCurrenciesSymbols := make([]string, 0, len(customCurrencies))

for _, symbol := range customCurrenciesSymbols {
customCurrency := resources.Currency{
Symbol: symbol,
// At the moment, for custom currencies (ESDTs), we hardcode the number of decimals to 0.
// In the future, we might fetch the actual number of decimals from the metachain observer.
Decimals: 0,
for index, customCurrency := range customCurrencies {
symbol := customCurrency.Symbol

if len(symbol) == 0 {
return nil, newInvalidCustomCurrency(index)
}

customCurrencies = append(customCurrencies, customCurrency)
customCurrenciesBySymbol[symbol] = customCurrency
customCurrenciesSymbols = append(customCurrenciesSymbols, symbol)
}

return &currenciesProvider{
Expand All @@ -35,7 +34,7 @@ func newCurrenciesProvider(nativeCurrencySymbol string, customCurrenciesSymbols
customCurrenciesSymbols: customCurrenciesSymbols,
customCurrencies: customCurrencies,
customCurrenciesBySymbol: customCurrenciesBySymbol,
}
}, nil
}

// GetNativeCurrency gets the native currency (EGLD, 18 decimals)
Expand Down
94 changes: 75 additions & 19 deletions server/provider/currenciesProvider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,104 @@ package provider
import (
"testing"

"github.com/multiversx/mx-chain-rosetta/server/resources"
"github.com/stretchr/testify/require"
)

func TestCurrenciesProvider(t *testing.T) {
func TestNewCurrenciesProvider(t *testing.T) {
t.Run("with success", func(t *testing.T) {
t.Parallel()

provider, err := newCurrenciesProvider("XeGLD", []resources.Currency{
{Symbol: "ROSETTA-3a2edf", Decimals: 2},
{Symbol: "ROSETTA-057ab4", Decimals: 2},
})

require.NoError(t, err)
require.NotNil(t, provider)
})

t.Run("with success (empty or nil array of custom currencies)", func(t *testing.T) {
t.Parallel()

provider, err := newCurrenciesProvider("XeGLD", []resources.Currency{})
require.NoError(t, err)
require.NotNil(t, provider)

provider, err = newCurrenciesProvider("XeGLD", nil)
require.NoError(t, err)
require.NotNil(t, provider)
})

t.Run("with invalid custom currency symbol", func(t *testing.T) {
t.Parallel()

_, err := newCurrenciesProvider("XeGLD", []resources.Currency{
{Symbol: "", Decimals: 2},
})

require.ErrorIs(t, err, errInvalidCustomCurrencySymbol)
require.Equal(t, "invalid custom currency symbol, index = 0", err.Error())
})
}

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

provider := newCurrenciesProvider("XeGLD", []string{"ROSETTA-3a2edf", "ROSETTA-057ab4"})
provider, err := newCurrenciesProvider("XeGLD", []resources.Currency{
{Symbol: "ROSETTA-3a2edf", Decimals: 2},
})

require.NoError(t, err)

t.Run("get native", func(t *testing.T) {
nativeCurrency := provider.GetNativeCurrency()
require.Equal(t, "XeGLD", nativeCurrency.Symbol)
require.Equal(t, int32(18), nativeCurrency.Decimals)
}

func TestCurrenciesProvider_CustomCurrencies(t *testing.T) {
provider, err := newCurrenciesProvider("XeGLD", []resources.Currency{
{Symbol: "ROSETTA-3a2edf", Decimals: 2},
{Symbol: "ROSETTA-057ab4", Decimals: 2},
})

require.NoError(t, err)

t.Run("check has", func(t *testing.T) {
t.Parallel()

nativeCurrency := provider.GetNativeCurrency()
require.Equal(t, "XeGLD", nativeCurrency.Symbol)
require.Equal(t, int32(18), nativeCurrency.Decimals)
require.True(t, provider.HasCustomCurrency("ROSETTA-3a2edf"))
require.True(t, provider.HasCustomCurrency("ROSETTA-057ab4"))
require.False(t, provider.HasCustomCurrency("FOO-abcdef"))
require.False(t, provider.HasCustomCurrency("BAR-abcdef"))
require.False(t, provider.HasCustomCurrency(""))
})

t.Run("get custom", func(t *testing.T) {
t.Run("get all", func(t *testing.T) {
t.Parallel()

customCurrencies := provider.GetCustomCurrencies()
require.Equal(t, 2, len(customCurrencies))
})

customCurrency, ok := provider.GetCustomCurrencyBySymbol("ROSETTA-3a2edf")
require.True(t, ok)
require.Equal(t, "ROSETTA-3a2edf", customCurrency.Symbol)

customCurrency, ok = provider.GetCustomCurrencyBySymbol("ROSETTA-057ab4")
require.True(t, ok)
require.Equal(t, "ROSETTA-057ab4", customCurrency.Symbol)
t.Run("get all symbols", func(t *testing.T) {
t.Parallel()

customCurrenciesSymbols := provider.GetCustomCurrenciesSymbols()
require.Equal(t, 2, len(customCurrenciesSymbols))
require.Equal(t, "ROSETTA-3a2edf", customCurrenciesSymbols[0])
require.Equal(t, "ROSETTA-057ab4", customCurrenciesSymbols[1])
})

t.Run("has custom", func(t *testing.T) {
t.Run("get by symbol", func(t *testing.T) {
t.Parallel()

require.True(t, provider.HasCustomCurrency("ROSETTA-3a2edf"))
require.True(t, provider.HasCustomCurrency("ROSETTA-057ab4"))
require.False(t, provider.HasCustomCurrency("FOO-abcdef"))
require.False(t, provider.HasCustomCurrency("BAR-abcdef"))
customCurrency, ok := provider.GetCustomCurrencyBySymbol("ROSETTA-3a2edf")
require.True(t, ok)
require.Equal(t, "ROSETTA-3a2edf", customCurrency.Symbol)

customCurrency, ok = provider.GetCustomCurrencyBySymbol("ROSETTA-057ab4")
require.True(t, ok)
require.Equal(t, "ROSETTA-057ab4", customCurrency.Symbol)
})
}
5 changes: 5 additions & 0 deletions server/provider/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var errCannotGetBlock = errors.New("cannot get block")
var errCannotGetAccount = errors.New("cannot get account")
var errCannotGetTransaction = errors.New("cannot get transaction")
var errCannotGetLatestBlockNonce = errors.New("cannot get latest block nonce, maybe the node didn't start syncing")
var errInvalidCustomCurrencySymbol = errors.New("invalid custom currency symbol")

func newErrCannotGetBlockByNonce(nonce uint64, innerError error) error {
return fmt.Errorf("%w: %v, nonce = %d", errCannotGetBlock, innerError, nonce)
Expand All @@ -28,6 +29,10 @@ func newErrCannotGetTransaction(hash string, innerError error) error {
return fmt.Errorf("%w: %v, address = %s", errCannotGetTransaction, innerError, hash)
}

func newInvalidCustomCurrency(index int) error {
return fmt.Errorf("%w, index = %d", errInvalidCustomCurrencySymbol, index)
}

// In proxy-go, the function CallGetRestEndPoint() returns an error message as the JSON content of the erroneous HTTP response.
// Here, we attempt to decode that JSON and create an error with a "flat" error message.
func convertStructuredApiErrToFlatErr(apiErr error) error {
Expand Down
7 changes: 5 additions & 2 deletions server/provider/networkProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type ArgsNewNetworkProvider struct {
MinGasLimit uint64
ExtraGasLimitGuardedTx uint64
NativeCurrencySymbol string
CustomCurrenciesSymbols []string
CustomCurrencies []resources.Currency
GenesisBlockHash string
GenesisTimestamp int64
FirstHistoricalEpoch uint32
Expand Down Expand Up @@ -83,7 +83,10 @@ func NewNetworkProvider(args ArgsNewNetworkProvider) (*networkProvider, error) {
return nil, err
}

currenciesProvider := newCurrenciesProvider(args.NativeCurrencySymbol, args.CustomCurrenciesSymbols)
currenciesProvider, err := newCurrenciesProvider(args.NativeCurrencySymbol, args.CustomCurrencies)
if err != nil {
return nil, err
}

return &networkProvider{
currenciesProvider: currenciesProvider,
Expand Down
Loading

0 comments on commit 280364a

Please sign in to comment.