From 3ac9f13cf9d1ead8faf99900e772565a7db9df48 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Thu, 26 Aug 2021 20:45:41 -0700 Subject: [PATCH] fix test2 tests; update README --- PHILOSOPHY.md | 10 +- PLAN.md | 14 ++- README.md | 125 ++++-------------------- ROADMAP.md | 20 ++++ logos/README.md | 11 +++ ownership.go | 30 ++++++ pkgs/bft/abci/types/mock_types.go | 12 +++ pkgs/sdk/baseapp.go | 38 ++++---- pkgs/sdk/baseapp_test.go | 6 +- pkgs/sdk/helpers.go | 7 +- pkgs/std/account.go | 148 +++++++++++++++++++++++++++++ pkgs/store/rootmulti/store_test.go | 10 +- pkgs/store/types/gas_test.go | 16 ++-- realm.go | 37 ++++++++ 14 files changed, 336 insertions(+), 148 deletions(-) create mode 100644 ROADMAP.md create mode 100644 logos/README.md create mode 100644 pkgs/std/account.go diff --git a/PHILOSOPHY.md b/PHILOSOPHY.md index b4501e9931..7074e7e16d 100644 --- a/PHILOSOPHY.md +++ b/PHILOSOPHY.md @@ -1,8 +1,12 @@ -## General Philosophy +# Philosophy - * Simplicity. + * Simplicity of design. * The code is the spec. - * Minimize dependencies; all dependencies must get audited. + * Minimal dependencies - all dependencies must get audited. + * Completeness - software projects that don't become + complete are projects that are forever vulnerable. One of +the primary goals of the Gno language and related works is to +become finished within a reasonable timeframe. ## Gno Philosophy diff --git a/PLAN.md b/PLAN.md index 1f6b42acba..17f021cd31 100644 --- a/PLAN.md +++ b/PLAN.md @@ -23,8 +23,18 @@ improve the plan. Read the plan for details on incentives for contributions. The ATOM distribution will be spooned, and a new premine created to incentive new contributors. -* 75% of GNOTs to ATOM holders, with minor modifications -* 25% of GNOTs as premine to new contributors +* 67% of GNOTs to ATOM holders, with minor modifications + - Governance voting-based modifications not needed + - TODO figure out how/whether to exclude/include exchanges. + - TODO figure out how/whether to exclude/include IBC locked ATOMs. + - NOTE: ATOM holders staked on the hub do not need to unstake. + +* 33% of GNOTs as premine to new contributors: + - The following distribution is a work in progress: + - 15% (of 33%) for core contributors responsible for the delivery of Gno's complete objectives. + - 10% for other contributors and business partnerships. + - 4% for short term incentivization of Gno's BFT and SDK stack for use by Cosmos projects. + - 4% for long term incentivization of Gnoland adoption. ### Contributing diff --git a/README.md b/README.md index 742d9a28e2..35204be27c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Among these were Tendermint and Cosmos to engineer robust PoS and IBC. Then came Gno upon Cosmos and there spring forth Gnoland, simulated by the Gnomes of the Greater Resistance. +This README is a placeholder, check back again for updates + ## Language Features * Like interpreted Go, but more ambitious. @@ -17,6 +19,12 @@ simulated by the Gnomes of the Greater Resistance. ## Status +_Update Aug 26th, 2021: SDK/store,baseapp ported; Plan updated_ + +Cosmos-SDK's store and baseapp modules have been ported. +Now porting x/auth, for minimal auth usage. +Plan updated with premine distribution for GNO adoption. + _Update Aug 16th, 2021: basic file tests pass_ Basic Go file tests now pass. Working on realm/ownership logic under tests/files/zrealm\*.go. @@ -41,115 +49,16 @@ Make sure you have >=[go1.15](https://golang.org/doc/install) installed, and the > make test ``` -## Ownership - -_TODO: update documentation on ownership, which is being worked on now_ - -In Gno, all objects are automatically persisted to disk after every atomic -"transaction" (a function call that must return immediately.) when new objects -are associated with a "ownership tree" which is maintained overlaying the -possibly cyclic object graph (NOTE: cyclic references for persistence not -supported at this stage). The ownership tree is composed of objects (arrays, -structs, maps, and blocks) and derivatives (pointers, slices, and so on) with -optional struct-tag annotations to define the ownership tree. - -If an object hangs off of the ownership tree, it becomes included in the Merkle -root, and is said to be "real". The Merkle-ized state of reality gets updated -with state transition transactions; during such a transaction, some new -temporary objects may "become real" by becoming associated in the ownership -tree (say, assigned to a struct field or appended to a slice that was part of -the ownership tree prior to the transaction), but those that don't get garbage -collected and forgotten. - -In the first release of Gno, all fields are owned in the same realm, and no -cyclic dependencies are allowed outside the bounds of a realm transaction (this -will change in phase 2, where ref-counted references and weak references will -be supported). - -We get a lack-of-owner problem when the ownership tree detaches an object -referred elsewhere (after running a statement or set of statements): - -## Realms - -Gno is designed with blockchain smart contract programming in mind. A -smart-contract enabled blockchain is like a massive-multiuser-online -operating-system (MMO-OS). Each user is provided a home package, for example -"gno.land/r/username". This is not just a regular package but a "realm -package", and functions and methods declared there have special privileges. - -Every "realm package" should define at last one package-level variable: - -```go -// PKGPATH: gno.land/r/alice -package alice -var root interface{} - -func UpdateRoot(...) error { - root = ... -} -``` - -Here, the root variable can be any object, and indicates the root node in -the data realm identified by the package path "gno.land/r/alice". - -Any number of package-level values may be declared in a realm; they are -all owned by the package and get merkle-hashed into a single root hash for -the package realm. - -The gas cost of transactions that modify state are paid for by whoever -submits the transaction, but the storage rent is paid for by the realm. -Anyone can pay the storage upkeep of a realm to keep it alive. - -## Concurrency - -Initially, we don't need to implement routines because realm package functions -provide all the inter-realm functionality we need to implement rich smart -contract programming systems. But later, for various reasons including -long-running background jobs, and parallel concurrency, Gno will implement -deterministic concurrency as well. - -Determinism is supported by including a deterministic timestamp with each -channel message as well as periodic heartbeat messages even with no sends, so -that select/receive operations can behave deterministically even in the -presence of multiple channels to select from. - -## Logos Browser - -[Logos](/logos) is a Gno object browser. The modern browser as well as the -modern javascript ecosystem is from a security point of view, completely fucked. -The entire paradigm of continuously updating browsers with incrementally added -features is a security nightmare. - -The Logos browser is based on a new model that is vastly simpler than HTML. -The purpose of Logos is to become a fully expressive web API and implementation -standard that does most of what HTML and the World Wide Web originally intended -to do, but without becoming more complex than necessary. - -## Completeness - -Software projects that don't become complete are projects that are forever -vulnerable. One of the requisite goals of the Gno language and related -software libraries like Logos is to become finished within a reasonable timeframe. - -## How to become a Gnome - -First, read the license. The license doesn't take away any of your rights, but -it gives the Gno project rights to your contributions. - -Contributions in the form of completed work in a pull request or issue or -comments are welcome and encouraged, especially if you are interested in -joining the project. - -The biggest bottleneck in these sorts of projects is finding the right people -with the right skillset and character; and my highest priority besides coding, -is to find the right contributors. If you can grok the complexities of this -and related projects without hand holding, and you understand the implications -of this project and are aligned with its mission, read on. +## Resources -The Gno Foundation is a non-profit with missions originally stated in the -[Virgo Project](https://github.com/virgo-project/virgo). The Gno Foundation, -which owns the IP to the Gno Works, proposes the plan as laid out in the [plan -doc](/PLAN.md). + * [GnoKey Client Tool](/cmd/gnokey) universal Gno client + * [Amino](/pkg/amino) complete with .proto generation + * [BFT Consensus](/pkg/bft) minimal port of Tendermint + * [SDK](/pkg/sdk) minimal port of Cosmos-SDK + * [Logos Browser](/logos) future terminal browser + * [Plan](/PLAN.md) project plan + * [Roadmap](/ROADMAP.md) development roadmap + * [Philosophy](/PHILOSOPHY.md) project philosophy ## Contact diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000000..2cbe72d722 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,20 @@ +# Roadmap + +## Immediate Roadmap + +TODO + +## Long Term Roadmap + +### Concurrency + +Initially, we don't need to implement routines because realm package functions +provide all the inter-realm functionality we need to implement rich smart +contract programming systems. But later, for various reasons including +long-running background jobs, and parallel concurrency, Gno will implement +deterministic concurrency as well. + +Determinism is supported by including a deterministic timestamp with each +channel message as well as periodic heartbeat messages even with no sends, so +that select/receive operations can behave deterministically even in the +presence of multiple channels to select from. diff --git a/logos/README.md b/logos/README.md new file mode 100644 index 0000000000..ba8ac8333a --- /dev/null +++ b/logos/README.md @@ -0,0 +1,11 @@ +## Logos Browser + +[Logos](/logos) is a Gno object browser. The modern browser as well as the +modern javascript ecosystem is from a security point of view, completely fucked. +The entire paradigm of continuously updating browsers with incrementally added +features is a security nightmare. + +The Logos browser is based on a new model that is vastly simpler than HTML. +The purpose of Logos is to become a fully expressive web API and implementation +standard that does most of what HTML and the World Wide Web originally intended +to do, but without becoming more complex than necessary. diff --git a/ownership.go b/ownership.go index 4ea03592b8..1a2a1e061f 100644 --- a/ownership.go +++ b/ownership.go @@ -5,6 +5,36 @@ import ( "fmt" ) +/* +## Ownership + +In Gno, all objects are automatically persisted to disk after +every atomic "transaction" (a function call that must return +immediately.) when new objects are associated with a +"ownership tree" which is maintained overlaying the possibly +cyclic object graph (NOTE: cyclic references for persistence +not supported at this stage). The ownership tree is composed +of objects (arrays, structs, maps, and blocks) and +derivatives (pointers, slices, and so on) with optional +struct-tag annotations to define the ownership tree. + +If an object hangs off of the ownership tree, it becomes +included in the Merkle root, and is said to be "real". The +Merkle-ized state of reality gets updated with state +transition transactions; during such a transaction, some new +temporary objects may "become real" by becoming associated in +the ownership tree (say, assigned to a struct field or +appended to a slice that was part of the ownership tree prior +to the transaction), but those that don't get garbage +collected and forgotten. + +In the first release of Gno, all fields are owned in the same +realm, and no cyclic dependencies are allowed outside the +bounds of a realm transaction (this will change in phase 2, +where ref-counted references and weak references will be +supported). +*/ + type ObjectID struct { RealmID // base NewTime uint64 // time created diff --git a/pkgs/bft/abci/types/mock_types.go b/pkgs/bft/abci/types/mock_types.go index 65b139a38c..c6b0279133 100644 --- a/pkgs/bft/abci/types/mock_types.go +++ b/pkgs/bft/abci/types/mock_types.go @@ -15,3 +15,15 @@ type MockHeader struct { } func (_ MockHeader) AssertABCIHeader() {} + +func (mh MockHeader) GetChainID() string { + return mh.ChainID +} + +func (mh MockHeader) GetHeight() int64 { + return mh.Height +} + +func (mh MockHeader) GetTime() time.Time { + return mh.Time +} diff --git a/pkgs/sdk/baseapp.go b/pkgs/sdk/baseapp.go index 9c71c07ccd..acec69ddd6 100644 --- a/pkgs/sdk/baseapp.go +++ b/pkgs/sdk/baseapp.go @@ -370,7 +370,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { path := splitPath(req.Path) if len(path) == 0 { msg := "no query path provided" - res.Error = toABCIError(std.ErrUnknownRequest(msg)) + res.Error = ABCIError(std.ErrUnknownRequest(msg)) return } @@ -388,7 +388,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { } msg := "unknown query path" - res.Error = toABCIError(std.ErrUnknownRequest(msg)) + res.Error = ABCIError(std.ErrUnknownRequest(msg)) return } @@ -402,7 +402,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc var tx Tx err := amino.Unmarshal(txBytes, &tx) if err != nil { - res.Error = toABCIError(std.ErrTxDecode(err.Error())) + res.Error = ABCIError(std.ErrTxDecode(err.Error())) } else { result = app.Simulate(txBytes, tx) } @@ -414,11 +414,11 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc res.Value = []byte(app.appVersion) return res default: - res.Error = toABCIError(std.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path))) + res.Error = ABCIError(std.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path))) return } } else { - res.Error = toABCIError(std.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path))) + res.Error = ABCIError(std.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path))) return } } @@ -428,7 +428,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a queryable, ok := app.cms.(store.Queryable) if !ok { msg := "multistore doesn't support queries" - res.Error = toABCIError(std.ErrUnknownRequest(msg)) + res.Error = ABCIError(std.ErrUnknownRequest(msg)) return } @@ -440,7 +440,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a } if req.Height <= 1 && req.Prove { - res.Error = toABCIError(std.ErrInternal("cannot query with proof when height <= 1; please provide a valid height")) + res.Error = ABCIError(std.ErrInternal("cannot query with proof when height <= 1; please provide a valid height")) return } @@ -451,13 +451,13 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { if len(path) < 1 || path[0] == "" { - res.Error = toABCIError(std.ErrUnknownRequest("No route for custom query specified")) + res.Error = ABCIError(std.ErrUnknownRequest("No route for custom query specified")) return } handler := app.router.Route(path[0]) if handler == nil { - res.Error = toABCIError(std.ErrUnknownRequest(fmt.Sprintf("no custom handler found for route %s", path[0]))) + res.Error = ABCIError(std.ErrUnknownRequest(fmt.Sprintf("no custom handler found for route %s", path[0]))) return } @@ -467,13 +467,13 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res } if req.Height <= 1 && req.Prove { - res.Error = toABCIError(std.ErrInternal("cannot query with proof when height <= 1; please provide a valid height")) + res.Error = ABCIError(std.ErrInternal("cannot query with proof when height <= 1; please provide a valid height")) return } cacheMS, err := app.cms.MultiImmutableCacheWrapWithVersion(req.Height) if err != nil { - res.Error = toABCIError(std.ErrInternal( + res.Error = ABCIError(std.ErrInternal( fmt.Sprintf( "failed to load state at height %d; %s (latest height: %d)", req.Height, err, app.LastBlockHeight(), @@ -553,7 +553,7 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) (res abci.ResponseCheckTx) var tx Tx err := amino.Unmarshal(req.Tx, &tx) if err != nil { - res.Error = toABCIError(std.ErrTxDecode(err.Error())) + res.Error = ABCIError(std.ErrTxDecode(err.Error())) return } else { result := app.runTx(runTxModeCheck, req.Tx, tx) @@ -569,7 +569,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv var tx Tx err := amino.Unmarshal(req.Tx, &tx) if err != nil { - res.Error = toABCIError(std.ErrTxDecode(err.Error())) + res.Error = ABCIError(std.ErrTxDecode(err.Error())) return } else { result := app.runTx(runTxModeDeliver, req.Tx, tx) @@ -625,7 +625,7 @@ func (app *BaseApp) runMsgs(ctx Context, msgs []Msg, mode runTxMode) (result Res msgRoute := msg.Route() handler := app.router.Route(msgRoute) if handler == nil { - result.Error = toABCIError(std.ErrUnknownRequest("unrecognized message type: " + msgRoute)) + result.Error = ABCIError(std.ErrUnknownRequest("unrecognized message type: " + msgRoute)) return } @@ -658,7 +658,7 @@ func (app *BaseApp) runMsgs(ctx Context, msgs []Msg, mode runTxMode) (result Res i, true, msgResult.Log, events)) } - result.Error = toABCIError(err) + result.Error = ABCIError(err) result.Data = data result.Log = strings.Join(msgLogs, "\n") result.GasUsed = ctx.GasMeter().GasConsumed() @@ -709,7 +709,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx Tx) (result Result) // only run the tx if there is block gas remaining if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { - result.Error = toABCIError(std.ErrOutOfGas("no block gas left to run tx")) + result.Error = ABCIError(std.ErrOutOfGas("no block gas left to run tx")) return } @@ -728,14 +728,14 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx Tx) (result Result) ctx.GasMeter().GasConsumed(), ex.Descriptor, ) - result.Error = toABCIError(std.ErrOutOfGas(log)) + result.Error = ABCIError(std.ErrOutOfGas(log)) result.Log = log result.GasWanted = gasWanted result.GasUsed = ctx.GasMeter().GasConsumed() return default: log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack())) - result.Error = toABCIError(std.ErrInternal(log)) + result.Error = ABCIError(std.ErrInternal(log)) result.Log = log result.GasWanted = gasWanted result.GasUsed = ctx.GasMeter().GasConsumed() @@ -767,7 +767,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx Tx) (result Result) var msgs = tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - result.Error = toABCIError(err) + result.Error = ABCIError(err) return } diff --git a/pkgs/sdk/baseapp_test.go b/pkgs/sdk/baseapp_test.go index 78f185f077..9c26e9b2c1 100644 --- a/pkgs/sdk/baseapp_test.go +++ b/pkgs/sdk/baseapp_test.go @@ -432,7 +432,7 @@ func anteHandlerTxTest(t *testing.T, capKey store.StoreKey, storeKey []byte) Ant return func(ctx Context, tx std.Tx, simulate bool) (newCtx Context, res Result, abort bool) { store := ctx.Store(capKey) if getFailOnAnte(tx) { - res.Error = toABCIError(std.ErrInternal("ante handler failure")) + res.Error = ABCIError(std.ErrInternal("ante handler failure")) return newCtx, res, true } @@ -477,7 +477,7 @@ func (mch msgCounterHandler) Process(ctx Context, msg Msg) (res Result) { switch m := msg.(type) { case msgCounter: if m.FailOnHandler { - res.Error = toABCIError(std.ErrInternal("message handler failure")) + res.Error = ABCIError(std.ErrInternal("message handler failure")) return } msgCount = m.Counter @@ -1070,7 +1070,7 @@ func TestGasConsumptionBadTx(t *testing.T) { newCtx.GasMeter().ConsumeGas(int64(getCounter(tx)), "counter-ante") if getFailOnAnte(tx) { - res.Error = toABCIError(std.ErrInternal("ante handler failure")) + res.Error = ABCIError(std.ErrInternal("ante handler failure")) return newCtx, res, true } diff --git a/pkgs/sdk/helpers.go b/pkgs/sdk/helpers.go index e04bf6a028..2ec8d27e35 100644 --- a/pkgs/sdk/helpers.go +++ b/pkgs/sdk/helpers.go @@ -35,7 +35,7 @@ func (app *BaseApp) NewContext(isCheckTx bool, header abci.Header) Context { return NewContext(app.deliverState.ms, header, false, app.logger) } -func toABCIError(err error) abci.Error { +func ABCIError(err error) abci.Error { if err == nil { return nil } @@ -47,3 +47,8 @@ func toABCIError(err error) abci.Error { return abcierr } } + +func ABCIResultFromError(err error) (res Result) { + res.Error = ABCIError(err) + return +} diff --git a/pkgs/std/account.go b/pkgs/std/account.go new file mode 100644 index 0000000000..eee17872fb --- /dev/null +++ b/pkgs/std/account.go @@ -0,0 +1,148 @@ +package std + +import ( + "fmt" + + "github.com/gnolang/gno/pkgs/crypto" + "github.com/gnolang/gno/pkgs/errors" +) + +// Account is an interface used to store coins at a given address within state. +// It presumes a notion of sequence numbers for replay protection, a notion of +// account numbers for replay protection for previously pruned accounts, and a +// pubkey for authentication purposes. +// +// Many complex conditions can be used in the concrete struct which implements Account. +type Account interface { + GetAddress() crypto.Address + SetAddress(crypto.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetAccountNumber() uint64 + SetAccountNumber(uint64) error + + GetSequence() uint64 + SetSequence(uint64) error + + GetCoins() Coins + SetCoins(Coins) error + + // Ensure that account implements stringer + String() string +} + +//---------------------------------------- +// BaseAccount + +// BaseAccount - a base account structure. +// This can be extended by embedding within in your *Account structure. +type BaseAccount struct { + Address crypto.Address `json:"address" yaml:"address"` + Coins Coins `json:"coins" yaml:"coins"` + PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` +} + +// NewBaseAccount creates a new BaseAccount object +func NewBaseAccount(address crypto.Address, coins Coins, + pubKey crypto.PubKey, accountNumber uint64, sequence uint64) *BaseAccount { + + return &BaseAccount{ + Address: address, + Coins: coins, + PubKey: pubKey, + AccountNumber: accountNumber, + Sequence: sequence, + } +} + +// String implements fmt.Stringer +func (acc BaseAccount) String() string { + var pubkey string + + if acc.PubKey != nil { + pubkey = crypto.PubKeyToBech32(acc.PubKey) + } + + return fmt.Sprintf(`Account: + Address: %s + Pubkey: %s + Coins: %s + AccountNumber: %d + Sequence: %d`, + acc.Address, pubkey, acc.Coins, acc.AccountNumber, acc.Sequence, + ) +} + +// ProtoBaseAccount - a prototype function for BaseAccount +func ProtoBaseAccount() Account { + return &BaseAccount{} +} + +// NewBaseAccountWithAddress - returns a new base account with a given address +func NewBaseAccountWithAddress(addr crypto.Address) BaseAccount { + return BaseAccount{ + Address: addr, + } +} + +// GetAddress - Implements Account. +func (acc BaseAccount) GetAddress() crypto.Address { + return acc.Address +} + +// SetAddress - Implements Account. +func (acc *BaseAccount) SetAddress(addr crypto.Address) error { + if len(acc.Address) != 0 { + return errors.New("cannot override BaseAccount address") + } + acc.Address = addr + return nil +} + +// GetPubKey - Implements Account. +func (acc BaseAccount) GetPubKey() crypto.PubKey { + return acc.PubKey +} + +// SetPubKey - Implements Account. +func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { + acc.PubKey = pubKey + return nil +} + +// GetCoins - Implements Account. +func (acc *BaseAccount) GetCoins() Coins { + return acc.Coins +} + +// SetCoins - Implements Account. +func (acc *BaseAccount) SetCoins(coins Coins) error { + acc.Coins = coins + return nil +} + +// GetAccountNumber - Implements Account +func (acc *BaseAccount) GetAccountNumber() uint64 { + return acc.AccountNumber +} + +// SetAccountNumber - Implements Account +func (acc *BaseAccount) SetAccountNumber(accNumber uint64) error { + acc.AccountNumber = accNumber + return nil +} + +// GetSequence - Implements Account. +func (acc *BaseAccount) GetSequence() uint64 { + return acc.Sequence +} + +// SetSequence - Implements Account. +func (acc *BaseAccount) SetSequence(seq uint64) error { + acc.Sequence = seq + return nil +} diff --git a/pkgs/store/rootmulti/store_test.go b/pkgs/store/rootmulti/store_test.go index c0f9807c8d..d50b3fe6b0 100644 --- a/pkgs/store/rootmulti/store_test.go +++ b/pkgs/store/rootmulti/store_test.go @@ -54,11 +54,11 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { require.Equal(t, int64(1), cID.Version) // require failure when given an invalid or pruned version - _, err = ms.MultiCacheWrapWithVersion(cID.Version + 1) + _, err = ms.MultiImmutableCacheWrapWithVersion(cID.Version + 1) require.Error(t, err) // require a valid version can be cache-loaded - cms, err := ms.MultiCacheWrapWithVersion(cID.Version) + cms, err := ms.MultiImmutableCacheWrapWithVersion(cID.Version) require.NoError(t, err) // require a valid key lookup yields the correct value @@ -214,16 +214,16 @@ func TestMultiStoreQuery(t *testing.T) { // Test bad path. query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} qres := multi.Query(query) - require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest:")) + require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest error:")) query.Path = "h897fy32890rf63296r92" qres = multi.Query(query) - require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest:")) + require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest error:")) // Test invalid store name. query.Path = "/garbage/key" qres = multi.Query(query) - require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest:")) + require.True(t, strings.HasPrefix(qres.Error.Error(), "unknownrequest error:")) // Test valid query with data. query.Path = "/store1/key" diff --git a/pkgs/store/types/gas_test.go b/pkgs/store/types/gas_test.go index 81bb0c9017..52020b8909 100644 --- a/pkgs/store/types/gas_test.go +++ b/pkgs/store/types/gas_test.go @@ -4,6 +4,7 @@ import ( "math" "testing" + "github.com/gnolang/overflow" "github.com/stretchr/testify/require" ) @@ -22,7 +23,7 @@ func TestGasMeter(t *testing.T) { for tcnum, tc := range cases { meter := NewGasMeter(tc.limit) - used := uint64(0) + used := int64(0) for unum, usage := range tc.usage { used += usage @@ -47,25 +48,26 @@ func TestGasMeter(t *testing.T) { func TestAddUint64Overflow(t *testing.T) { testCases := []struct { - a, b uint64 - result uint64 + a, b int64 + result int64 overflow bool }{ {0, 0, 0, false}, {100, 100, 200, false}, - {math.MaxUint64 / 2, math.MaxUint64/2 + 1, math.MaxUint64, false}, - {math.MaxUint64 / 2, math.MaxUint64/2 + 2, 0, true}, + {math.MaxInt64 / 2, math.MaxInt64/2 + 1, math.MaxInt64, false}, + {math.MaxInt64 / 2, math.MaxInt64/2 + 2, math.MinInt64, true}, } for i, tc := range testCases { - res, overflow := addUint64Overflow(tc.a, tc.b) + res, ok := overflow.Add64(tc.a, tc.b) + overflow := !ok require.Equal( t, tc.overflow, overflow, "invalid overflow result; tc: #%d, a: %d, b: %d", i, tc.a, tc.b, ) require.Equal( t, tc.result, res, - "invalid uint64 result; tc: #%d, a: %d, b: %d", i, tc.a, tc.b, + "invalid int64 result; tc: #%d, a: %d, b: %d", i, tc.a, tc.b, ) } } diff --git a/realm.go b/realm.go index 0407143425..04ec0bf775 100644 --- a/realm.go +++ b/realm.go @@ -8,6 +8,43 @@ import ( "github.com/davecgh/go-spew/spew" ) +/* +## Realms + +Gno is designed with blockchain smart contract programming in +mind. A smart-contract enabled blockchain is like a +massive-multiuser-online operating-system (MMO-OS). Each user +is provided a home package, for example +"gno.land/r/username". This is not just a regular package but +a "realm package", and functions and methods declared there +have special privileges. + +Every "realm package" should define at last one package-level variable: + +```go +// PKGPATH: gno.land/r/alice +package alice +var root interface{} + +func UpdateRoot(...) error { + root = ... +} +``` + +Here, the root variable can be any object, and indicates the +root node in the data realm identified by the package path +"gno.land/r/alice". + +Any number of package-level values may be declared in a +realm; they are all owned by the package and get +merkle-hashed into a single root hash for the package realm. + +The gas cost of transactions that modify state are paid for +by whoever submits the transaction, but the storage rent is +paid for by the realm. Anyone can pay the storage upkeep of +a realm to keep it alive. +*/ + //---------------------------------------- // Realm