From 14fe03cbfecf508848bcd1172ea8d2ee3e41fda4 Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Thu, 30 Jul 2020 22:00:38 -0700 Subject: TWEAK: Set minimum gas price. --- plugin/evm/vm.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index cf5ef8a..7b4d064 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -60,6 +60,10 @@ const ( ) var ( + // minGasPrice is the number of nAVAX required per gas unit for a transaction + // to be valid + minGasPrice = big.NewInt(85) + errEmptyBlock = errors.New("empty block") errCreateBlock = errors.New("couldn't create block") errUnknownBlock = errors.New("unknown block") @@ -140,6 +144,12 @@ func (vm *VM) Initialize( config.Genesis = g config.Miner.ManualMining = true config.Miner.DisableUncle = true + + // Set minimum price for mining and default gas price oracle value to the min + // gas price to prevent so transactions and blocks all use the correct fees + config.Miner.GasPrice = minGasPrice + config.GPO.Default = minGasPrice + if err := config.SetGCMode("archive"); err != nil { panic(err) } -- cgit v1.2.3 From 89df16782ed7a6b45600f3685371b8574b12f1ff Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Wed, 12 Aug 2020 21:49:21 -0400 Subject: increased cache sizes --- plugin/evm/vm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index c710b9d..c22d9d1 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -53,6 +53,7 @@ const ( minBlockTime = 250 * time.Millisecond maxBlockTime = 1000 * time.Millisecond batchSize = 250 + cacheSize = 1 << 15 // 32768 ) const ( @@ -183,8 +184,8 @@ func (vm *VM) Initialize( chain.SetOnQueryAcceptedBlock(func() *types.Block { return vm.getLastAccepted().ethBlock }) - vm.blockCache = cache.LRU{Size: 2048} - vm.blockStatusCache = cache.LRU{Size: 1024} + vm.blockCache = cache.LRU{Size: cacheSize} + vm.blockStatusCache = cache.LRU{Size: cacheSize} vm.newBlockChan = make(chan *Block) vm.networkChan = toEngine vm.blockDelayTimer = timer.NewTimer(func() { -- cgit v1.2.3 From 4945ae1427399d9a0f6b3561306f50f360011613 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Wed, 12 Aug 2020 22:50:17 -0400 Subject: read blocks with caching --- plugin/evm/vm.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index c22d9d1..6c96870 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -422,10 +422,6 @@ func (vm *VM) updateStatus(blockID ids.ID, status choices.Status) { vm.blockStatusCache.Put(blockID, status) } -func (vm *VM) getCachedBlock(blockID ids.ID) *types.Block { - return vm.chain.GetBlockByHash(blockID.Key()) -} - func (vm *VM) tryBlockGen() error { vm.bdlock.Lock() defer vm.bdlock.Unlock() @@ -474,10 +470,11 @@ func (vm *VM) getCachedStatus(blockID ids.ID) choices.Status { if statusIntf, ok := vm.blockStatusCache.Get(blockID); ok { status = statusIntf.(choices.Status) } else { - blk := vm.chain.GetBlockByHash(blockID.Key()) - if blk == nil { + wrappedBlk := vm.getBlock(blockID) + if wrappedBlk == nil { return choices.Unknown } + blk := wrappedBlk.ethBlock acceptedBlk := vm.lastAccepted.ethBlock // TODO: There must be a better way of doing this. @@ -488,7 +485,7 @@ func (vm *VM) getCachedStatus(blockID ids.ID) choices.Status { highBlock, lowBlock = lowBlock, highBlock } for highBlock.Number().Cmp(lowBlock.Number()) > 0 { - highBlock = vm.chain.GetBlockByHash(highBlock.ParentHash()) + highBlock = vm.getBlock(ids.NewID(highBlock.ParentHash())).ethBlock } if highBlock.Hash() == lowBlock.Hash() { // on the same branch @@ -508,7 +505,7 @@ func (vm *VM) getBlock(id ids.ID) *Block { if blockIntf, ok := vm.blockCache.Get(id); ok { return blockIntf.(*Block) } - ethBlock := vm.getCachedBlock(id) + ethBlock := vm.chain.GetBlockByHash(id.Key()) if ethBlock == nil { return nil } -- cgit v1.2.3 From 4676ebb4aca5464e9ecba47f9db7e63593e92a0e Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Thu, 13 Aug 2020 01:00:42 -0400 Subject: fixed nil pointer error in getCachedStatus + removed ip filter --- plugin/evm/vm.go | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 6c96870..7e9e205 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -10,8 +10,6 @@ import ( "errors" "fmt" "math/big" - "net" - "net/http" "sync" "sync/atomic" "time" @@ -359,23 +357,6 @@ func (vm *VM) LastAccepted() ids.ID { return vm.lastAccepted.ID() } -type ipFilter struct { - handler http.Handler -} - -func (ipf ipFilter) ServeHTTP(writer http.ResponseWriter, request *http.Request) { - if ips, _, err := net.SplitHostPort(request.RemoteAddr); err == nil && ips == "127.0.0.1" { - ipf.handler.ServeHTTP(writer, request) - return - } - writer.WriteHeader(404) - writer.Write([]byte("404 page not found\r\n")) -} - -func newIPFilter(handler http.Handler) http.Handler { - return ipFilter{handler} -} - // CreateHandlers makes new http handlers that can handle API calls func (vm *VM) CreateHandlers() map[string]*commonEng.HTTPHandler { handler := vm.chain.NewRPCHandler() @@ -387,8 +368,8 @@ func (vm *VM) CreateHandlers() map[string]*commonEng.HTTPHandler { handler.RegisterName("admin", &admin.Performance{}) return map[string]*commonEng.HTTPHandler{ - "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: newIPFilter(handler)}, - "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: newIPFilter(handler.WebsocketHandler([]string{"*"}))}, + "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler}, + "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandler([]string{"*"})}, } } @@ -397,8 +378,8 @@ func (vm *VM) CreateStaticHandlers() map[string]*commonEng.HTTPHandler { handler := rpc.NewServer() handler.RegisterName("static", &StaticService{}) return map[string]*commonEng.HTTPHandler{ - "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: newIPFilter(handler)}, - "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: newIPFilter(handler.WebsocketHandler([]string{"*"}))}, + "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler}, + "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandler([]string{"*"})}, } } @@ -485,7 +466,12 @@ func (vm *VM) getCachedStatus(blockID ids.ID) choices.Status { highBlock, lowBlock = lowBlock, highBlock } for highBlock.Number().Cmp(lowBlock.Number()) > 0 { - highBlock = vm.getBlock(ids.NewID(highBlock.ParentHash())).ethBlock + parentBlock := vm.getBlock(ids.NewID(highBlock.ParentHash())) + if parentBlock == nil { + vm.blockStatusCache.Put(blockID, choices.Processing) + return choices.Processing + } + highBlock = parentBlock.ethBlock } if highBlock.Hash() == lowBlock.Hash() { // on the same branch -- cgit v1.2.3 From 0d2a35293b7aa49d143ce215591104aba1c89388 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Thu, 13 Aug 2020 02:34:53 -0400 Subject: yuge cache, all the cache --- plugin/evm/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 7e9e205..c55bfe6 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -51,7 +51,7 @@ const ( minBlockTime = 250 * time.Millisecond maxBlockTime = 1000 * time.Millisecond batchSize = 250 - cacheSize = 1 << 15 // 32768 + cacheSize = 1 << 17 // 131072 ) const ( -- cgit v1.2.3 From 88cc3698b3663972cd9b60faf5c14a7e1bbee965 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 13 Aug 2020 21:11:56 -0400 Subject: WIP: X-to-C transfer --- plugin/evm/vm.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index cf5ef8a..18eca47 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -20,9 +20,10 @@ import ( "github.com/ava-labs/coreth/eth" "github.com/ava-labs/coreth/node" - "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/rlp" + "github.com/ava-labs/go-ethereum/rpc" + avarpc "github.com/gorilla/rpc/v2" "github.com/ava-labs/gecko/api/admin" "github.com/ava-labs/gecko/cache" @@ -31,7 +32,11 @@ import ( "github.com/ava-labs/gecko/snow" "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" + "github.com/ava-labs/gecko/utils/codec" + avajson "github.com/ava-labs/gecko/utils/json" "github.com/ava-labs/gecko/utils/timer" + "github.com/ava-labs/gecko/utils/wrappers" + "github.com/ava-labs/gecko/vms/components/ava" commonEng "github.com/ava-labs/gecko/snow/engine/common" ) @@ -59,6 +64,10 @@ const ( bdTimerStateLong ) +const ( + addressSep = "-" +) + var ( errEmptyBlock = errors.New("empty block") errCreateBlock = errors.New("couldn't create block") @@ -66,6 +75,7 @@ var ( errBlockFrequency = errors.New("too frequent block issuance") errUnsupportedFXs = errors.New("unsupported feature extensions") errInvalidBlock = errors.New("invalid block") + errInvalidAddr = errors.New("invalid hex address") ) func maxDuration(x, y time.Duration) time.Duration { @@ -75,6 +85,21 @@ func maxDuration(x, y time.Duration) time.Duration { return y } +// Codec does serialization and deserialization +var Codec codec.Codec + +func init() { + Codec = codec.NewDefault() + + errs := wrappers.Errs{} + errs.Add( + Codec.RegisterType(&UnsignedImportTx{}), + ) + if errs.Errored() { + panic(errs.Err) + } +} + // VM implements the snowman.ChainVM interface type VM struct { ctx *snow.Context @@ -105,6 +130,11 @@ type VM struct { genlock sync.Mutex txSubmitChan <-chan struct{} + codec codec.Codec + clock timer.Clock + avaxAssetID ids.ID + txFee uint64 + //atomicTxPool [] } /* @@ -259,6 +289,7 @@ func (vm *VM) Initialize( } } }) + vm.codec = Codec return nil } @@ -356,6 +387,26 @@ func (vm *VM) LastAccepted() ids.ID { return vm.lastAccepted.ID() } +// NewHandler returns a new Handler for a service where: +// * The handler's functionality is defined by [service] +// [service] should be a gorilla RPC service (see https://www.gorillatoolkit.org/pkg/rpc/v2) +// * The name of the service is [name] +// * The LockOption is the first element of [lockOption] +// By default the LockOption is WriteLock +// [lockOption] should have either 0 or 1 elements. Elements beside the first are ignored. +func newHandler(name string, service interface{}, lockOption ...commonEng.LockOption) *commonEng.HTTPHandler { + server := avarpc.NewServer() + server.RegisterCodec(avajson.NewCodec(), "application/json") + server.RegisterCodec(avajson.NewCodec(), "application/json;charset=UTF-8") + server.RegisterService(service, name) + + var lock commonEng.LockOption = commonEng.WriteLock + if len(lockOption) != 0 { + lock = lockOption[0] + } + return &commonEng.HTTPHandler{LockOptions: lock, Handler: server} +} + // CreateHandlers makes new http handlers that can handle API calls func (vm *VM) CreateHandlers() map[string]*commonEng.HTTPHandler { handler := vm.chain.NewRPCHandler() @@ -368,6 +419,7 @@ func (vm *VM) CreateHandlers() map[string]*commonEng.HTTPHandler { return map[string]*commonEng.HTTPHandler{ "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler}, + "/ava": newHandler("", &AvaAPI{vm}), "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandler([]string{"*"})}, } } @@ -531,3 +583,25 @@ func (vm *VM) getLastAccepted() *Block { return vm.lastAccepted } + +func (vm *VM) ParseAddress(addrStr string) (common.Address, error) { + if !common.IsHexAddress(addrStr) { + return common.Address{}, errInvalidAddr + } + return common.HexToAddress(addrStr), nil +} + +func (vm *VM) FormatAddress(addr common.Address) (string, error) { + return addr.Hex(), nil +} + +func (vm *VM) issueTx(tx *AtomicTx) error { + return nil +} + +// GetAtomicUTXOs returns the utxos that at least one of the provided addresses is +// referenced in. +func (vm *VM) GetAtomicUTXOs(addrs ids.Set) ([]*ava.UTXO, error) { + utxos := []*ava.UTXO{} + return utxos, nil +} -- cgit v1.2.3 From b989b5f949424f72b125cbec460824b94b7c55ab Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 13 Aug 2020 21:30:56 -0400 Subject: ... --- plugin/evm/vm.go | 1 + 1 file changed, 1 insertion(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 18eca47..1010d60 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -602,6 +602,7 @@ func (vm *VM) issueTx(tx *AtomicTx) error { // GetAtomicUTXOs returns the utxos that at least one of the provided addresses is // referenced in. func (vm *VM) GetAtomicUTXOs(addrs ids.Set) ([]*ava.UTXO, error) { + // TODO: finish this function via gRPC utxos := []*ava.UTXO{} return utxos, nil } -- cgit v1.2.3 From 0844c8c6919f6d98ebe8a9501360ef5bc362dff3 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 01:25:20 -0400 Subject: catch up with the new P-Chain cross-chain impl --- plugin/evm/vm.go | 83 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 21 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 1010d60..4fe4cc0 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -16,6 +16,7 @@ import ( "github.com/ava-labs/coreth" "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/eth" "github.com/ava-labs/coreth/node" @@ -33,10 +34,12 @@ import ( "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" "github.com/ava-labs/gecko/utils/codec" + //"github.com/ava-labs/gecko/utils/constants" + //"github.com/ava-labs/gecko/utils/formatting" avajson "github.com/ava-labs/gecko/utils/json" "github.com/ava-labs/gecko/utils/timer" "github.com/ava-labs/gecko/utils/wrappers" - "github.com/ava-labs/gecko/vms/components/ava" + "github.com/ava-labs/gecko/vms/components/avax" commonEng "github.com/ava-labs/gecko/snow/engine/common" ) @@ -69,13 +72,14 @@ const ( ) var ( - errEmptyBlock = errors.New("empty block") - errCreateBlock = errors.New("couldn't create block") - errUnknownBlock = errors.New("unknown block") - errBlockFrequency = errors.New("too frequent block issuance") - errUnsupportedFXs = errors.New("unsupported feature extensions") - errInvalidBlock = errors.New("invalid block") - errInvalidAddr = errors.New("invalid hex address") + errEmptyBlock = errors.New("empty block") + errCreateBlock = errors.New("couldn't create block") + errUnknownBlock = errors.New("unknown block") + errBlockFrequency = errors.New("too frequent block issuance") + errUnsupportedFXs = errors.New("unsupported feature extensions") + errInvalidBlock = errors.New("invalid block") + errInvalidAddr = errors.New("invalid hex address") + errTooManyAtomicTx = errors.New("too many pending atomix txs") ) func maxDuration(x, y time.Duration) time.Duration { @@ -128,13 +132,25 @@ type VM struct { bdGenWaitFlag bool bdGenFlag bool - genlock sync.Mutex - txSubmitChan <-chan struct{} - codec codec.Codec - clock timer.Clock - avaxAssetID ids.ID - txFee uint64 - //atomicTxPool [] + genlock sync.Mutex + txSubmitChan <-chan struct{} + codec codec.Codec + clock timer.Clock + avaxAssetID ids.ID + avm ids.ID + txFee uint64 + pendingAtomicTxs chan *Tx + blockAtomicInputCache cache.LRU +} + +func (vm *VM) getAtomicTx(block *types.Block) *Tx { + var atx *Tx + if extdata := block.ExtraData(); extdata != nil { + if err := vm.codec.Unmarshal(block.ExtraData(), atx); err != nil { + panic(err) + } + } + return atx } /* @@ -191,6 +207,11 @@ func (vm *VM) Initialize( vm.newBlockChan <- nil return errEmptyBlock } + select { + case atx := <-vm.pendingAtomicTxs: + raw, _ := vm.codec.Marshal(atx) + block.SetExtraData(raw) + } return nil }) chain.SetOnSealFinish(func(block *types.Block) error { @@ -211,8 +232,14 @@ func (vm *VM) Initialize( chain.SetOnQueryAcceptedBlock(func() *types.Block { return vm.getLastAccepted().ethBlock }) + chain.SetOnExtraStateChange(func(block *types.Block, statedb *state.StateDB) error { + atx := vm.getAtomicTx(block).UnsignedTx.(*UnsignedImportTx) + vm.ctx.Log.Info(atx.ID().String()) + return nil + }) vm.blockCache = cache.LRU{Size: 2048} vm.blockStatusCache = cache.LRU{Size: 1024} + vm.blockAtomicInputCache = cache.LRU{Size: 4096} vm.newBlockChan = make(chan *Block) vm.networkChan = toEngine vm.blockDelayTimer = timer.NewTimer(func() { @@ -236,6 +263,8 @@ func (vm *VM) Initialize( vm.bdGenWaitFlag = true vm.newTxPoolHeadChan = make(chan core.NewTxPoolHeadEvent, 1) vm.txPoolStabilizedOk = make(chan struct{}, 1) + // TODO: read size from options + vm.pendingAtomicTxs = make(chan *Tx, 1024) chain.GetTxPool().SubscribeNewHeadEvent(vm.newTxPoolHeadChan) // TODO: shutdown this go routine go ctx.Log.RecoverAndPanic(func() { @@ -419,7 +448,7 @@ func (vm *VM) CreateHandlers() map[string]*commonEng.HTTPHandler { return map[string]*commonEng.HTTPHandler{ "/rpc": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler}, - "/ava": newHandler("", &AvaAPI{vm}), + "/ava": newHandler("ava", &AvaAPI{vm}), "/ws": &commonEng.HTTPHandler{LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandler([]string{"*"})}, } } @@ -584,7 +613,8 @@ func (vm *VM) getLastAccepted() *Block { return vm.lastAccepted } -func (vm *VM) ParseAddress(addrStr string) (common.Address, error) { +// ParseLocalAddress takes in an address for this chain and produces the ID +func (vm *VM) ParseLocalAddress(addrStr string) (common.Address, error) { if !common.IsHexAddress(addrStr) { return common.Address{}, errInvalidAddr } @@ -595,14 +625,25 @@ func (vm *VM) FormatAddress(addr common.Address) (string, error) { return addr.Hex(), nil } -func (vm *VM) issueTx(tx *AtomicTx) error { +func (vm *VM) issueTx(tx *Tx) error { + select { + case vm.pendingAtomicTxs <- tx: + default: + return errTooManyAtomicTx + } return nil } // GetAtomicUTXOs returns the utxos that at least one of the provided addresses is // referenced in. -func (vm *VM) GetAtomicUTXOs(addrs ids.Set) ([]*ava.UTXO, error) { +func (vm *VM) GetAtomicUTXOs( + chainID ids.ID, + addrs ids.ShortSet, + startAddr ids.ShortID, + startUTXOID ids.ID, + limit int, +) ([]*avax.UTXO, ids.ShortID, ids.ID, error) { // TODO: finish this function via gRPC - utxos := []*ava.UTXO{} - return utxos, nil + utxos := []*avax.UTXO{} + return utxos, ids.ShortEmpty, ids.Empty, nil } -- cgit v1.2.3 From 315ad2c63fa4879e5a91c3aa013c93f8f4969362 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 11:16:35 -0400 Subject: finish the block verification impl --- plugin/evm/vm.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 4fe4cc0..7a310bf 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -134,6 +134,7 @@ type VM struct { genlock sync.Mutex txSubmitChan <-chan struct{} + atomicTxSubmitChan chan struct{} codec codec.Codec clock timer.Clock avaxAssetID ids.ID @@ -211,6 +212,7 @@ func (vm *VM) Initialize( case atx := <-vm.pendingAtomicTxs: raw, _ := vm.codec.Marshal(atx) block.SetExtraData(raw) + // TODO: make sure the atomic Tx is valid } return nil }) @@ -313,6 +315,9 @@ func (vm *VM) Initialize( case <-vm.txSubmitChan: vm.ctx.Log.Verbo("New tx detected, trying to generate a block") vm.tryBlockGen() + case <-vm.atomicTxSubmitChan: + vm.ctx.Log.Verbo("New atomic Tx detected, trying to generate a block") + vm.tryBlockGen() case <-time.After(5 * time.Second): vm.tryBlockGen() } @@ -628,6 +633,7 @@ func (vm *VM) FormatAddress(addr common.Address) (string, error) { func (vm *VM) issueTx(tx *Tx) error { select { case vm.pendingAtomicTxs <- tx: + vm.atomicTxSubmitChan <- struct{}{} default: return errTooManyAtomicTx } -- cgit v1.2.3 From fbcfc73c7a92d0a2615ef90c4dffa4746161b9c7 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 11:45:32 -0400 Subject: ... --- plugin/evm/vm.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 7a310bf..b72ac49 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -173,6 +173,8 @@ func (vm *VM) Initialize( } vm.ctx = ctx + vm.avaxAssetID = ctx.AVAXAssetID + vm.avm = ctx.XChainID vm.chaindb = Database{db} g := new(core.Genesis) err := json.Unmarshal(b, g) @@ -237,6 +239,11 @@ func (vm *VM) Initialize( chain.SetOnExtraStateChange(func(block *types.Block, statedb *state.StateDB) error { atx := vm.getAtomicTx(block).UnsignedTx.(*UnsignedImportTx) vm.ctx.Log.Info(atx.ID().String()) + for _, to := range atx.Outs { + amount := new(big.Int) + amount.SetUint64(to.Amount) + statedb.AddBalance(to.Address, amount) + } return nil }) vm.blockCache = cache.LRU{Size: 2048} -- cgit v1.2.3 From ec103c07738b3db70501dee7a7da113edbb68875 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 16:13:57 -0400 Subject: ... --- plugin/evm/vm.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index b72ac49..7cbfabd 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -34,6 +34,7 @@ import ( "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" "github.com/ava-labs/gecko/utils/codec" + "github.com/ava-labs/gecko/vms/secp256k1fx" //"github.com/ava-labs/gecko/utils/constants" //"github.com/ava-labs/gecko/utils/formatting" avajson "github.com/ava-labs/gecko/utils/json" @@ -98,6 +99,13 @@ func init() { errs := wrappers.Errs{} errs.Add( Codec.RegisterType(&UnsignedImportTx{}), + Codec.RegisterType(&secp256k1fx.TransferInput{}), + Codec.RegisterType(&secp256k1fx.Input{}), + Codec.RegisterType(&secp256k1fx.Credential{}), + Codec.RegisterType(&secp256k1fx.TransferOutput{}), + Codec.RegisterType(&secp256k1fx.OutputOwners{}), + Codec.RegisterType(&secp256k1fx.MintOperation{}), + Codec.RegisterType(&secp256k1fx.MintOutput{}), ) if errs.Errored() { panic(errs.Err) @@ -657,6 +665,11 @@ func (vm *VM) GetAtomicUTXOs( limit int, ) ([]*avax.UTXO, ids.ShortID, ids.ID, error) { // TODO: finish this function via gRPC - utxos := []*avax.UTXO{} + utxos := []*avax.UTXO{{ + Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 100, + }, + }} return utxos, ids.ShortEmpty, ids.Empty, nil } -- cgit v1.2.3 From 1e9599e88a5d88e0090b0ebddfae756e343e605a Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 20:32:18 -0400 Subject: make the basic X-to-C logic work --- plugin/evm/vm.go | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 7cbfabd..baf6106 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -34,13 +34,11 @@ import ( "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" "github.com/ava-labs/gecko/utils/codec" - "github.com/ava-labs/gecko/vms/secp256k1fx" - //"github.com/ava-labs/gecko/utils/constants" - //"github.com/ava-labs/gecko/utils/formatting" avajson "github.com/ava-labs/gecko/utils/json" "github.com/ava-labs/gecko/utils/timer" "github.com/ava-labs/gecko/utils/wrappers" "github.com/ava-labs/gecko/vms/components/avax" + "github.com/ava-labs/gecko/vms/secp256k1fx" commonEng "github.com/ava-labs/gecko/snow/engine/common" ) @@ -153,9 +151,9 @@ type VM struct { } func (vm *VM) getAtomicTx(block *types.Block) *Tx { - var atx *Tx + atx := new(Tx) if extdata := block.ExtraData(); extdata != nil { - if err := vm.codec.Unmarshal(block.ExtraData(), atx); err != nil { + if err := vm.codec.Unmarshal(extdata, atx); err != nil { panic(err) } } @@ -212,19 +210,24 @@ func (vm *VM) Initialize( } header.Extra = append(header.Extra, hid...) }) - chain.SetOnSeal(func(block *types.Block) error { - if len(block.Transactions()) == 0 { - // this could happen due to the async logic of geth tx pool - vm.newBlockChan <- nil - return errEmptyBlock - } + chain.SetOnFinalizeAndAssemble(func(state *state.StateDB, txs []*types.Transaction) ([]byte, error) { select { case atx := <-vm.pendingAtomicTxs: + for _, to := range atx.UnsignedTx.(*UnsignedImportTx).Outs { + amount := new(big.Int) + amount.SetUint64(to.Amount) + state.AddBalance(to.Address, amount) + } raw, _ := vm.codec.Marshal(atx) - block.SetExtraData(raw) - // TODO: make sure the atomic Tx is valid + return raw, nil + default: + if len(txs) == 0 { + // this could happen due to the async logic of geth tx pool + vm.newBlockChan <- nil + return nil, errEmptyBlock + } } - return nil + return nil, nil }) chain.SetOnSealFinish(func(block *types.Block) error { vm.ctx.Log.Verbo("EVM sealed a block") @@ -234,6 +237,9 @@ func (vm *VM) Initialize( ethBlock: block, vm: vm, } + if blk.Verify() != nil { + return errInvalidBlock + } vm.newBlockChan <- blk vm.updateStatus(ids.NewID(block.Hash()), choices.Processing) vm.txPoolStabilizedLock.Lock() @@ -246,7 +252,6 @@ func (vm *VM) Initialize( }) chain.SetOnExtraStateChange(func(block *types.Block, statedb *state.StateDB) error { atx := vm.getAtomicTx(block).UnsignedTx.(*UnsignedImportTx) - vm.ctx.Log.Info(atx.ID().String()) for _, to := range atx.Outs { amount := new(big.Int) amount.SetUint64(to.Amount) @@ -282,6 +287,7 @@ func (vm *VM) Initialize( vm.txPoolStabilizedOk = make(chan struct{}, 1) // TODO: read size from options vm.pendingAtomicTxs = make(chan *Tx, 1024) + vm.atomicTxSubmitChan = make(chan struct{}, 1) chain.GetTxPool().SubscribeNewHeadEvent(vm.newTxPoolHeadChan) // TODO: shutdown this go routine go ctx.Log.RecoverAndPanic(func() { @@ -523,7 +529,7 @@ func (vm *VM) tryBlockGen() error { if err != nil { return err } - if size == 0 { + if size == 0 && len(vm.pendingAtomicTxs) == 0 { return nil } @@ -648,7 +654,10 @@ func (vm *VM) FormatAddress(addr common.Address) (string, error) { func (vm *VM) issueTx(tx *Tx) error { select { case vm.pendingAtomicTxs <- tx: - vm.atomicTxSubmitChan <- struct{}{} + select { + case vm.atomicTxSubmitChan <- struct{}{}: + default: + } default: return errTooManyAtomicTx } @@ -666,7 +675,8 @@ func (vm *VM) GetAtomicUTXOs( ) ([]*avax.UTXO, ids.ShortID, ids.ID, error) { // TODO: finish this function via gRPC utxos := []*avax.UTXO{{ - Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, + UTXOID: avax.UTXOID{TxID: ids.Empty}, + Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ Amt: 100, }, -- cgit v1.2.3 From 40879ea67433b73b464bd8b012a9809fbb646cfd Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 23:34:12 -0400 Subject: WIP: C-to-X transfer --- plugin/evm/vm.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 11 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index baf6106..5bb8ac0 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -22,6 +22,7 @@ import ( "github.com/ava-labs/coreth/node" "github.com/ava-labs/go-ethereum/common" + ethcrypto "github.com/ava-labs/go-ethereum/crypto" "github.com/ava-labs/go-ethereum/rlp" "github.com/ava-labs/go-ethereum/rpc" avarpc "github.com/gorilla/rpc/v2" @@ -34,6 +35,7 @@ import ( "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" "github.com/ava-labs/gecko/utils/codec" + "github.com/ava-labs/gecko/utils/crypto" avajson "github.com/ava-labs/gecko/utils/json" "github.com/ava-labs/gecko/utils/timer" "github.com/ava-labs/gecko/utils/wrappers" @@ -48,6 +50,7 @@ var ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } + x2cRate = big.NewInt(1000000000) ) const ( @@ -160,6 +163,15 @@ func (vm *VM) getAtomicTx(block *types.Block) *Tx { return atx } +func importTxStateTransfer(tx *UnsignedImportTx, state *state.StateDB) { + for _, to := range tx.Outs { + amount := new(big.Int).SetUint64(to.Amount) + state.AddBalance(to.Address, new(big.Int).Mul(amount, x2cRate)) + nonce := state.GetNonce(to.Address) + state.SetNonce(to.Address, nonce+1) + } +} + /* ****************************************************************************** ********************************* Snowman API ******************************** @@ -213,11 +225,7 @@ func (vm *VM) Initialize( chain.SetOnFinalizeAndAssemble(func(state *state.StateDB, txs []*types.Transaction) ([]byte, error) { select { case atx := <-vm.pendingAtomicTxs: - for _, to := range atx.UnsignedTx.(*UnsignedImportTx).Outs { - amount := new(big.Int) - amount.SetUint64(to.Amount) - state.AddBalance(to.Address, amount) - } + importTxStateTransfer(atx.UnsignedTx.(*UnsignedImportTx), state) raw, _ := vm.codec.Marshal(atx) return raw, nil default: @@ -250,13 +258,9 @@ func (vm *VM) Initialize( chain.SetOnQueryAcceptedBlock(func() *types.Block { return vm.getLastAccepted().ethBlock }) - chain.SetOnExtraStateChange(func(block *types.Block, statedb *state.StateDB) error { + chain.SetOnExtraStateChange(func(block *types.Block, state *state.StateDB) error { atx := vm.getAtomicTx(block).UnsignedTx.(*UnsignedImportTx) - for _, to := range atx.Outs { - amount := new(big.Int) - amount.SetUint64(to.Amount) - statedb.AddBalance(to.Address, amount) - } + importTxStateTransfer(atx, state) return nil }) vm.blockCache = cache.LRU{Size: 2048} @@ -683,3 +687,38 @@ func (vm *VM) GetAtomicUTXOs( }} return utxos, ids.ShortEmpty, ids.Empty, nil } + +func GetEthAddress(privKey *crypto.PrivateKeySECP256K1R) common.Address { + return ethcrypto.PubkeyToAddress( + (*privKey.PublicKey().(*crypto.PublicKeySECP256K1R).ToECDSA())) +} + +func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount uint64) ([]EVMInput, [][]*crypto.PrivateKeySECP256K1R, error) { + // NOTE: should we use HEAD block or lastAccepted? + state, err := vm.chain.BlockState(vm.lastAccepted.ethBlock) + if err != nil { + return nil, nil, err + } + inputs := []EVMInput{} + signers := [][]*crypto.PrivateKeySECP256K1R{} + for _, key := range keys { + if amount == 0 { + break + } + addr := GetEthAddress(key) + balance := new(big.Int).Div(state.GetBalance(addr), x2cRate).Uint64() + if amount < balance { + balance = amount + } + inputs = append(inputs, EVMInput{ + Address: addr, + Amount: balance, + }) + signers = append(signers, []*crypto.PrivateKeySECP256K1R{key}) + amount -= balance + } + if amount > 0 { + return nil, nil, errInsufficientFunds + } + return inputs, signers, nil +} -- cgit v1.2.3 From c6fbdb0dc9453bf4dbf43490d7d83b7a4de2f182 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 23:42:43 -0400 Subject: clean up code --- plugin/evm/vm.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 5bb8ac0..292e383 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -163,15 +163,6 @@ func (vm *VM) getAtomicTx(block *types.Block) *Tx { return atx } -func importTxStateTransfer(tx *UnsignedImportTx, state *state.StateDB) { - for _, to := range tx.Outs { - amount := new(big.Int).SetUint64(to.Amount) - state.AddBalance(to.Address, new(big.Int).Mul(amount, x2cRate)) - nonce := state.GetNonce(to.Address) - state.SetNonce(to.Address, nonce+1) - } -} - /* ****************************************************************************** ********************************* Snowman API ******************************** @@ -225,7 +216,7 @@ func (vm *VM) Initialize( chain.SetOnFinalizeAndAssemble(func(state *state.StateDB, txs []*types.Transaction) ([]byte, error) { select { case atx := <-vm.pendingAtomicTxs: - importTxStateTransfer(atx.UnsignedTx.(*UnsignedImportTx), state) + atx.UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) raw, _ := vm.codec.Marshal(atx) return raw, nil default: @@ -259,8 +250,7 @@ func (vm *VM) Initialize( return vm.getLastAccepted().ethBlock }) chain.SetOnExtraStateChange(func(block *types.Block, state *state.StateDB) error { - atx := vm.getAtomicTx(block).UnsignedTx.(*UnsignedImportTx) - importTxStateTransfer(atx, state) + vm.getAtomicTx(block).UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) return nil }) vm.blockCache = cache.LRU{Size: 2048} -- cgit v1.2.3 From 2d409cb9790e55fd014546222f448786bbefa46b Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 19 Aug 2020 23:48:47 -0400 Subject: ... --- plugin/evm/vm.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 292e383..53810ee 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -74,14 +74,27 @@ const ( ) var ( - errEmptyBlock = errors.New("empty block") - errCreateBlock = errors.New("couldn't create block") - errUnknownBlock = errors.New("unknown block") - errBlockFrequency = errors.New("too frequent block issuance") - errUnsupportedFXs = errors.New("unsupported feature extensions") - errInvalidBlock = errors.New("invalid block") - errInvalidAddr = errors.New("invalid hex address") - errTooManyAtomicTx = errors.New("too many pending atomix txs") + errEmptyBlock = errors.New("empty block") + errCreateBlock = errors.New("couldn't create block") + errUnknownBlock = errors.New("unknown block") + errBlockFrequency = errors.New("too frequent block issuance") + errUnsupportedFXs = errors.New("unsupported feature extensions") + errInvalidBlock = errors.New("invalid block") + errInvalidAddr = errors.New("invalid hex address") + errTooManyAtomicTx = errors.New("too many pending atomix txs") + errAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo") + errWrongNumberOfCredentials = errors.New("should have the same number of credentials as inputs") + errNoInputs = errors.New("tx has no inputs") + errNoImportInputs = errors.New("tx has no imported inputs") + errInputsNotSortedUnique = errors.New("inputs not sorted and unique") + errPublicKeySignatureMismatch = errors.New("signature doesn't match public key") + errUnknownAsset = errors.New("unknown asset ID") + errNoFunds = errors.New("no spendable funds were found") + errWrongChainID = errors.New("tx has wrong chain ID") + errInsufficientFunds = errors.New("insufficient funds") + errNoExportOutputs = errors.New("no export outputs") + errOutputsNotSorted = errors.New("outputs not sorted") + errOverflowExport = errors.New("overflow when computing export amount + txFee") ) func maxDuration(x, y time.Duration) time.Duration { @@ -146,8 +159,6 @@ type VM struct { atomicTxSubmitChan chan struct{} codec codec.Codec clock timer.Clock - avaxAssetID ids.ID - avm ids.ID txFee uint64 pendingAtomicTxs chan *Tx blockAtomicInputCache cache.LRU @@ -182,8 +193,6 @@ func (vm *VM) Initialize( } vm.ctx = ctx - vm.avaxAssetID = ctx.AVAXAssetID - vm.avm = ctx.XChainID vm.chaindb = Database{db} g := new(core.Genesis) err := json.Unmarshal(b, g) -- cgit v1.2.3 From 0c417aaa02c5cc8bb6a9629ac2502e0c4d200071 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 00:03:12 -0400 Subject: impl state transfer for C-to-X Tx --- plugin/evm/vm.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 53810ee..6155728 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -95,6 +95,7 @@ var ( errNoExportOutputs = errors.New("no export outputs") errOutputsNotSorted = errors.New("outputs not sorted") errOverflowExport = errors.New("overflow when computing export amount + txFee") + errInvalidNonce = errors.New("invalid nonce") ) func maxDuration(x, y time.Duration) time.Duration { @@ -721,3 +722,11 @@ func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount } return inputs, signers, nil } + +func (vm *VM) GetAcceptedNonce(address common.Address) (uint64, error) { + state, err := vm.chain.BlockState(vm.lastAccepted.ethBlock) + if err != nil { + return 0, err + } + return state.GetNonce(address), nil +} -- cgit v1.2.3 From 9f503c997bdb67a40ac2817c6cf0eb780a86f3c1 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 00:14:34 -0400 Subject: add C-to-X RPC --- plugin/evm/vm.go | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 6155728..f62bc7b 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -25,7 +25,7 @@ import ( ethcrypto "github.com/ava-labs/go-ethereum/crypto" "github.com/ava-labs/go-ethereum/rlp" "github.com/ava-labs/go-ethereum/rpc" - avarpc "github.com/gorilla/rpc/v2" + geckorpc "github.com/gorilla/rpc/v2" "github.com/ava-labs/gecko/api/admin" "github.com/ava-labs/gecko/cache" @@ -35,8 +35,10 @@ import ( "github.com/ava-labs/gecko/snow/choices" "github.com/ava-labs/gecko/snow/consensus/snowman" "github.com/ava-labs/gecko/utils/codec" + "github.com/ava-labs/gecko/utils/constants" "github.com/ava-labs/gecko/utils/crypto" - avajson "github.com/ava-labs/gecko/utils/json" + "github.com/ava-labs/gecko/utils/formatting" + geckojson "github.com/ava-labs/gecko/utils/json" "github.com/ava-labs/gecko/utils/timer" "github.com/ava-labs/gecko/utils/wrappers" "github.com/ava-labs/gecko/vms/components/avax" @@ -454,9 +456,9 @@ func (vm *VM) LastAccepted() ids.ID { // By default the LockOption is WriteLock // [lockOption] should have either 0 or 1 elements. Elements beside the first are ignored. func newHandler(name string, service interface{}, lockOption ...commonEng.LockOption) *commonEng.HTTPHandler { - server := avarpc.NewServer() - server.RegisterCodec(avajson.NewCodec(), "application/json") - server.RegisterCodec(avajson.NewCodec(), "application/json;charset=UTF-8") + server := geckorpc.NewServer() + server.RegisterCodec(geckojson.NewCodec(), "application/json") + server.RegisterCodec(geckojson.NewCodec(), "application/json;charset=UTF-8") server.RegisterService(service, name) var lock commonEng.LockOption = commonEng.WriteLock @@ -643,18 +645,43 @@ func (vm *VM) getLastAccepted() *Block { return vm.lastAccepted } -// ParseLocalAddress takes in an address for this chain and produces the ID -func (vm *VM) ParseLocalAddress(addrStr string) (common.Address, error) { +func (vm *VM) ParseEthAddress(addrStr string) (common.Address, error) { if !common.IsHexAddress(addrStr) { return common.Address{}, errInvalidAddr } return common.HexToAddress(addrStr), nil } -func (vm *VM) FormatAddress(addr common.Address) (string, error) { +func (vm *VM) FormatEthAddress(addr common.Address) (string, error) { return addr.Hex(), nil } +// ParseAddress takes in an address and produces the ID of the chain it's for +// the ID of the address +func (vm *VM) ParseAddress(addrStr string) (ids.ID, ids.ShortID, error) { + chainIDAlias, hrp, addrBytes, err := formatting.ParseAddress(addrStr) + if err != nil { + return ids.ID{}, ids.ShortID{}, err + } + + chainID, err := vm.ctx.BCLookup.Lookup(chainIDAlias) + if err != nil { + return ids.ID{}, ids.ShortID{}, err + } + + expectedHRP := constants.GetHRP(vm.ctx.NetworkID) + if hrp != expectedHRP { + return ids.ID{}, ids.ShortID{}, fmt.Errorf("expected hrp %q but got %q", + expectedHRP, hrp) + } + + addr, err := ids.ToShortID(addrBytes) + if err != nil { + return ids.ID{}, ids.ShortID{}, err + } + return chainID, addr, nil +} + func (vm *VM) issueTx(tx *Tx) error { select { case vm.pendingAtomicTxs <- tx: -- cgit v1.2.3 From eeb62be039927d461bcd5bebc456e3ab1a31307c Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 00:27:32 -0400 Subject: move nonce to EVMOutput/Input --- plugin/evm/vm.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index f62bc7b..38646c9 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -737,9 +737,14 @@ func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount if amount < balance { balance = amount } + nonce, err := vm.GetAcceptedNonce(addr) + if err != nil { + return nil, nil, err + } inputs = append(inputs, EVMInput{ Address: addr, Amount: balance, + Nonce: nonce, }) signers = append(signers, []*crypto.PrivateKeySECP256K1R{key}) amount -= balance -- cgit v1.2.3 From 5fc26bb832c715cfd2628585d41bb82209ecdfe4 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 00:44:56 -0400 Subject: ... --- plugin/evm/vm.go | 1 + 1 file changed, 1 insertion(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 38646c9..fffc0d5 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -116,6 +116,7 @@ func init() { errs := wrappers.Errs{} errs.Add( Codec.RegisterType(&UnsignedImportTx{}), + Codec.RegisterType(&UnsignedExportTx{}), Codec.RegisterType(&secp256k1fx.TransferInput{}), Codec.RegisterType(&secp256k1fx.Input{}), Codec.RegisterType(&secp256k1fx.Credential{}), -- cgit v1.2.3 From a054d19f05a31a0421d6fe1bc534da46921481d5 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 01:03:31 -0400 Subject: fix minor bugs --- plugin/evm/vm.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index fffc0d5..8823380 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -229,7 +229,10 @@ func (vm *VM) Initialize( chain.SetOnFinalizeAndAssemble(func(state *state.StateDB, txs []*types.Transaction) ([]byte, error) { select { case atx := <-vm.pendingAtomicTxs: - atx.UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) + if err := atx.UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state); err != nil { + vm.newBlockChan <- nil + return nil, err + } raw, _ := vm.codec.Marshal(atx) return raw, nil default: @@ -263,8 +266,7 @@ func (vm *VM) Initialize( return vm.getLastAccepted().ethBlock }) chain.SetOnExtraStateChange(func(block *types.Block, state *state.StateDB) error { - vm.getAtomicTx(block).UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) - return nil + return vm.getAtomicTx(block).UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) }) vm.blockCache = cache.LRU{Size: 2048} vm.blockStatusCache = cache.LRU{Size: 1024} @@ -735,6 +737,9 @@ func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount } addr := GetEthAddress(key) balance := new(big.Int).Div(state.GetBalance(addr), x2cRate).Uint64() + if balance == 0 { + continue + } if amount < balance { balance = amount } -- cgit v1.2.3 From 1c078567367ef45884da079cecc09a71d1761b01 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Thu, 20 Aug 2020 01:09:43 -0400 Subject: Added first pass of importTx verification --- plugin/evm/vm.go | 78 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 16 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index fffc0d5..f439f59 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -39,6 +39,7 @@ import ( "github.com/ava-labs/gecko/utils/crypto" "github.com/ava-labs/gecko/utils/formatting" geckojson "github.com/ava-labs/gecko/utils/json" + "github.com/ava-labs/gecko/utils/logging" "github.com/ava-labs/gecko/utils/timer" "github.com/ava-labs/gecko/utils/wrappers" "github.com/ava-labs/gecko/vms/components/avax" @@ -63,6 +64,8 @@ const ( minBlockTime = 250 * time.Millisecond maxBlockTime = 1000 * time.Millisecond batchSize = 250 + + maxUTXOsToFetch = 1024 ) const ( @@ -117,13 +120,16 @@ func init() { errs.Add( Codec.RegisterType(&UnsignedImportTx{}), Codec.RegisterType(&UnsignedExportTx{}), + ) + Codec.Skip(3) + errs.Add( Codec.RegisterType(&secp256k1fx.TransferInput{}), - Codec.RegisterType(&secp256k1fx.Input{}), - Codec.RegisterType(&secp256k1fx.Credential{}), + Codec.RegisterType(&secp256k1fx.MintOutput{}), Codec.RegisterType(&secp256k1fx.TransferOutput{}), - Codec.RegisterType(&secp256k1fx.OutputOwners{}), Codec.RegisterType(&secp256k1fx.MintOperation{}), - Codec.RegisterType(&secp256k1fx.MintOutput{}), + Codec.RegisterType(&secp256k1fx.Credential{}), + Codec.RegisterType(&secp256k1fx.Input{}), + Codec.RegisterType(&secp256k1fx.OutputOwners{}), ) if errs.Errored() { panic(errs.Err) @@ -166,6 +172,8 @@ type VM struct { txFee uint64 pendingAtomicTxs chan *Tx blockAtomicInputCache cache.LRU + + fx secp256k1fx.Fx } func (vm *VM) getAtomicTx(block *types.Block) *Tx { @@ -178,6 +186,15 @@ func (vm *VM) getAtomicTx(block *types.Block) *Tx { return atx } +// Codec implements the secp256k1fx interface +func (vm *VM) Codec() codec.Codec { return codec.NewDefault() } + +// Clock implements the secp256k1fx interface +func (vm *VM) Clock() *timer.Clock { return &vm.clock } + +// Logger implements the secp256k1fx interface +func (vm *VM) Logger() logging.Logger { return vm.ctx.Log } + /* ****************************************************************************** ********************************* Snowman API ******************************** @@ -353,16 +370,16 @@ func (vm *VM) Initialize( }) vm.codec = Codec - return nil + return vm.fx.Initialize(vm) } // Bootstrapping notifies this VM that the consensus engine is performing // bootstrapping -func (vm *VM) Bootstrapping() error { return nil } +func (vm *VM) Bootstrapping() error { return vm.fx.Bootstrapping() } // Bootstrapped notifies this VM that the consensus engine has finished // bootstrapping -func (vm *VM) Bootstrapped() error { return nil } +func (vm *VM) Bootstrapped() error { return vm.fx.Bootstrapped() } // Shutdown implements the snowman.ChainVM interface func (vm *VM) Shutdown() error { @@ -705,15 +722,44 @@ func (vm *VM) GetAtomicUTXOs( startUTXOID ids.ID, limit int, ) ([]*avax.UTXO, ids.ShortID, ids.ID, error) { - // TODO: finish this function via gRPC - utxos := []*avax.UTXO{{ - UTXOID: avax.UTXOID{TxID: ids.Empty}, - Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 100, - }, - }} - return utxos, ids.ShortEmpty, ids.Empty, nil + if limit <= 0 || limit > maxUTXOsToFetch { + limit = maxUTXOsToFetch + } + + addrsList := make([][]byte, addrs.Len()) + for i, addr := range addrs.List() { + addrsList[i] = addr.Bytes() + } + + allUTXOBytes, lastAddr, lastUTXO, err := vm.ctx.SharedMemory.Indexed( + chainID, + addrsList, + startAddr.Bytes(), + startUTXOID.Bytes(), + limit, + ) + if err != nil { + return nil, ids.ShortID{}, ids.ID{}, fmt.Errorf("error fetching atomic UTXOs: %w", err) + } + + lastAddrID, err := ids.ToShortID(lastAddr) + if err != nil { + lastAddrID = ids.ShortEmpty + } + lastUTXOID, err := ids.ToID(lastUTXO) + if err != nil { + lastAddrID = ids.ShortEmpty + } + + utxos := make([]*avax.UTXO, len(allUTXOBytes)) + for i, utxoBytes := range allUTXOBytes { + utxo := &avax.UTXO{} + if err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil { + return nil, ids.ShortID{}, ids.ID{}, fmt.Errorf("error parsing UTXO: %w", err) + } + utxos[i] = utxo + } + return utxos, lastAddrID, lastUTXOID, nil } func GetEthAddress(privKey *crypto.PrivateKeySECP256K1R) common.Address { -- cgit v1.2.3 From b3fb1dc6ed3c5610c03abdd6f2ff7bf164fb83ca Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 20 Aug 2020 02:21:57 -0400 Subject: add flow check for ExportTx --- plugin/evm/vm.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 8823380..98ecb6f 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -175,6 +175,7 @@ func (vm *VM) getAtomicTx(block *types.Block) *Tx { panic(err) } } + atx.Sign(vm.codec, nil) return atx } @@ -719,8 +720,12 @@ func (vm *VM) GetAtomicUTXOs( } func GetEthAddress(privKey *crypto.PrivateKeySECP256K1R) common.Address { + return PublicKeyToEthAddress(privKey.PublicKey()) +} + +func PublicKeyToEthAddress(pubKey crypto.PublicKey) common.Address { return ethcrypto.PubkeyToAddress( - (*privKey.PublicKey().(*crypto.PublicKeySECP256K1R).ToECDSA())) + (*pubKey.(*crypto.PublicKeySECP256K1R).ToECDSA())) } func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount uint64) ([]EVMInput, [][]*crypto.PrivateKeySECP256K1R, error) { -- cgit v1.2.3 From 52c6ccd2f063a6cccc35f5b4380b22fb9dd0f102 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Thu, 20 Aug 2020 09:42:06 -0400 Subject: implemented exportTx accept --- plugin/evm/vm.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 0910f6d..4ea3793 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -177,11 +177,10 @@ type VM struct { } func (vm *VM) getAtomicTx(block *types.Block) *Tx { + extdata := block.ExtraData() atx := new(Tx) - if extdata := block.ExtraData(); extdata != nil { - if err := vm.codec.Unmarshal(extdata, atx); err != nil { - panic(err) - } + if err := vm.codec.Unmarshal(extdata, atx); err != nil { + return nil } atx.Sign(vm.codec, nil) return atx @@ -284,7 +283,11 @@ func (vm *VM) Initialize( return vm.getLastAccepted().ethBlock }) chain.SetOnExtraStateChange(func(block *types.Block, state *state.StateDB) error { - return vm.getAtomicTx(block).UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) + tx := vm.getAtomicTx(block) + if tx == nil { + return nil + } + return tx.UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state) }) vm.blockCache = cache.LRU{Size: 2048} vm.blockStatusCache = cache.LRU{Size: 1024} -- cgit v1.2.3 From 6aa9e31ed3082df34373679f98ad2b004bef2ffa Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Thu, 20 Aug 2020 11:31:24 -0400 Subject: fixed copy paste bug --- plugin/evm/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 4ea3793..cc58e8b 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -754,7 +754,7 @@ func (vm *VM) GetAtomicUTXOs( } lastUTXOID, err := ids.ToID(lastUTXO) if err != nil { - lastAddrID = ids.ShortEmpty + lastUTXOID = ids.Empty } utxos := make([]*avax.UTXO, len(allUTXOBytes)) -- cgit v1.2.3 From 9f9c3ac8b840e99db942c01505be987d8b2663d4 Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Mon, 24 Aug 2020 19:27:32 -0700 Subject: TWEAK: Set TxPool PriceLimit to minGas. --- plugin/evm/vm.go | 1 + 1 file changed, 1 insertion(+) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 08d7bcb..f656d02 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -241,6 +241,7 @@ func (vm *VM) Initialize( // gas price to prevent so transactions and blocks all use the correct fees config.Miner.GasPrice = minGasPrice config.GPO.Default = minGasPrice + config.TxPool.PriceLimit = minGasPrice.Uint64() if err := config.SetGCMode("archive"); err != nil { panic(err) -- cgit v1.2.3 From b53cf297e5cccd577af725bacdb7f3ccb61336bd Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Mon, 24 Aug 2020 22:09:52 -0700 Subject: BUGFIX: Fix minGasPrice. --- plugin/evm/vm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index f656d02..b4026a8 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -20,6 +20,7 @@ import ( "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/eth" "github.com/ava-labs/coreth/node" + "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" ethcrypto "github.com/ava-labs/go-ethereum/crypto" @@ -81,8 +82,8 @@ const ( var ( // minGasPrice is the number of nAVAX required per gas unit for a transaction - // to be valid - minGasPrice = big.NewInt(47) + // to be valid, measured in wei + minGasPrice = big.NewInt(47*params.GWei) txFee = units.MilliAvax -- cgit v1.2.3 From b05d11d451fb73843abcf6bd5fc8664b069433a4 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Tue, 25 Aug 2020 13:20:28 -0400 Subject: fixed potential vulnerability with bootstrapping blocks --- plugin/evm/vm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugin/evm/vm.go') diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index b4026a8..e1fdc33 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -83,7 +83,7 @@ const ( var ( // minGasPrice is the number of nAVAX required per gas unit for a transaction // to be valid, measured in wei - minGasPrice = big.NewInt(47*params.GWei) + minGasPrice = big.NewInt(47 * params.GWei) txFee = units.MilliAvax @@ -94,7 +94,7 @@ var ( errUnsupportedFXs = errors.New("unsupported feature extensions") errInvalidBlock = errors.New("invalid block") errInvalidAddr = errors.New("invalid hex address") - errTooManyAtomicTx = errors.New("too many pending atomix txs") + errTooManyAtomicTx = errors.New("too many pending atomic txs") errAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo") errWrongNumberOfCredentials = errors.New("should have the same number of credentials as inputs") errNoInputs = errors.New("tx has no inputs") -- cgit v1.2.3