Skip to content

Commit

Permalink
feat: add InMemory gnoland node (gnolang#1241)
Browse files Browse the repository at this point in the history
Co-authored-by: Manfred Touron <[email protected]>
  • Loading branch information
gfanton and moul committed Nov 9, 2023
1 parent 5bbeb28 commit 0e4744a
Show file tree
Hide file tree
Showing 24 changed files with 1,010 additions and 887 deletions.
8 changes: 3 additions & 5 deletions .github/workflows/gnoland.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ jobs:
- _test.gnoland
- _test.gnokey
- _test.pkgs
# XXX: test broken, should be rewritten to run an inmemory localnode
# Re-add to makefile when fixed. Tracked here: https://github.com/gnolang/gno/issues/1222
#- _test.gnoweb
- _test.gnoweb
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -78,7 +76,7 @@ jobs:
export LOG_DIR="${{ runner.temp }}/logs/test-${{ matrix.goversion }}-gnoland"
make ${{ matrix.args }}
- name: Upload Test Log
if: always()
if: always()
uses: actions/upload-artifact@v3
with:
name: logs-test-gnoland-go${{ matrix.goversion }}
Expand All @@ -101,7 +99,7 @@ jobs:
uses: codecov/codecov-action@v3
with:
directory: ${{ runner.temp }}/coverage
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: ${{ github.repository == 'gnolang/gno' }}

docker-integration:
Expand Down
4 changes: 1 addition & 3 deletions gno.land/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ fmt:
########################################
# Test suite
.PHONY: test
test: _test.gnoland _test.gnokey _test.pkgs
# XXX: _test.gnoweb is currently disabled. If fixed, re-enable here and in CI.
# https://github.com/gnolang/gno/issues/1222
test: _test.gnoland _test.gnoweb _test.gnokey _test.pkgs

GOTEST_FLAGS ?= -v -p 1 -timeout=30m

Expand Down
131 changes: 37 additions & 94 deletions gno.land/cmd/genesis/balances_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,22 @@ import (
"fmt"
"io"
"os"
"regexp"
"strconv"
"strings"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/sdk/bank"
"github.com/gnolang/gno/tm2/pkg/std"

_ "github.com/gnolang/gno/gno.land/pkg/sdk/vm"
)

var (
balanceRegex = regexp.MustCompile(`^(\w+)=(\d+)ugnot$`)
amountRegex = regexp.MustCompile(`^(\d+)ugnot$`)
)

var (
errNoBalanceSource = errors.New("at least one balance source must be set")
errBalanceParsingAborted = errors.New("balance parsing aborted")
errInvalidBalanceFormat = errors.New("invalid balance format encountered")
errInvalidAddress = errors.New("invalid address encountered")
errInvalidAmount = errors.New("invalid amount encountered")
)

type balancesAddCfg struct {
Expand Down Expand Up @@ -152,7 +142,7 @@ func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io *commands.IO)

// Construct the initial genesis balance sheet
state := genesis.AppState.(gnoland.GnoGenesisState)
genesisBalances, err := extractGenesisBalances(state)
genesisBalances, err := mapGenesisBalancesFromState(state)
if err != nil {
return err
}
Expand Down Expand Up @@ -190,12 +180,11 @@ func getBalancesFromEntries(entries []string) (accountBalances, error) {
balances := make(accountBalances)

for _, entry := range entries {
accountBalance, err := getBalanceFromEntry(entry)
if err != nil {
return nil, fmt.Errorf("unable to extract balance data, %w", err)
var balance gnoland.Balance
if err := balance.Parse(entry); err != nil {
return nil, fmt.Errorf("unable to parse balance entry: %w", err)
}

balances[accountBalance.address] = accountBalance.amount
balances[balance.Address] = balance
}

return balances, nil
Expand All @@ -220,12 +209,12 @@ func getBalancesFromSheet(sheet io.Reader) (accountBalances, error) {
continue
}

accountBalance, err := getBalanceFromEntry(entry)
if err != nil {
var balance gnoland.Balance
if err := balance.Parse(entry); err != nil {
return nil, fmt.Errorf("unable to extract balance data, %w", err)
}

balances[accountBalance.address] = accountBalance.amount
balances[balance.Address] = balance
}

if err := scanner.Err(); err != nil {
Expand Down Expand Up @@ -262,21 +251,19 @@ func getBalancesFromTransactions(

if err := amino.UnmarshalJSON(line, &tx); err != nil {
io.ErrPrintfln(
"invalid amino JSON encountered: %s",
"invalid amino JSON encountered: %q",
string(line),
)

continue
}

feeAmount, err := getAmountFromEntry(tx.Fee.GasFee.String())
if err != nil {
feeAmount := std.NewCoins(tx.Fee.GasFee)
if feeAmount.AmountOf("ugnot") <= 0 {
io.ErrPrintfln(
"invalid gas fee amount encountered: %s",
"invalid gas fee amount encountered: %q",
tx.Fee.GasFee.String(),
)

continue
}

for _, msg := range tx.Msgs {
Expand All @@ -286,13 +273,12 @@ func getBalancesFromTransactions(

msgSend := msg.(bank.MsgSend)

sendAmount, err := getAmountFromEntry(msgSend.Amount.String())
if err != nil {
sendAmount := msgSend.Amount
if sendAmount.AmountOf("ugnot") <= 0 {
io.ErrPrintfln(
"invalid send amount encountered: %s",
msgSend.Amount.String(),
)

continue
}

Expand All @@ -304,27 +290,35 @@ func getBalancesFromTransactions(
// causes an accounts balance to go < 0. In these cases,
// we initialize the account (it is present in the balance sheet), but
// with the balance of 0
from := balances[msgSend.FromAddress]
to := balances[msgSend.ToAddress]

to += sendAmount
from := balances[msgSend.FromAddress].Amount
to := balances[msgSend.ToAddress].Amount

to = to.Add(sendAmount)

if from < sendAmount || from < feeAmount {
if from.IsAllLT(sendAmount) || from.IsAllLT(feeAmount) {
// Account cannot cover send amount / fee
// (see message above)
from = 0
from = std.NewCoins(std.NewCoin("ugnot", 0))
}

if from > sendAmount {
from -= sendAmount
if from.IsAllGT(sendAmount) {
from = from.Sub(sendAmount)
}

if from > feeAmount {
from -= feeAmount
if from.IsAllGT(feeAmount) {
from = from.Sub(feeAmount)
}

balances[msgSend.FromAddress] = from
balances[msgSend.ToAddress] = to
// Set new balance
balances[msgSend.FromAddress] = gnoland.Balance{
Address: msgSend.FromAddress,
Amount: from,
}
balances[msgSend.ToAddress] = gnoland.Balance{
Address: msgSend.ToAddress,
Amount: to,
}
}
}
}
Expand All @@ -340,65 +334,14 @@ func getBalancesFromTransactions(
return balances, nil
}

// getAmountFromEntry
func getAmountFromEntry(entry string) (int64, error) {
matches := amountRegex.FindStringSubmatch(entry)

// Check if there is a match
if len(matches) != 2 {
return 0, fmt.Errorf(
"invalid amount, %s",
entry,
)
}

amount, err := strconv.ParseInt(matches[1], 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid amount, %s", matches[1])
}

return amount, nil
}

// getBalanceFromEntry extracts the account balance information
// from a single line in the form of: <address>=<amount>ugnot
func getBalanceFromEntry(entry string) (*accountBalance, error) {
matches := balanceRegex.FindStringSubmatch(entry)
if len(matches) != 3 {
return nil, fmt.Errorf("%w, %s", errInvalidBalanceFormat, entry)
}

// Validate the address
address, err := crypto.AddressFromString(matches[1])
if err != nil {
return nil, fmt.Errorf("%w, %w", errInvalidAddress, err)
}

// Validate the amount
amount, err := strconv.ParseInt(matches[2], 10, 64)
if err != nil {
return nil, fmt.Errorf("%w, %w", errInvalidAmount, err)
}

return &accountBalance{
address: address,
amount: amount,
}, nil
}

// extractGenesisBalances extracts the initial account balances from the
// mapGenesisBalancesFromState extracts the initial account balances from the
// genesis app state
func extractGenesisBalances(state gnoland.GnoGenesisState) (accountBalances, error) {
func mapGenesisBalancesFromState(state gnoland.GnoGenesisState) (accountBalances, error) {
// Construct the initial genesis balance sheet
genesisBalances := make(accountBalances)

for _, entry := range state.Balances {
accountBalance, err := getBalanceFromEntry(entry)
if err != nil {
return nil, fmt.Errorf("invalid genesis balance entry, %w", err)
}

genesisBalances[accountBalance.address] = accountBalance.amount
for _, balance := range state.Balances {
genesisBalances[balance.Address] = balance
}

return genesisBalances, nil
Expand Down
Loading

0 comments on commit 0e4744a

Please sign in to comment.