diff --git a/erisdb/serve.go b/erisdb/serve.go index 478ae9aa7b3a1b09d79e7b6dab45ae5fbd2df481..ec998c56feba1fef9f0ec1b5b9272bb8228b025b 100644 --- a/erisdb/serve.go +++ b/erisdb/serve.go @@ -19,6 +19,7 @@ import ( "github.com/tendermint/tendermint/node" ep "github.com/eris-ltd/eris-db/erisdb/pipe" + evm "github.com/eris-ltd/eris-db/evm" "github.com/eris-ltd/eris-db/server" edbapp "github.com/eris-ltd/eris-db/tmsp" @@ -105,6 +106,8 @@ func ServeErisDB(workDir string) (*server.ServeProcess, error) { app := edbapp.NewErisDBApp(state, evsw) app.SetHostAddress(sConf.Consensus.TendermintHost) + evm.SetDebug(sConf.Logging.VMLog) + // Start the tmsp listener for state update commands go func() { // TODO config diff --git a/evm/vm.go b/evm/vm.go index af947fbc3456d1df428f1d68fd27d690a8d64c68..656350bf5e7c653da00722e58598ed3f9d21b73d 100644 --- a/evm/vm.go +++ b/evm/vm.go @@ -36,15 +36,20 @@ func (err ErrPermission) Error() string { return fmt.Sprintf("Contract does not have permission to %s", err.typ) } -type Debug bool - const ( - dataStackCapacity = 1024 - callStackCapacity = 100 // TODO ensure usage. - memoryCapacity = 1024 * 1024 // 1 MB - dbg Debug = true + dataStackCapacity = 1024 + callStackCapacity = 100 // TODO ensure usage. + memoryCapacity = 1024 * 1024 // 1 MB ) +type Debug bool + +var dbg Debug + +func SetDebug(d bool) { + dbg = Debug(d) +} + func (d Debug) Printf(s string, a ...interface{}) { if d { fmt.Printf(s, a...) diff --git a/server/config.go b/server/config.go index 7354408ff26e997e04da58191c5fb41ee86f449c..24b948926c9f153defb2f361e9850ad8512a2ce6 100644 --- a/server/config.go +++ b/server/config.go @@ -54,6 +54,7 @@ type ( ConsoleLogLevel string `toml:"console_log_level"` FileLogLevel string `toml:"file_log_level"` LogFile string `toml:"log_file"` + VMLog bool `toml:"vm_log"` } Consensus struct { diff --git a/tmsp/erisdb.go b/tmsp/erisdb.go index f649a48807145f61b6031ca106112c0f6fe0e464..514f219806b8e8101aa56f8b754870626cff7b87 100644 --- a/tmsp/erisdb.go +++ b/tmsp/erisdb.go @@ -35,6 +35,8 @@ type ErisDBApp struct { // client to the tendermint core rpc client *client.ClientURI host string // tendermint core endpoint + + nTxs int // count txs in a block } func (app *ErisDBApp) GetState() *sm.State { @@ -43,18 +45,13 @@ func (app *ErisDBApp) GetState() *sm.State { return app.state.Copy() } +// TODO: this is used for call/callcode and to get nonces during mempool. +// the former should work on last committed state only and the later should +// be handled by the client, or a separate wallet-like nonce tracker thats not part of the app func (app *ErisDBApp) GetCheckCache() *sm.BlockCache { - app.mtx.Lock() - defer app.mtx.Unlock() return app.checkCache } -func (app *ErisDBApp) ResetCheckCache() { - app.mtx.Lock() - defer app.mtx.Unlock() - app.checkCache = sm.NewBlockCache(app.state) -} - func (app *ErisDBApp) SetHostAddress(host string) { app.host = host app.client = client.NewClientURI(host) //fmt.Sprintf("http://%s", host)) @@ -100,7 +97,10 @@ func (app *ErisDBApp) SetOption(key string, value string) (log string) { } // Implements tmsp.Application -func (app ErisDBApp) AppendTx(txBytes []byte) (res tmsp.Result) { +func (app *ErisDBApp) AppendTx(txBytes []byte) (res tmsp.Result) { + + app.nTxs += 1 + // XXX: if we had tx ids we could cache the decoded txs on CheckTx var n int var err error @@ -111,19 +111,17 @@ func (app ErisDBApp) AppendTx(txBytes []byte) (res tmsp.Result) { return tmsp.NewError(tmsp.CodeType_EncodingError, fmt.Sprintf("Encoding error: %v", err)) } + log.Info("AppendTx", "tx", *tx) + err = sm.ExecTx(app.cache, *tx, true, app.evc) if err != nil { - return tmsp.NewError(tmsp.CodeType_InternalError, fmt.Sprintf("Encoding error: %v", err)) + return tmsp.NewError(tmsp.CodeType_InternalError, fmt.Sprintf("Internal error: %v", err)) } return tmsp.NewResultOK(nil, "Success") } // Implements tmsp.Application -func (app ErisDBApp) CheckTx(txBytes []byte) (res tmsp.Result) { - log.Info("Check Tx", "tx", txBytes) - defer func() { - log.Info("Check Tx", "res", res) - }() +func (app *ErisDBApp) CheckTx(txBytes []byte) (res tmsp.Result) { var n int var err error tx := new(types.Tx) @@ -133,13 +131,12 @@ func (app ErisDBApp) CheckTx(txBytes []byte) (res tmsp.Result) { return tmsp.NewError(tmsp.CodeType_EncodingError, fmt.Sprintf("Encoding error: %v", err)) } - // we need the lock because CheckTx can run concurrently with Commit, - // and Commit refreshes the checkCache - app.mtx.Lock() - defer app.mtx.Unlock() + log.Info("CheckTx", "tx", *tx) + + // TODO: make errors tmsp aware err = sm.ExecTx(app.checkCache, *tx, false, nil) if err != nil { - return tmsp.NewError(tmsp.CodeType_InternalError, fmt.Sprintf("Encoding error: %v", err)) + return tmsp.NewError(tmsp.CodeType_InternalError, fmt.Sprintf("Internal error: %v", err)) } return tmsp.NewResultOK(nil, "Success") @@ -147,12 +144,25 @@ func (app ErisDBApp) CheckTx(txBytes []byte) (res tmsp.Result) { // Implements tmsp.Application // Commit the state (called at end of block) +// NOTE: CheckTx/AppendTx must not run concurrently with Commit - +// the mempool should run during AppendTxs, but lock for Commit and Update func (app *ErisDBApp) Commit() (res tmsp.Result) { + app.mtx.Lock() // the lock protects app.state + defer app.mtx.Unlock() + + app.state.LastBlockHeight += 1 + log.Info("Commit", "block", app.state.LastBlockHeight) + // sync the AppendTx cache app.cache.Sync() + // if there were any txs in the block, // reset the check cache to the new height - app.ResetCheckCache() + if app.nTxs > 0 { + log.Info("Reset checkCache", "txs", app.nTxs) + app.checkCache = sm.NewBlockCache(app.state) + } + app.nTxs = 0 // save state to disk app.state.Save()