diff --git a/.gitignore b/.gitignore index 8d3c65fab..ff766a916 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ vendor/ build/ out/ +.run/ *.lock *.txt diff --git a/cmd/custom/node.go b/cmd/custom/node.go index 43cbe000c..7eef9bd65 100644 --- a/cmd/custom/node.go +++ b/cmd/custom/node.go @@ -24,7 +24,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/node/blocks_applier" "github.com/wavesplatform/gowaves/pkg/node/messages" "github.com/wavesplatform/gowaves/pkg/node/peer_manager" - "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + peersPersistentStorage "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" "github.com/wavesplatform/gowaves/pkg/node/state_fsm/ng" "github.com/wavesplatform/gowaves/pkg/p2p/peer" "github.com/wavesplatform/gowaves/pkg/proto" @@ -57,6 +57,7 @@ var ( walletPassword = flag.String("wallet-password", "", "Pass password for wallet. Extremely insecure") limitConnectionsS = flag.String("limit-connections", "30", "N incoming and outgoing connections") minPeersMining = flag.Int("min-peers-mining", 1, "Minimum connected peers for allow mining") + dropPeers = flag.Bool("drop-peers", false, "Drop peers storage before node start.") ) func init() { @@ -190,7 +191,23 @@ func main() { peerSpawnerImpl := peer_manager.NewPeerSpawner(btsPool, parent, conf.WavesNetwork, declAddr, "gowaves", uint64(rand.Int()), version) - peerStorage := storage.NewBinaryStorage(path) + peerStorage, err := peersPersistentStorage.NewCBORStorage(*statePath, time.Now()) + if err != nil { + zap.S().Errorf("Failed to open or create peers storage: %v", err) + cancel() + return + } + if *dropPeers { + if err := peerStorage.DropStorage(); err != nil { + zap.S().Errorf( + "Failed to drop peers storage. Drop peers storage manually. Err: %v", + err, + ) + cancel() + return + } + zap.S().Info("Successfully dropped peers storage") + } peerManager := peer_manager.NewPeerManager(peerSpawnerImpl, peerStorage, int(limitConnections), version) go peerManager.Run(ctx) @@ -234,7 +251,19 @@ func main() { if len(conf.Addresses) > 0 { addresses := strings.Split(conf.Addresses, ",") for _, addr := range addresses { - peerManager.AddAddress(ctx, addr) + tcpAddr := proto.NewTCPAddrFromString(addr) + if tcpAddr.Empty() { + // nickeskov: that means that configuration parameter is invalid + zap.S().Errorf("Failed to parse TCPAddr from string %q", tcpAddr.String()) + cancel() + return + } + if err := peerManager.AddAddress(ctx, tcpAddr); err != nil { + // nickeskov: than means that we have problems with peers storage + zap.S().Errorf("Failed to add addres into know peers storage: %v", err) + cancel() + return + } } } diff --git a/cmd/forkdetector/internal/api.go b/cmd/forkdetector/internal/api.go index e572a7821..1247c22d6 100644 --- a/cmd/forkdetector/internal/api.go +++ b/cmd/forkdetector/internal/api.go @@ -119,7 +119,7 @@ func (a *api) routes() chi.Router { r := chi.NewRouter() r.Get("/status", a.status) // Status information r.Get("/peers/all", a.peers) // Returns the list of all known peers - r.Get("/peers/friendly", a.friendly) // Returns the list of peers that have been successfully handshaked at least once + r.Get("/peers/friendly", a.friendly) // Returns the list of peers that have been successfully connected at least once r.Get("/connections", a.connections) // Returns the list of active connections r.Get("/forks", a.forks) // Returns the combined info about forks for all connected peers r.Get("/all-forks", a.allForks) // Returns the combined info about all registered forks @@ -129,7 +129,7 @@ func (a *api) routes() chi.Router { return r } -func (a *api) status(w http.ResponseWriter, r *http.Request) { +func (a *api) status(w http.ResponseWriter, _ *http.Request) { goroutines := runtime.NumGoroutine() stats := a.drawer.stats() peers, err := a.registry.Peers() @@ -159,7 +159,7 @@ func (a *api) status(w http.ResponseWriter, r *http.Request) { } } -func (a *api) peers(w http.ResponseWriter, r *http.Request) { +func (a *api) peers(w http.ResponseWriter, _ *http.Request) { peers, err := a.registry.Peers() if err != nil { http.Error(w, fmt.Sprintf("Failed to complete request: %v", err), http.StatusInternalServerError) @@ -172,7 +172,7 @@ func (a *api) peers(w http.ResponseWriter, r *http.Request) { } } -func (a *api) friendly(w http.ResponseWriter, r *http.Request) { +func (a *api) friendly(w http.ResponseWriter, _ *http.Request) { peers, err := a.registry.FriendlyPeers() if err != nil { http.Error(w, fmt.Sprintf("Failed to complete request: %v", err), http.StatusInternalServerError) @@ -185,7 +185,7 @@ func (a *api) friendly(w http.ResponseWriter, r *http.Request) { } } -func (a *api) connections(w http.ResponseWriter, r *http.Request) { +func (a *api) connections(w http.ResponseWriter, _ *http.Request) { connections := a.registry.Connections() err := json.NewEncoder(w).Encode(connections) if err != nil { @@ -194,7 +194,7 @@ func (a *api) connections(w http.ResponseWriter, r *http.Request) { } } -func (a *api) forks(w http.ResponseWriter, r *http.Request) { +func (a *api) forks(w http.ResponseWriter, _ *http.Request) { nodes := a.registry.Connections() ips := make([]net.IP, len(nodes)) for i, n := range nodes { @@ -214,7 +214,7 @@ func (a *api) forks(w http.ResponseWriter, r *http.Request) { } } -func (a *api) allForks(w http.ResponseWriter, r *http.Request) { +func (a *api) allForks(w http.ResponseWriter, _ *http.Request) { nodes, err := a.registry.Peers() if err != nil { http.Error(w, fmt.Sprintf("Failed to complete request: %v", err), http.StatusInternalServerError) diff --git a/cmd/node/node.go b/cmd/node/node.go index 157a621f6..418fd1be0 100644 --- a/cmd/node/node.go +++ b/cmd/node/node.go @@ -31,7 +31,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/node/blocks_applier" "github.com/wavesplatform/gowaves/pkg/node/messages" "github.com/wavesplatform/gowaves/pkg/node/peer_manager" - "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + peersPersistentStorage "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" "github.com/wavesplatform/gowaves/pkg/p2p/peer" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/services" @@ -83,6 +83,7 @@ var ( integrationMinAssetInfoUpdateInterval = flag.Int("integration.min-asset-info-update-interval", 100000, "Minimum asset info update interval for integration tests.") metricsID = flag.Int("metrics-id", -1, "ID of the node on the metrics collection system") metricsURL = flag.String("metrics-url", "", "URL of InfluxDB or Telegraf in form of 'http://username:password@host:port/db'") + dropPeers = flag.Bool("drop-peers", false, "Drop peers storage before node start.") ) var defaultPeers = map[string]string{ @@ -120,6 +121,7 @@ func debugCommandLineParameters() { zap.S().Debugf("limit-connections: %s", *limitConnectionsS) zap.S().Debugf("profiler: %v", *profiler) zap.S().Debugf("bloom: %v", *bloomFilter) + zap.S().Debugf("drop-peers: %v", *dropPeers) } func main() { @@ -294,7 +296,23 @@ func main() { peerSpawnerImpl := peer_manager.NewPeerSpawner(pool, parent, conf.WavesNetwork, declAddr, *nodeName, uint64(rand.Int()), version) - peerStorage := storage.NewBinaryStorage(path) + peerStorage, err := peersPersistentStorage.NewCBORStorage(*statePath, time.Now()) + if err != nil { + zap.S().Errorf("Failed to open or create peers storage: %v", err) + cancel() + return + } + if *dropPeers { + if err := peerStorage.DropStorage(); err != nil { + zap.S().Errorf( + "Failed to drop peers storage. Drop peers storage manually. Err: %v", + err, + ) + cancel() + return + } + zap.S().Info("Successfully dropped peers storage") + } peerManager := peer_manager.NewPeerManager( peerSpawnerImpl, @@ -344,7 +362,19 @@ func main() { if len(conf.Addresses) > 0 { addresses := strings.Split(conf.Addresses, ",") for _, addr := range addresses { - peerManager.AddAddress(ctx, addr) + tcpAddr := proto.NewTCPAddrFromString(addr) + if tcpAddr.Empty() { + // nickeskov: that means that configuration parameter is invalid + zap.S().Errorf("Failed to parse TCPAddr from string %q", tcpAddr.String()) + cancel() + return + } + if err := peerManager.AddAddress(ctx, tcpAddr); err != nil { + // nickeskov: than means that we have problems with peers storage + zap.S().Errorf("Failed to add addres into know peers storage: %v", err) + cancel() + return + } } } @@ -357,6 +387,7 @@ func main() { webApi := api.NewNodeApi(app, st, n) go func() { + zap.S().Infof("Starting node HTTP API on '%v'", conf.HttpAddr) err := api.Run(ctx, conf.HttpAddr, webApi) if err != nil { zap.S().Errorf("Failed to start API: %v", err) @@ -368,6 +399,7 @@ func main() { h := http.NewServeMux() h.Handle("/metrics", promhttp.Handler()) s := &http.Server{Addr: *prometheus, Handler: h} + zap.S().Infof("Starting node metrics endpoint on '%v'", *prometheus) _ = s.ListenAndServe() } }() diff --git a/go.mod b/go.mod index 928e95077..f84213682 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/fxamacker/cbor/v2 v2.2.0 + github.com/fxamacker/cbor/v2 v2.3.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 github.com/golang/protobuf v1.4.2 @@ -23,8 +23,6 @@ require ( github.com/kilic/bn254 v0.0.0-20200902152204-ab63fe16fead github.com/magiconair/properties v1.8.1 github.com/mr-tron/base58 v1.1.2 - github.com/onsi/ginkgo v1.10.1 // indirect - github.com/onsi/gomega v1.7.0 // indirect github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.7.1 @@ -37,6 +35,7 @@ require ( github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 github.com/stretchr/testify v1.6.1 github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d + github.com/throttled/throttled/v2 v2.7.1 github.com/valyala/bytebufferpool v1.0.0 github.com/xenolf/lego v2.7.2+incompatible go.uber.org/atomic v1.4.0 diff --git a/go.sum b/go.sum index 974cfae70..926a746d1 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= -github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.3.0 h1:aM45YGMctNakddNNAezPxDUpv38j44Abh+hifNuqXik= +github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/go-chi/chi v4.0.3+incompatible h1:gakN3pDJnzZN5jqFV2TEdF66rTfKeITyR8qu6ekICEY= github.com/go-chi/chi v4.0.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= @@ -93,6 +93,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -115,6 +116,8 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -126,6 +129,7 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk= github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= @@ -256,6 +260,8 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/throttled/throttled/v2 v2.7.1 h1:FnBysDX4Sok55bvfDMI0l2Y71V1vM2wi7O79OW7fNtw= +github.com/throttled/throttled/v2 v2.7.1/go.mod h1:fuOeyK9fmnA+LQnsBbfT/mmPHjmkdogRBQxaD8YsgZ8= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -290,6 +296,7 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -307,6 +314,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -371,6 +379,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/pkg/api/app.go b/pkg/api/app.go index 38965ebb5..c051b396f 100644 --- a/pkg/api/app.go +++ b/pkg/api/app.go @@ -97,30 +97,34 @@ func (a *App) LoadKeys(apiKey string, password []byte) error { } func (a *App) Accounts() ([]account, error) { - r := make([]account, 0) - for _, s := range a.services.Wallet.Seeds() { - _, pk, err := crypto.GenerateKeyPair(s) + seeds := a.services.Wallet.Seeds() + + accounts := make([]account, 0, len(seeds)) + for _, seed := range seeds { + _, pk, err := crypto.GenerateKeyPair(seed) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to generate key pair for seed") } - a, err := proto.NewAddressFromPublicKey(a.services.Scheme, pk) + addr, err := proto.NewAddressFromPublicKey(a.services.Scheme, pk) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to generate new address from public key") } - r = append(r, account{Address: a, PublicKey: pk}) + accounts = append(accounts, account{Address: addr, PublicKey: pk}) } - return r, nil + return accounts, nil } func (a *App) checkAuth(key string) error { if !a.apiKeyEnabled { + // TODO(nickeskov): use new types of errors return &AuthError{errors.New("api key disabled")} } d, err := crypto.SecureHash([]byte(key)) if err != nil { - return &AuthError{err} + return errors.Wrap(err, "failed to calculate secure hash for API key") } if d != a.hashedApiKey { + // TODO(nickeskov): use new types of errors return &AuthError{errors.New("invalid api key")} } return nil diff --git a/pkg/api/app_addresses.go b/pkg/api/app_addresses.go new file mode 100644 index 000000000..9d37c8909 --- /dev/null +++ b/pkg/api/app_addresses.go @@ -0,0 +1,17 @@ +package api + +import "github.com/pkg/errors" + +func (a *App) Addresses() ([]string, error) { + accounts, err := a.Accounts() + if err != nil { + return nil, errors.Wrap(err, "failed to get wallet accounts") + } + + addresses := make([]string, 0, len(accounts)) + for i := range accounts { + addresses = append(addresses, accounts[i].Address.String()) + } + + return addresses, nil +} diff --git a/pkg/api/app_blocks.go b/pkg/api/app_blocks.go index 4f22a9555..deed560ff 100644 --- a/pkg/api/app_blocks.go +++ b/pkg/api/app_blocks.go @@ -1,6 +1,7 @@ package api import ( + "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" ) @@ -9,23 +10,23 @@ type Score struct { Score string `json:"score"` } -func (a *App) BlocksScoreAt(at proto.Height) (*Score, error) { +func (a *App) BlocksScoreAt(at proto.Height) (Score, error) { score, err := a.state.ScoreAtHeight(at) if err != nil { - return nil, err + return Score{}, err } - return &Score{Score: score.String()}, nil + return Score{Score: score.String()}, nil } func (a *App) BlocksLast() (*proto.Block, error) { h, err := a.state.Height() if err != nil { - return nil, &InternalError{err} + return nil, errors.Wrap(err, "failed to get state height") } block, err := a.state.BlockByHeight(h) if err != nil { - return nil, &InternalError{err} + return nil, errors.Wrapf(err, "failed to get %d block from state", h) } block.Height = h return block, nil @@ -34,7 +35,7 @@ func (a *App) BlocksLast() (*proto.Block, error) { func (a *App) BlocksFirst() (*proto.Block, error) { block, err := a.state.BlockByHeight(1) if err != nil { - return nil, &InternalError{err} + return nil, errors.Wrap(err, "failed to get first block from state") } block.Height = 1 return block, nil @@ -49,7 +50,7 @@ type Generator struct { func (a *App) BlocksGenerators() (Generators, error) { curHeight, err := a.state.Height() if err != nil { - return nil, &InternalError{err} + return nil, errors.Wrap(err, "failed to get state height") } // show only last 150 rows @@ -62,7 +63,7 @@ func (a *App) BlocksGenerators() (Generators, error) { for i := initialHeight; i < curHeight; i++ { block, err := a.state.BlockByHeight(i) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "failed to get from state block by height %d", i) } out = append(out, Generator{ diff --git a/pkg/api/app_miner.go b/pkg/api/app_miner.go index 486834c1b..0d4278ae8 100644 --- a/pkg/api/app_miner.go +++ b/pkg/api/app_miner.go @@ -19,10 +19,10 @@ type MinerInfo struct { Scheduler Scheduler } -func (a *App) Miner() (*MinerInfo, error) { +func (a *App) Miner() MinerInfo { e := a.scheduler.Emits() - next := make([]Next, 0) + next := make([]Next, 0, len(e)) for _, row := range e { next = append(next, Next{ PublicKey: row.KeyPair.Public, @@ -30,10 +30,10 @@ func (a *App) Miner() (*MinerInfo, error) { }) } - return &MinerInfo{ + return MinerInfo{ Scheduler: Scheduler{ TimeNow: time.Now(), Next: next, }, - }, nil + } } diff --git a/pkg/api/app_peers.go b/pkg/api/app_peers.go index 064f32ecc..35c485134 100644 --- a/pkg/api/app_peers.go +++ b/pkg/api/app_peers.go @@ -2,34 +2,60 @@ package api import ( "context" - "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/p2p/peer" "github.com/wavesplatform/gowaves/pkg/proto" "go.uber.org/zap" + "time" ) type Peer struct { Address string `json:"address"` - LastSeen uint64 `json:"lastSeen"` + LastSeen uint64 `json:"lastSeen,omitempty"` } -type PeersAll struct { +type PeersKnown struct { Peers []Peer `json:"peers"` } -func (a *App) PeersAll() (*PeersAll, error) { - peers, err := a.state.Peers() - if err != nil { - return nil, &InternalError{err} +// PeersAll is a list of all known not banned and not suspended peers with a publicly available declared address +func (a *App) PeersAll() (PeersKnown, error) { + suspended := a.peers.Suspended() + suspendedIPsMap := make(map[string]struct{}, len(suspended)) + for _, suspendedPeer := range suspended { + suspendedIPsMap[suspendedPeer.IP.String()] = struct{}{} + } + + knownPeers := a.peers.KnownPeers() + + nowMillis := unixMillis(time.Now()) + + out := make([]Peer, 0, len(knownPeers)) + for _, knownPeer := range knownPeers { + ip := knownPeer.String() + if _, in := suspendedIPsMap[ip]; in { + continue + } + // FIXME(nickeksov): add normal lastSeen field + out = append(out, Peer{ + Address: "/" + ip, + LastSeen: uint64(nowMillis), + }) } - var out []Peer - for _, row := range peers { - out = append(out, Peer{Address: row.String()}) + return PeersKnown{Peers: out}, nil +} + +func (a *App) PeersKnown() (PeersKnown, error) { + knownPeers := a.peers.KnownPeers() + + out := make([]Peer, 0, len(knownPeers)) + for _, knownPeer := range knownPeers { + // nickeksov: knownPeers without lastSeen field + out = append(out, Peer{Address: knownPeer.String()}) } - return &PeersAll{Peers: out}, nil + return PeersKnown{Peers: out}, nil } type PeersConnectResponse struct { @@ -61,10 +87,10 @@ func (a *App) PeersConnect(ctx context.Context, apiKey string, addr string) (*Pe } type PeersConnectedResponse struct { - Peers []PeersConnectedRow `json:"peers"` + Peers []PeerInfo `json:"peers"` } -type PeersConnectedRow struct { +type PeerInfo struct { Address string `json:"address"` DeclaredAddress string `json:"declaredAddress"` PeerName string `json:"peerName"` @@ -73,42 +99,61 @@ type PeersConnectedRow struct { ApplicationVersion string `json:"applicationVersion"` } -func (a *App) PeersConnected() (*PeersConnectedResponse, error) { - var out []PeersConnectedRow - a.peers.EachConnected(func(peer peer.Peer, i *proto.Score) { - - v := PeersConnectedRow{ - Address: "/" + peer.RemoteAddr().String(), - DeclaredAddress: "/" + peer.Handshake().DeclaredAddr.String(), - PeerName: peer.Handshake().NodeName, - PeerNonce: peer.Handshake().NodeNonce, - ApplicationName: peer.Handshake().AppName, - ApplicationVersion: peer.Handshake().Version.String(), - } +func peerInfoFromPeer(peer peer.Peer) PeerInfo { + handshake := peer.Handshake() + + declaredAddrStr := "N/A" + if !handshake.DeclaredAddr.Empty() { + declaredAddrStr = handshake.DeclaredAddr.String() + } - out = append(out, v) + return PeerInfo{ + Address: "/" + peer.RemoteAddr().String(), + DeclaredAddress: "/" + declaredAddrStr, + PeerName: handshake.NodeName, + PeerNonce: handshake.NodeNonce, + ApplicationName: handshake.AppName, + ApplicationVersion: handshake.Version.String(), + } +} +func (a *App) PeersConnected() PeersConnectedResponse { + var out []PeerInfo + a.peers.EachConnected(func(peer peer.Peer, _ *proto.Score) { + out = append(out, peerInfoFromPeer(peer)) }) - return &PeersConnectedResponse{ + return PeersConnectedResponse{ Peers: out, - }, nil + } } -type PeersSuspendedResponse struct { - Peers []string `json:"peers"` +type SuspendedPeerInfo struct { + Hostname string `json:"hostname"` + Timestamp int64 `json:"timestamp"` // nickeskov: timestamp in millis + Reason string `json:"reason,omitempty"` } -func (a *App) PeersSuspended() (*PeersSuspendedResponse, error) { - peers := a.peers.Suspended() - return &PeersSuspendedResponse{peers}, nil +func (a *App) PeersSuspended() []SuspendedPeerInfo { + suspended := a.peers.Suspended() + + out := make([]SuspendedPeerInfo, 0, len(suspended)) + for _, p := range suspended { + out = append(out, SuspendedPeerInfo{ + Hostname: "/" + p.IP.String(), + Timestamp: p.SuspendTimestampMillis, + Reason: p.Reason, + }) + } + + return out } type PeersSpawnedResponse struct { - Peers []proto.IpPort + Peers []proto.IpPort `json:"peers"` } -func (a *App) PeersSpawned() *PeersSpawnedResponse { +func (a *App) PeersSpawned() PeersSpawnedResponse { rs := a.peers.Spawned() - return &PeersSpawnedResponse{Peers: rs} + return PeersSpawnedResponse{Peers: rs} } diff --git a/pkg/api/app_peers_test.go b/pkg/api/app_peers_test.go index e90ca964c..3a883be02 100644 --- a/pkg/api/app_peers_test.go +++ b/pkg/api/app_peers_test.go @@ -1,26 +1,73 @@ package api import ( + "github.com/stretchr/testify/assert" + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + "github.com/wavesplatform/gowaves/pkg/proto" + "net" "testing" + "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/mock" - "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/services" ) -func TestApp_PeersAll(t *testing.T) { +func TestApp_PeersKnown(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - s := mock.NewMockState(ctrl) - s.EXPECT().Peers().Return([]proto.TCPAddr{proto.NewTCPAddrFromString("127.0.0.1:6868")}, nil) + peerManager := mock.NewMockPeerManager(ctrl) + addr := proto.NewTCPAddr(net.ParseIP("127.0.0.1"), 6868).ToIpPort() + peerManager.EXPECT().KnownPeers().Return([]storage.KnownPeer{storage.KnownPeer(addr)}) - app, err := NewApp("key", nil, services.Services{State: s}) + app, err := NewApp("key", nil, services.Services{Peers: peerManager}) require.NoError(t, err) - rs2, err := app.PeersAll() + rs2, err := app.PeersKnown() require.NoError(t, err) require.Len(t, rs2.Peers, 1) } + +func TestApp_PeersSuspended(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + peerManager := mock.NewMockPeerManager(ctrl) + + now := time.Now() + + ips := []string{"13.3.4.1", "5.3.6.7"} + testData := []storage.SuspendedPeer{ + { + IP: storage.IPFromString(ips[0]), + SuspendTimestampMillis: now.Add(time.Minute).UnixNano() / 1_000_000, + SuspendDuration: time.Minute, + Reason: "some reason #1", + }, + { + IP: storage.IPFromString(ips[1]), + SuspendTimestampMillis: now.Add(2*time.Minute).UnixNano() / 1_000_000, + SuspendDuration: time.Minute, + Reason: "some reason #2", + }, + } + + peerManager.EXPECT().Suspended().Return(testData) + + app, err := NewApp("key", nil, services.Services{Peers: peerManager}) + require.NoError(t, err) + + suspended := app.PeersSuspended() + + for i, actual := range suspended { + p := testData[i] + expected := SuspendedPeerInfo{ + Hostname: "/" + ips[i], + Timestamp: p.SuspendTimestampMillis, + Reason: p.Reason, + } + assert.Equal(t, expected, actual) + } +} diff --git a/pkg/api/errors.go b/pkg/api/errors.go index 30a908610..e3856d651 100644 --- a/pkg/api/errors.go +++ b/pkg/api/errors.go @@ -1,5 +1,15 @@ package api +import ( + "encoding/json" + "fmt" + "github.com/go-chi/chi/middleware" + "github.com/pkg/errors" + apiErrs "github.com/wavesplatform/gowaves/pkg/api/errors" + "go.uber.org/zap" + "net/http" +) + type BadRequestError struct { error } @@ -8,6 +18,60 @@ type AuthError struct { error } -type InternalError struct { - error +type ErrorHandler struct { + logger *zap.Logger +} + +func NewErrorHandler(logger *zap.Logger) ErrorHandler { + return ErrorHandler{ + logger: logger, + } +} + +func (eh *ErrorHandler) Handle(w http.ResponseWriter, r *http.Request, err error) { + if err == nil { + return + } + switch innerErr := errors.Cause(err).(type) { + case BadRequestError, *BadRequestError: + // nickeskov: this error type will be removed in future + http.Error(w, fmt.Sprintf("Failed to complete request: %s", innerErr.Error()), http.StatusBadRequest) + case AuthError, *AuthError: + // nickeskov: this error type will be removed in future + http.Error(w, fmt.Sprintf("Failed to complete request: %s", innerErr.Error()), http.StatusForbidden) + case *apiErrs.UnknownError: + eh.logger.Error("UnknownError", + zap.String("proto", r.Proto), + zap.String("path", r.URL.Path), + zap.String("reqId", middleware.GetReqID(r.Context())), + zap.Error(err), + ) + eh.sendApiErrJSON(w, r, innerErr) + case apiErrs.ApiError: + eh.sendApiErrJSON(w, r, innerErr) + default: + eh.logger.Error("InternalServerError", + zap.String("proto", r.Proto), + zap.String("path", r.URL.Path), + zap.String("reqId", middleware.GetReqID(r.Context())), + zap.Error(err), + ) + unknownErrWrapper := apiErrs.NewUnknownError(innerErr) + eh.sendApiErrJSON(w, r, unknownErrWrapper) + } +} + +func (eh *ErrorHandler) sendApiErrJSON(w http.ResponseWriter, r *http.Request, apiErr apiErrs.ApiError) { + w.WriteHeader(apiErr.GetHttpCode()) + if encodeErr := json.NewEncoder(w).Encode(apiErr); encodeErr != nil { + eh.logger.Error("Failed to marshal API Error to JSON", + zap.String("proto", r.Proto), + zap.String("path", r.URL.Path), + zap.String("request_id", middleware.GetReqID(r.Context())), + zap.Error(encodeErr), + zap.String("api_error", apiErr.Error()), + ) + // nickeskov: Type which implements ApiError interface MUST be serializable to JSON. + panic(errors.Errorf("BUG, CREATE REPORT: %s", encodeErr.Error())) + } } diff --git a/pkg/api/errors/auth.go b/pkg/api/errors/auth.go new file mode 100644 index 000000000..8201ed040 --- /dev/null +++ b/pkg/api/errors/auth.go @@ -0,0 +1,43 @@ +package errors + +import ( + "fmt" + "net/http" +) + +//API Auth +type authError struct { + genericError +} + +type ( + ApiKeyNotValidError authError + TooBigArrayAllocationError authError +) + +var ( + ApiKeyNotValid = &ApiKeyNotValidError{ + genericError: genericError{ + ID: ApiKeyNotValidErrorID, + HttpCode: http.StatusBadRequest, + Message: "Provided API key is not correct", + }, + } + TooBigArrayAllocation = &TooBigArrayAllocationError{ + genericError: genericError{ + ID: TooBigArrayAllocationErrorID, + HttpCode: http.StatusBadRequest, + Message: "Too big sequence requested", + }, + } +) + +func NewTooBigArrayAllocationError(limit int) *TooBigArrayAllocationError { + return &TooBigArrayAllocationError{ + genericError: genericError{ + ID: TooBigArrayAllocationErrorID, + HttpCode: http.StatusBadRequest, + Message: fmt.Sprintf("Too big sequence requested: max limit is %d entries", limit), + }, + } +} diff --git a/pkg/api/errors/basics.go b/pkg/api/errors/basics.go new file mode 100644 index 000000000..20a02d549 --- /dev/null +++ b/pkg/api/errors/basics.go @@ -0,0 +1,124 @@ +package errors + +import ( + "fmt" + "net/http" +) + +type Identifier interface { + IntCode() int +} + +// ApiError is a basic interface for node HTTP API. +// Type which implements this interface MUST be serializable to JSON. +type ApiError interface { + error + GetID() Identifier + GetName() string + GetHttpCode() int + GetMessage() string +} + +type ErrorID int +type ApiAuthErrorID ErrorID +type ValidationErrorID ErrorID +type TransactionErrorID ErrorID + +func (e ErrorID) IntCode() int { + return int(e) +} +func (e ApiAuthErrorID) IntCode() int { + return int(e) +} +func (e ValidationErrorID) IntCode() int { + return int(e) +} +func (e TransactionErrorID) IntCode() int { + return int(e) +} + +// generic error + +type genericError struct { + ID Identifier `json:"error"` + HttpCode int `json:"-"` + Message string `json:"message"` +} + +func (g *genericError) GetID() Identifier { + return g.ID +} + +func (g *genericError) GetName() string { + return errorNames[g.ID] +} + +func (g *genericError) GetHttpCode() int { + return g.HttpCode +} + +func (g *genericError) GetMessage() string { + return g.Message +} + +func (g *genericError) Error() string { + return fmt.Sprintf("%s #%d: %s", g.GetName(), g.ID.IntCode(), g.Message) +} + +// --generic error + +// UnknownError is a wrapper for any unknown internal error +type UnknownError struct { + genericError + inner error +} + +func (u *UnknownError) Unwrap() error { + return u.inner +} + +func (u *UnknownError) Error() string { + if u.Unwrap() != nil { + return fmt.Sprintf( + "%s; inner error (%T): %s", + u.genericError.Error(), + u.Unwrap(), u.Unwrap().Error(), + ) + } + return u.genericError.Error() +} + +func NewUnknownError(inner error) *UnknownError { + return NewUnknownErrorWithMsg("Error is unknown", inner) +} + +func NewUnknownErrorWithMsg(message string, inner error) *UnknownError { + return &UnknownError{ + genericError: genericError{ + ID: UnknownErrorID, + HttpCode: http.StatusInternalServerError, + Message: message, + }, + inner: inner, + } +} + +// --UnknownError + +type WrongJsonError struct { + genericError + Cause string `json:"cause,omitempty"` + ValidationErrors []error `json:"validationErrors,omitempty"` +} + +func NewWrongJsonError(cause string, validationErrors []error) *WrongJsonError { + return &WrongJsonError{ + genericError: genericError{ + ID: WrongJsonErrorID, + HttpCode: http.StatusBadRequest, + Message: "failed to parse json message", + }, + Cause: cause, + ValidationErrors: validationErrors, + } +} diff --git a/pkg/api/errors/basics_test.go b/pkg/api/errors/basics_test.go new file mode 100644 index 000000000..cc3d8e1d7 --- /dev/null +++ b/pkg/api/errors/basics_test.go @@ -0,0 +1,41 @@ +package errors + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestApiErrorWithSameIntID(t *testing.T) { + type testSample struct { + id Identifier + expectedName string + } + + testData := []struct { + first testSample + second testSample + }{ + { + testSample{InvalidNameErrorID, "InvalidNameError"}, + testSample{NegativeAmountErrorID, "NegativeAmountError"}, + }, + { + testSample{StateCheckFailedErrorID, "StateCheckFailedError"}, + testSample{InsufficientFeeErrorID, "InsufficientFeeError"}, + }, + { + testSample{ToSelfErrorID, "ToSelfError"}, + testSample{NegativeMinFeeErrorID, "NegativeMinFeeError"}, + }, + { + testSample{MissingSenderPrivateKeyErrorID, "MissingSenderPrivateKeyError"}, + testSample{NonPositiveAmountErrorID, "NonPositiveAmountError"}, + }, + } + + for _, sample := range testData { + assert.Equal(t, sample.first.id.IntCode(), sample.second.id.IntCode()) + assert.Equal(t, sample.first.expectedName, errorNames[sample.first.id]) + assert.Equal(t, sample.second.expectedName, errorNames[sample.second.id]) + } +} diff --git a/pkg/api/errors/consts.go b/pkg/api/errors/consts.go new file mode 100644 index 000000000..bca3f3219 --- /dev/null +++ b/pkg/api/errors/consts.go @@ -0,0 +1,97 @@ +package errors + +const ( + UnknownErrorID ErrorID = 0 + WrongJsonErrorID ErrorID = 1 +) + +//API Auth +const ( + ApiKeyNotValidErrorID ApiAuthErrorID = 2 + TooBigArrayAllocationErrorID ApiAuthErrorID = 10 +) + +//VALIDATION +const ( + InvalidSignatureErrorID ValidationErrorID = 101 + InvalidAddressErrorID ValidationErrorID = 102 + InvalidPublicKeyErrorID ValidationErrorID = 108 + InvalidMessageErrorID ValidationErrorID = 110 + InvalidNameErrorID ValidationErrorID = 111 + StateCheckFailedErrorID ValidationErrorID = 112 + OverflowErrorID ValidationErrorID = 113 + ToSelfErrorID ValidationErrorID = 114 + MissingSenderPrivateKeyErrorID ValidationErrorID = 115 + InvalidIdsErrorID ValidationErrorID = 116 + CustomValidationErrorErrorID ValidationErrorID = 199 + BlockDoesNotExistErrorID ValidationErrorID = 301 + AliasDoesNotExistErrorID ValidationErrorID = 302 + MistimingErrorID ValidationErrorID = 303 + DataKeyDoesNotExistErrorID ValidationErrorID = 304 + ScriptCompilerErrorID ValidationErrorID = 305 + ScriptExecutionErrorErrorID ValidationErrorID = 306 + TransactionNotAllowedByAccountScriptErrorID ValidationErrorID = 307 + TransactionNotAllowedByAssetScriptErrorID ValidationErrorID = 308 +) + +//TRANSACTIONS +const ( + TransactionDoesNotExistErrorID TransactionErrorID = 311 + UnsupportedTransactionTypeErrorID TransactionErrorID = 312 + AssetDoesNotExistErrorID TransactionErrorID = 313 + NegativeAmountErrorID TransactionErrorID = 111 + InsufficientFeeErrorID TransactionErrorID = 112 + NegativeMinFeeErrorID TransactionErrorID = 114 + NonPositiveAmountErrorID TransactionErrorID = 115 + AlreadyInStateErrorID TransactionErrorID = 400 + AccountBalanceErrorsErrorID TransactionErrorID = 402 + OrderInvalidErrorID TransactionErrorID = 403 + InvalidChainIdErrorID TransactionErrorID = 404 + InvalidProofsErrorID TransactionErrorID = 405 + InvalidTransactionIdErrorID TransactionErrorID = 4001 + InvalidBlockIdErrorID TransactionErrorID = 4002 + InvalidAssetIdErrorID TransactionErrorID = 4007 +) + +var errorNames = map[Identifier]string{ + UnknownErrorID: "UnknownError", + WrongJsonErrorID: "WrongJsonError", + + ApiKeyNotValidErrorID: "ApiKeyNotValidError", + TooBigArrayAllocationErrorID: "TooBigArrayAllocationError", + InvalidSignatureErrorID: "InvalidSignatureError", + InvalidAddressErrorID: "InvalidAddressError", + InvalidPublicKeyErrorID: "InvalidPublicKeyError", + InvalidMessageErrorID: "InvalidMessageError", + InvalidNameErrorID: "InvalidNameError", + StateCheckFailedErrorID: "StateCheckFailedError", + OverflowErrorID: "OverflowError", + ToSelfErrorID: "ToSelfError", + MissingSenderPrivateKeyErrorID: "MissingSenderPrivateKeyError", + InvalidIdsErrorID: "InvalidIdsError", + CustomValidationErrorErrorID: "CustomValidationErrorError", + BlockDoesNotExistErrorID: "BlockDoesNotExistError", + AliasDoesNotExistErrorID: "AliasDoesNotExistError", + MistimingErrorID: "MistimingError", + DataKeyDoesNotExistErrorID: "DataKeyDoesNotExistError", + ScriptCompilerErrorID: "ScriptCompilerError", + ScriptExecutionErrorErrorID: "ScriptExecutionErrorError", + TransactionNotAllowedByAccountScriptErrorID: "TransactionNotAllowedByAccountScriptError", + TransactionNotAllowedByAssetScriptErrorID: "TransactionNotAllowedByAssetScriptError", + + TransactionDoesNotExistErrorID: "TransactionDoesNotExistError", + UnsupportedTransactionTypeErrorID: "UnsupportedTransactionTypeError", + AssetDoesNotExistErrorID: "AssetDoesNotExistError", + NegativeAmountErrorID: "NegativeAmountError", + InsufficientFeeErrorID: "InsufficientFeeError", + NegativeMinFeeErrorID: "NegativeMinFeeError", + NonPositiveAmountErrorID: "NonPositiveAmountError", + AlreadyInStateErrorID: "AlreadyInStateError", + AccountBalanceErrorsErrorID: "AccountBalanceErrorsError", + OrderInvalidErrorID: "OrderInvalidError", + InvalidChainIdErrorID: "InvalidChainIdError", + InvalidProofsErrorID: "InvalidProofsError", + InvalidTransactionIdErrorID: "InvalidTransactionIdError", + InvalidBlockIdErrorID: "InvalidBlockIdError", + InvalidAssetIdErrorID: "InvalidAssetIdError", +} diff --git a/pkg/api/errors/transaction.go b/pkg/api/errors/transaction.go new file mode 100644 index 000000000..e30faf2d5 --- /dev/null +++ b/pkg/api/errors/transaction.go @@ -0,0 +1,71 @@ +package errors + +import ( + "github.com/wavesplatform/gowaves/pkg/proto" + "net/http" +) + +type transactionError struct { + genericError +} + +// TODO(nickeskov): IMPLEMENT ME +type order struct{} + +type ( + TransactionDoesNotExistError transactionError + UnsupportedTransactionTypeError transactionError + AssetDoesNotExistError transactionError + NegativeAmount transactionError + InsufficientFeeError transactionError + NegativeMinFeeError transactionError + NonPositiveAmountError transactionError + AlreadyInStateError transactionError + AccountBalanceErrorsError struct { + transactionError + Details map[proto.Address]string `json:"details"` + } + OrderInvalidError struct { + transactionError + Order order `json:"order"` + } + InvalidChainIdError transactionError + InvalidProofsError transactionError + InvalidTransactionIdError transactionError + InvalidBlockIdError transactionError + InvalidAssetIdError transactionError +) + +var ( + TransactionDoesNotExist = &TransactionDoesNotExistError{ + genericError: genericError{ + ID: TransactionDoesNotExistErrorID, + HttpCode: http.StatusNotFound, + Message: "transactions does not exist", + }, + } + UnsupportedTransactionType = &UnsupportedTransactionTypeError{ + genericError: genericError{ + ID: UnsupportedTransactionTypeErrorID, + HttpCode: http.StatusNotImplemented, + Message: "transaction type not supported", + }, + } + InvalidAssetId = &InvalidAssetIdError{ + genericError: genericError{ + ID: InvalidAssetIdErrorID, + HttpCode: http.StatusBadRequest, + Message: "Invalid asset id", + }, + } +) + +func NewInvalidBlockIDError(message string) *InvalidBlockIdError { + return &InvalidBlockIdError{ + genericError: genericError{ + ID: InvalidBlockIdErrorID, + HttpCode: http.StatusBadRequest, + Message: message, + }, + } +} diff --git a/pkg/api/errors/validation.go b/pkg/api/errors/validation.go new file mode 100644 index 000000000..dd3a59b6f --- /dev/null +++ b/pkg/api/errors/validation.go @@ -0,0 +1,154 @@ +package errors + +import ( + "encoding/json" + "github.com/pkg/errors" + "net/http" +) + +type validationError struct { + genericError +} + +// TODO(nickeskov): IMPLEMENT ME +type transaction interface{} + +type validationErrorWithTransaction struct { + validationError + Transaction transaction `json:"transaction,omitempty"` +} + +type ( + InvalidSignatureError validationError + InvalidAddressError validationError + InvalidPublicKeyError validationError + InvalidMessageError validationError + InvalidNameError validationError + StateCheckFailedError struct { + validationErrorWithTransaction + // TODO(nickeskov): implement more optimized way for fields embedding + // for converting any structs to map[string]interface{} + // in a convenient way use "github.com/mitchellh/mapstructure" + embeddedFields map[string]interface{} + } + OverflowError validationError + ToSelfError validationError + MissingSenderPrivateKeyError validationError + InvalidIdsError struct { + validationError + Ids []string `json:"ids"` + } + CustomValidationError validationError + BlockDoesNotExistError validationError + AliasDoesNotExistError validationError + MistimingError validationError + DataKeyDoesNotExistError validationError + ScriptCompilerError validationError + ScriptExecutionError validationErrorWithTransaction + TransactionNotAllowedByAccountScriptError validationErrorWithTransaction +) + +func (e *StateCheckFailedError) MarshalJSON() ([]byte, error) { + errorJson, err := json.Marshal(e.validationErrorWithTransaction) + if err != nil { + return nil, errors.Wrap(err, "StateCheckFailedError.MarshalJSON") + } + + if len(e.embeddedFields) == 0 { + return errorJson, nil + } + + embedded, err := json.Marshal(e.embeddedFields) + if err != nil { + return nil, errors.Wrap(err, "StateCheckFailedError.MarshalJSON") + } + + // nickeskov `{"extra":"somevalue"}` -> `"extra":"somevalue"` + extraFields := embedded[1 : len(embedded)-1] + + buffer := make([]byte, 0, len(errorJson)+len(extraFields)+1) + + // nickeskov: errorJson=`{"somekey":"somevalue"}`, buffer = `"{"somekey":"somevalue"` + buffer = append(buffer, errorJson[:len(errorJson)-1]...) + // buffer = `"{"somekey":"somevalue",` + buffer = append(buffer, ',') + // buffer = `"{"somekey":"somevalue","extra":"somevalue"` + buffer = append(buffer, extraFields...) + // buffer = `"{"somekey":"somevalue","extra":"somevalue"}` + buffer = append(buffer, '}') + + return buffer, nil +} + +var ( + InvalidSignature = &InvalidSignatureError{ + genericError: genericError{ + ID: InvalidSignatureErrorID, + HttpCode: http.StatusBadRequest, + Message: "invalid signature", + }, + } + InvalidAddress = &InvalidAddressError{ + genericError: genericError{ + ID: InvalidAddressErrorID, + HttpCode: http.StatusBadRequest, + Message: "invalid address", + }, + } + InvalidPublicKey = &InvalidPublicKeyError{ + genericError: genericError{ + ID: InvalidPublicKeyErrorID, + HttpCode: http.StatusBadRequest, + Message: "invalid public key", + }, + } + InvalidMessage = &InvalidMessageError{ + genericError: genericError{ + ID: InvalidMessageErrorID, + HttpCode: http.StatusBadRequest, + Message: "invalid message", + }, + } + InvalidName = &InvalidNameError{ + genericError: genericError{ + ID: InvalidNameErrorID, + HttpCode: http.StatusBadRequest, + Message: "invalid name", + }, + } + Overflow = &OverflowError{ + genericError: genericError{ + ID: OverflowErrorID, + HttpCode: http.StatusBadRequest, + Message: "overflow error", + }, + } + ToSelf = &ToSelfError{ + genericError: genericError{ + ID: ToSelfErrorID, + HttpCode: http.StatusBadRequest, + Message: "Transaction to yourself", + }, + } + MissingSenderPrivateKey = &MissingSenderPrivateKeyError{ + genericError: genericError{ + ID: MissingSenderPrivateKeyErrorID, + HttpCode: http.StatusBadRequest, + Message: "no private key for sender address in wallet", + }, + } + BlockDoesNotExist = &BlockDoesNotExistError{ + genericError: genericError{ + ID: BlockDoesNotExistErrorID, + HttpCode: http.StatusNotFound, + Message: "block does not exist", + }, + } + DataKeyDoesNotExist = &DataKeyDoesNotExistError{ + genericError: genericError{ + ID: DataKeyDoesNotExistErrorID, + HttpCode: http.StatusNotFound, + Message: "no data for this key", + }, + } +) diff --git a/pkg/api/errors/validation_test.go b/pkg/api/errors/validation_test.go new file mode 100644 index 000000000..8059cb3e6 --- /dev/null +++ b/pkg/api/errors/validation_test.go @@ -0,0 +1,39 @@ +package errors + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func TestStateCheckFailedError_MarshalJSON(t *testing.T) { + value := StateCheckFailedError{ + validationErrorWithTransaction: validationErrorWithTransaction{ + validationError: validationError{ + genericError: genericError{ + ID: StateCheckFailedErrorID, + HttpCode: http.StatusBadRequest, + Message: "some message", + }, + }, + Transaction: nil, + }, + embeddedFields: map[string]interface{}{ + "extra_field": "value", + "extra_int": 1, + }, + } + + marshaled, err := value.MarshalJSON() + assert.NoError(t, err) + + var unmarshaled map[string]interface{} + err = json.Unmarshal(marshaled, &unmarshaled) + assert.NoError(t, err) + + assert.Equal(t, float64(StateCheckFailedErrorID), unmarshaled["error"].(float64)) + assert.Equal(t, "some message", unmarshaled["message"]) + assert.Equal(t, "value", unmarshaled["extra_field"]) + assert.Equal(t, float64(1), unmarshaled["extra_int"].(float64)) +} diff --git a/pkg/api/errors_test.go b/pkg/api/errors_test.go index 5d62b3e17..156c66fd1 100644 --- a/pkg/api/errors_test.go +++ b/pkg/api/errors_test.go @@ -15,8 +15,3 @@ func TestAuthError(t *testing.T) { err := AuthError{errors.New("bad auth")} require.Error(t, err) } - -func TestInternalError(t *testing.T) { - err := InternalError{errors.New("internal error")} - require.Error(t, err) -} diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go new file mode 100644 index 000000000..4d7a52d64 --- /dev/null +++ b/pkg/api/helpers.go @@ -0,0 +1,7 @@ +package api + +import "time" + +func unixMillis(t time.Time) int64 { + return t.UnixNano() / 1_000_000 +} diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go new file mode 100644 index 000000000..69f9572a9 --- /dev/null +++ b/pkg/api/metrics.go @@ -0,0 +1,43 @@ +package api + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +const httpAPIMetricsNamespace = "http_api" + +var ( + metricApiTotalRequests = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: httpAPIMetricsNamespace, + Name: "total_hits", + Help: "Node HTTP API Requests count", + }, + ) + + metricApiHits = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: httpAPIMetricsNamespace, + Name: "path_hits", + Help: "Node HTTP API paths hits", + }, + []string{"status", "path"}, + ) + + metricApiRequestDuration = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: httpAPIMetricsNamespace, + Name: "path_duration", + // TODO(nickeskov): add custom buckets + }, + []string{"method", "path"}, + ) +) + +func init() { + prometheus.MustRegister( + metricApiTotalRequests, + metricApiHits, + metricApiRequestDuration, + ) +} diff --git a/pkg/api/middleware.go b/pkg/api/middleware.go new file mode 100644 index 000000000..e0c69f3c2 --- /dev/null +++ b/pkg/api/middleware.go @@ -0,0 +1,99 @@ +package api + +import ( + "github.com/go-chi/chi" + "github.com/go-chi/chi/middleware" + "go.uber.org/zap" + "net/http" + "strconv" + "time" +) + +// CreateLoggerMiddleware creates a middleware that logs the start and end of each request, along +// with some useful data about what was requested, what the response status was, +// and how long it took to return. +func CreateLoggerMiddleware(l *zap.Logger) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + ww, ok := w.(middleware.WrapResponseWriter) + if !ok { + ww = middleware.NewWrapResponseWriter(w, r.ProtoMajor) + } + + t1 := time.Now() + defer func() { + l.Info("ServedHttpRequest", + zap.String("proto", r.Proto), + zap.String("path", r.URL.Path), + zap.Duration("lat", time.Since(t1)), + zap.Int("status", ww.Status()), + zap.Int("size", ww.BytesWritten()), + zap.String("request_id", middleware.GetReqID(r.Context()))) + }() + + next.ServeHTTP(ww, r) + } + return http.HandlerFunc(fn) + } +} + +func chiHttpApiGeneralMetricsMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + begin := time.Now() + + metricApiTotalRequests.Inc() + + ww, ok := w.(middleware.WrapResponseWriter) + if !ok { + ww = middleware.NewWrapResponseWriter(w, r.ProtoMajor) + } + + defer func() { + routePath := r.URL.Path + if chiRouteContext := chi.RouteContext(r.Context()); chiRouteContext != nil { + if updatedRoutePath := chiRouteContext.RoutePattern(); updatedRoutePath != "" { + routePath = updatedRoutePath + } + } + + statusCode := ww.Status() + metricApiHits.WithLabelValues(strconv.Itoa(statusCode), routePath).Inc() + + observer := metricApiRequestDuration.WithLabelValues(r.Method, routePath) + observer.Observe(time.Since(begin).Seconds()) + }() + + next.ServeHTTP(ww, r) + }) +} + +func CreateHeadersMiddleware(headers map[string]string) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for k, v := range headers { + w.Header().Set(k, v) + } + next.ServeHTTP(w, r) + }) + } +} + +func JsonContentTypeMiddleware(next http.Handler) http.Handler { + return CreateHeadersMiddleware(map[string]string{ + "Content-Type": "application/json", + })(next) +} + +func createCheckAuthMiddleware(app *App, errorHandler HandleErrorFunc) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + apiKey := r.Header.Get("X-API-Key") + err := app.checkAuth(apiKey) + if err != nil { + errorHandler(w, r, err) + } else { + next.ServeHTTP(w, r) + } + }) + } +} diff --git a/pkg/api/node_api.go b/pkg/api/node_api.go index 5ec69b1e9..d08b72b9f 100644 --- a/pkg/api/node_api.go +++ b/pkg/api/node_api.go @@ -4,46 +4,23 @@ import ( "context" "encoding/json" "fmt" + "io" "io/ioutil" "net/http" "strconv" - "time" "github.com/pkg/errors" "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" + "github.com/mr-tron/base58" + apiErrs "github.com/wavesplatform/gowaves/pkg/api/errors" + "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/node" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/state" "go.uber.org/zap" ) -// Logger is a middleware that logs the start and end of each request, along -// with some useful data about what was requested, what the response status was, -// and how long it took to return. -func Logger(l *zap.Logger) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) - - t1 := time.Now() - defer func() { - l.Info("Served", - zap.String("proto", r.Proto), - zap.String("path", r.URL.Path), - zap.Duration("lat", time.Since(t1)), - zap.Int("status", ww.Status()), - zap.Int("size", ww.BytesWritten()), - zap.String("reqId", middleware.GetReqID(r.Context()))) - }() - - next.ServeHTTP(ww, r) - } - return http.HandlerFunc(fn) - } -} - type NodeApi struct { state state.State node *node.Node @@ -58,141 +35,194 @@ func NewNodeApi(app *App, state state.State, node *node.Node) *NodeApi { } } -func (a *NodeApi) TransactionsBroadcast(w http.ResponseWriter, r *http.Request) { +func (a *NodeApi) TransactionsBroadcast(_ http.ResponseWriter, r *http.Request) error { b, err := ioutil.ReadAll(r.Body) - defer r.Body.Close() if err != nil { - handleError(w, &BadRequestError{err}) - return + return errors.Wrap(err, "TransactionsBroadcast: failed to read request body") } - err = a.app.TransactionsBroadcast(r.Context(), b) if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "TransactionsBroadcast") } + return nil } -func (a *NodeApi) BlocksLast(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) BlocksLast(w http.ResponseWriter, _ *http.Request) error { block, err := a.app.BlocksLast() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "BlocksLast: failed to get last block") } bts, err := proto.BlockEncodeJson(block) if err != nil { - http.Error(w, fmt.Sprintf("Failed to marshal status to JSON: %s", err.Error()), http.StatusInternalServerError) - return + return errors.Wrap(err, "BlocksLast: failed to marshal block to JSON") } - _, _ = w.Write(bts) + if _, err = w.Write(bts); err != nil { + return errors.Wrap(err, "BlocksLast: failed to write block json to ResponseWriter") + } + return nil } -func (a *NodeApi) BlocksFirst(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) BlocksFirst(w http.ResponseWriter, _ *http.Request) error { block, err := a.state.BlockByHeight(1) if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "BlocksFirst") } block.Height = 1 bts, err := proto.BlockEncodeJson(block) if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "BlocksFirst: failed to marshal block to JSON") + } + if _, err = w.Write(bts); err != nil { + return errors.Wrap(err, "BlocksFirst: failed to write block json to ResponseWriter") } - _, _ = w.Write(bts) + return nil +} + +func blockIDAtInvalidLenErr(key string) *apiErrs.InvalidBlockIdError { + return apiErrs.NewInvalidBlockIDError( + fmt.Sprintf("%s has invalid length %d. Length can either be %d or %d", + key, // nickeskov: this part must be the last part of HTTP path + len(key), + crypto.DigestSize, + crypto.SignatureSize, + ), + ) } -func (a *NodeApi) BlockAt(w http.ResponseWriter, r *http.Request) { +func blockIDAtInvalidCharErr(invalidChar rune, id string) *apiErrs.InvalidBlockIdError { + return apiErrs.NewInvalidBlockIDError( + fmt.Sprintf( + "requirement failed: Wrong char %q in Base58 string '%s'", + invalidChar, + id, + ), + ) +} + +func (a *NodeApi) BlockAt(w http.ResponseWriter, r *http.Request) error { s := chi.URLParam(r, "height") id, err := strconv.ParseUint(s, 10, 64) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return + // nickeskov: message taken from scala node + // try execute `curl -X GET "https://nodes-testnet.wavesnodes.com/blocks/at/fdsfasdff" -H "accept: application/json"` + return blockIDAtInvalidLenErr("at") } block, err := a.state.BlockByHeight(id) if err != nil { - handleError(w, err) - return + origErr := errors.Cause(err) + if state.IsNotFound(origErr) { + // nickeskov: it's strange, but scala node sends empty response... + // try execute `curl -X GET "https://nodes-testnet.wavesnodes.com/blocks/at/0" -H "accept: application/json"` + return nil + } + return errors.Wrap(err, + "BlockAt: expected NotFound in state error, but received other error") } + block.Height = id err = json.NewEncoder(w).Encode(block) if err != nil { - handleError(w, err) - return + return errors.Wrap(err, + "BlockEncodeJson: failed to marshal block to JSON and write to ResponseWriter") } + return nil } -func (a *NodeApi) DebugSyncEnabled(w http.ResponseWriter, r *http.Request) { - s := chi.URLParam(r, "enabled") - id, err := strconv.ParseUint(s, 10, 64) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return +func findFirstInvalidRuneInBase58String(str string) *rune { + for _, r := range str { + if _, err := base58.Decode(string(r)); err != nil { + return &r + } } - a.app.DebugSyncEnabled(id == 1) + return nil } -func (a *NodeApi) BlockIDAt(w http.ResponseWriter, r *http.Request) { +func (a *NodeApi) BlockIDAt(w http.ResponseWriter, r *http.Request) error { + // nickeskov: in this case id param must be non zero length s := chi.URLParam(r, "id") id, err := proto.NewBlockIDFromBase58(s) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return + if invalidRune := findFirstInvalidRuneInBase58String(s); invalidRune != nil { + return blockIDAtInvalidCharErr(*invalidRune, s) + } + return blockIDAtInvalidLenErr(s) } block, err := a.state.Block(id) if err != nil { - handleError(w, err) - return + origErr := errors.Cause(err) + if state.IsNotFound(origErr) { + return apiErrs.BlockDoesNotExist + } + return errors.Wrapf(err, + "BlockIDAt: expected NotFound in state error, but received other error for blockID=%s", + s, + ) } + height, err := a.state.BlockIDToHeight(id) if err != nil { - handleError(w, err) - return + // TODO(nickeskov): should handle state.IsNotFound(...)? + return errors.Wrapf(err, + "BlockIDAt: failed to execute state.BlockIDToHeight for blockID=%s", s) } block.Height = height err = json.NewEncoder(w).Encode(block) if err != nil { - handleError(w, err) - return + return errors.Wrap(err, + "BlockIDAt: failed to marshal block to JSON and write to ResponseWriter") } + return nil } -type BlockHeightResponse struct { - Height uint64 `json:"height"` -} +func (a *NodeApi) BlockHeight(w http.ResponseWriter, _ *http.Request) error { + type blockHeightResponse struct { + Height uint64 `json:"height"` + } -func (a *NodeApi) BlockHeight(w http.ResponseWriter, _ *http.Request) { height, err := a.state.Height() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "BlockHeight: failed to bet blocks height") } - err = json.NewEncoder(w).Encode(&BlockHeightResponse{Height: height}) - if err != nil { - handleError(w, err) - return + + if err := trySendJson(w, blockHeightResponse{Height: height}); err != nil { + return errors.Wrap(err, "BlockHeight") } + return nil } -func (a *NodeApi) BlockScoreAt(w http.ResponseWriter, r *http.Request) { +// nickeskov: in scala node this route does not exist + +func (a *NodeApi) BlockScoreAt(w http.ResponseWriter, r *http.Request) error { s := chi.URLParam(r, "id") id, err := strconv.ParseUint(s, 10, 64) if err != nil { - handleError(w, &BadRequestError{err}) - return + // TODO(nickeskov): which error it should send? + return &BadRequestError{err} } rs, err := a.app.BlocksScoreAt(id) if err != nil { - handleError(w, err) - return + // TODO(nickeskov): which error it should send? + return errors.Wrapf(err, "failed get blocks score at for id %d", id) } - sendJson(w, rs) + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "BlockScoreAt") + } + return nil } -func Run(ctx context.Context, address string, n *NodeApi) error { - apiServer := &http.Server{Addr: address, Handler: n.routes()} +func RunWithOpts(ctx context.Context, address string, n *NodeApi, opts *RunOptions) error { + if opts == nil { + opts = DefaultRunOptions() + } + + routes, err := n.routes(opts) + if err != nil { + return errors.Wrap(err, "RunWithOpts") + } + + apiServer := &http.Server{Addr: address, Handler: routes} go func() { <-ctx.Done() zap.S().Info("Shutting down API...") @@ -201,25 +231,47 @@ func Run(ctx context.Context, address string, n *NodeApi) error { zap.S().Errorf("Failed to shutdown API server: %v", err) } }() - err := apiServer.ListenAndServe() + + err = apiServer.ListenAndServe() if err != nil && err != http.ErrServerClosed { return err } return nil } -func (a *NodeApi) PeersAll(w http.ResponseWriter, _ *http.Request) { +func Run(ctx context.Context, address string, n *NodeApi) error { + // TODO(nickeskov): add run flags in CLI flags + return RunWithOpts(ctx, address, n, nil) +} + +func (a *NodeApi) PeersAll(w http.ResponseWriter, _ *http.Request) error { rs, err := a.app.PeersAll() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "failed to fetch all peers") + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersAll") + } + return nil +} + +func (a *NodeApi) PeersKnown(w http.ResponseWriter, _ *http.Request) error { + rs, err := a.app.PeersKnown() + if err != nil { + return errors.Wrap(err, "failed to fetch known peers") + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersKnown") } - sendJson(w, rs) + return nil } -func (a *NodeApi) PeersSpawned(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) PeersSpawned(w http.ResponseWriter, _ *http.Request) error { rs := a.app.PeersSpawned() - sendJson(w, rs) + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersSpawned") + } + return nil } type PeersConnectRequest struct { @@ -227,58 +279,78 @@ type PeersConnectRequest struct { Port uint16 `json:"port"` } -func (a *NodeApi) PeersConnect(w http.ResponseWriter, r *http.Request) { - req := new(PeersConnectRequest) - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - handleError(w, err) - return +func (a *NodeApi) PeersConnect(w http.ResponseWriter, r *http.Request) error { + req := &PeersConnectRequest{} + if err := tryParseJson(r.Body, req); err != nil { + return errors.Wrap(err, "failed to parse PeersConnect request body as JSON") } + // TODO(nickeskov): remove this and use auth middleware apiKey := r.Header.Get("X-API-Key") - rs, err := a.app.PeersConnect(r.Context(), apiKey, fmt.Sprintf("%s:%d", req.Host, req.Port)) + addr := fmt.Sprintf("%s:%d", req.Host, req.Port) + rs, err := a.app.PeersConnect(r.Context(), apiKey, addr) if err != nil { - handleError(w, err) - return + return errors.Wrapf(err, "failed to connect to new peer, addr %s", addr) + } + + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersConnect") } - sendJson(w, rs) + return nil } -func (a *NodeApi) PeersConnected(w http.ResponseWriter, _ *http.Request) { - rs, err := a.app.PeersConnected() - if err != nil { - handleError(w, err) - return +func (a *NodeApi) PeersConnected(w http.ResponseWriter, _ *http.Request) error { + rs := a.app.PeersConnected() + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersConnected") } - sendJson(w, rs) + return nil } -func (a *NodeApi) PeersSuspended(w http.ResponseWriter, _ *http.Request) { - rs, err := a.app.PeersSuspended() - if err != nil { - handleError(w, err) - return +func (a *NodeApi) PeersSuspended(w http.ResponseWriter, _ *http.Request) error { + rs := a.app.PeersSuspended() + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "PeersSuspended") } - sendJson(w, rs) + return nil } -func (a *NodeApi) BlocksGenerators(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) BlocksGenerators(w http.ResponseWriter, _ *http.Request) error { rs, err := a.app.BlocksGenerators() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "failed to get BlocksGenerators") + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "BlocksGenerators") } - sendJson(w, rs) + return nil } -func (a *NodeApi) poolTransactions(w http.ResponseWriter, _ *http.Request) { - rs := a.app.PoolTransactions() - sendJson(w, rs) +func (a *NodeApi) poolTransactions(w http.ResponseWriter, _ *http.Request) error { + type poolTransactions struct { + Count int `json:"count"` + } + + rs := poolTransactions{ + Count: a.app.PoolTransactions(), + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "poolTransactions") + } + return nil } -func (a *NodeApi) unconfirmedSize(w http.ResponseWriter, _ *http.Request) { - sendJson(w, map[string]int{ - "size": a.app.PoolTransactions(), - }) +func (a *NodeApi) unconfirmedSize(w http.ResponseWriter, _ *http.Request) error { + type unconfirmedSize struct { + Size int `json:"size"` + } + + rs := unconfirmedSize{ + Size: a.app.PoolTransactions(), + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "unconfirmedSize") + } + return nil } type rollbackRequest struct { @@ -289,21 +361,22 @@ type rollbackToHeight interface { RollbackToHeight(string, proto.Height) error } -func RollbackToHeight(app rollbackToHeight) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - js := &rollbackRequest{} - err := json.NewDecoder(r.Body).Decode(js) - if err != nil { - handleError(w, err) - return +func RollbackToHeight(app rollbackToHeight) HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { + rollbackReq := &rollbackRequest{} + if err := tryParseJson(r.Body, rollbackReq); err != nil { + return errors.Wrap(err, "failed to parse RollbackToHeight body as JSON") } + // TODO(nickeskov): remove this and use auth middleware apiKey := r.Header.Get("X-API-Key") - err = app.RollbackToHeight(apiKey, js.Height) - if err != nil { - handleError(w, err) - return + if err := app.RollbackToHeight(apiKey, rollbackReq.Height); err != nil { + return errors.Wrapf(err, "failed to rollback to height %d", rollbackReq.Height) } - sendJson(w, nil) + // TODO(nickeskov): looks like bug... + if err := trySendJson(w, nil); err != nil { + return errors.Wrap(err, "RollbackToHeight") + } + return nil } } @@ -315,81 +388,91 @@ type walletLoadKeys interface { LoadKeys(apiKey string, password []byte) error } -func WalletLoadKeys(app walletLoadKeys) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func WalletLoadKeys(app walletLoadKeys) HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { js := &walletLoadKeysRequest{} - err := json.NewDecoder(r.Body).Decode(js) - if err != nil { - handleError(w, err) - return + if err := tryParseJson(r.Body, js); err != nil { + return errors.Wrap(err, "failed to parse WalletLoadKeys body as JSON") } + // TODO(nickeskov): remove this and use auth middleware apiKey := r.Header.Get("X-API-Key") - err = app.LoadKeys(apiKey, []byte(js.Password)) - if err != nil { - handleError(w, err) - return + if err := app.LoadKeys(apiKey, []byte(js.Password)); err != nil { + return errors.Wrap(err, "failed to execute LoadKeys") } - sendJson(w, nil) + return nil } } -func (a *NodeApi) WalletAccounts(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) WalletAccounts(w http.ResponseWriter, _ *http.Request) error { rs, err := a.app.Accounts() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "failed to get Accounts") + } + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "WalletAccounts") + } + return nil +} + +func (a *NodeApi) GoMinerInfo(w http.ResponseWriter, _ *http.Request) error { + rs := a.app.Miner() + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "GoMinerInfo") } - sendJson(w, rs) + return nil } -func (a *NodeApi) MinerInfo(w http.ResponseWriter, _ *http.Request) { - rs, err := a.app.Miner() +func (a *NodeApi) Addresses(w http.ResponseWriter, _ *http.Request) error { + addresses, err := a.app.Addresses() if err != nil { - handleError(w, err) - return + return errors.Wrap(err, "failed to get Addresses") + } + if err := trySendJson(w, addresses); err != nil { + return errors.Wrap(err, "Addresses") } - sendJson(w, rs) + return nil } -func (a *NodeApi) nodeProcesses(w http.ResponseWriter, _ *http.Request) { +func (a *NodeApi) nodeProcesses(w http.ResponseWriter, _ *http.Request) error { rs := a.app.NodeProcesses() - sendJson(w, rs) + if err := trySendJson(w, rs); err != nil { + return errors.Wrap(err, "nodeProcesses") + } + return nil } -func (a *NodeApi) stateHash(w http.ResponseWriter, r *http.Request) { +func (a *NodeApi) stateHash(w http.ResponseWriter, r *http.Request) error { s := chi.URLParam(r, "height") height, err := strconv.ParseUint(s, 10, 64) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return + // TODO(nickeskov): which error it should send? + return &BadRequestError{err} } stateHash, err := a.state.StateHashAtHeight(height) if err != nil { - handleError(w, err) - return + return errors.Wrapf(err, "failed to get state hash at height %d", height) } - err = json.NewEncoder(w).Encode(stateHash) - if err != nil { - handleError(w, err) - return + if err := trySendJson(w, stateHash); err != nil { + return errors.Wrap(err, "stateHash") } + return nil } -func handleError(w http.ResponseWriter, err error) { - switch err.(type) { - case *AuthError: - http.Error(w, fmt.Sprintf("Failed to complete request: %s", err.Error()), http.StatusForbidden) - case *BadRequestError: - http.Error(w, fmt.Sprintf("Failed to complete request: %s", err.Error()), http.StatusBadRequest) - default: - http.Error(w, fmt.Sprintf("Failed to complete request: %s", err.Error()), http.StatusInternalServerError) +// tryParseJson receives reader and out params. out MUST be a pointer +func tryParseJson(r io.Reader, out interface{}) error { + // TODO(nickeskov): check empty reader + err := json.NewDecoder(r).Decode(out) + if err != nil { + return errors.Wrapf(err, "Failed to unmarshal %T as JSON into %T", r, out) } + return nil } -func sendJson(w http.ResponseWriter, v interface{}) { +func trySendJson(w io.Writer, v interface{}) error { err := json.NewEncoder(w).Encode(v) if err != nil { - http.Error(w, fmt.Sprintf("Failed to marshal status to JSON: %s", err.Error()), http.StatusInternalServerError) + return errors.Wrapf(err, "Failed to marshal %T to JSON and write it to %T", v, w) } + return nil } diff --git a/pkg/api/node_api_test.go b/pkg/api/node_api_test.go index baa3de1fe..36e0d47b5 100644 --- a/pkg/api/node_api_test.go +++ b/pkg/api/node_api_test.go @@ -28,7 +28,8 @@ func TestRollbackToHeight(t *testing.T) { req := httptest.NewRequest("POST", "/blocks/rollback", strings.NewReader(`{"height": 100500}`)) req.Header.Add(apiKey, "apikey") resp := httptest.NewRecorder() - f(resp, req) + err := f(resp, req) + assert.NoError(t, err) assert.Equal(t, "apikey", r.apiKey) assert.EqualValues(t, 100500, r.height) @@ -52,8 +53,29 @@ func TestWalletLoadKeys(t *testing.T) { req := httptest.NewRequest("POST", "/wallet/load", strings.NewReader(`{"password": "password"}`)) req.Header.Add(apiKey, "apikey") resp := httptest.NewRecorder() - f(resp, req) + err := f(resp, req) + assert.NoError(t, err) assert.Equal(t, "apikey", r.apiKey) assert.EqualValues(t, "password", r.password) } + +func TestNodeApi_FindFirstInvalidRuneInBase58String(t *testing.T) { + invalidData := []struct { + str string + expected rune + }{ + {"234234😀$32@", '😀'}, + {"234234$32@", '$'}, + {"2@3423432", '@'}, + } + + for _, testCase := range invalidData { + actual := findFirstInvalidRuneInBase58String(testCase.str) + assert.NotNil(t, actual) + assert.Equal(t, testCase.expected, *actual) + } + + actual := findFirstInvalidRuneInBase58String("42354") + assert.Nil(t, actual) +} diff --git a/pkg/api/rate_limiter.go b/pkg/api/rate_limiter.go new file mode 100644 index 000000000..17f0a8eaa --- /dev/null +++ b/pkg/api/rate_limiter.go @@ -0,0 +1,39 @@ +package api + +import ( + "github.com/pkg/errors" + "github.com/throttled/throttled/v2" + "github.com/throttled/throttled/v2/store/memstore" +) + +func createRateLimiter(opts *RateLimiterOptions) (throttled.HTTPRateLimiter, error) { + store, err := memstore.New(opts.MemoryCacheSize) + if err != nil { + return throttled.HTTPRateLimiter{}, + errors.Wrapf( + err, + "createRateLimiter: failed to create memstore with capacity %d", + opts.MemoryCacheSize, + ) + } + + quota := throttled.RateQuota{ + MaxRate: throttled.PerSec(opts.MaxRequestsPerSecond), + MaxBurst: opts.MaxBurst, + } + + rateLimiter, err := throttled.NewGCRARateLimiter(store, quota) + if err != nil { + return throttled.HTTPRateLimiter{}, + errors.Wrap(err, "createRateLimiter: can't create rate limiter") + } + + httpRateLimiter := throttled.HTTPRateLimiter{ + RateLimiter: rateLimiter, + VaryBy: &throttled.VaryBy{ + RemoteAddr: true, + }, + } + + return httpRateLimiter, nil +} diff --git a/pkg/api/routes.go b/pkg/api/routes.go index 110dd9d2e..c8e425f37 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -1,50 +1,135 @@ package api import ( - "io/ioutil" - "net/http" - "github.com/go-chi/chi" + "github.com/go-chi/chi/middleware" + "github.com/pkg/errors" "go.uber.org/zap" + "net/http" ) -func (a *NodeApi) routes() chi.Router { +type HandleErrorFunc func(w http.ResponseWriter, r *http.Request, err error) +type HandlerFunc func(w http.ResponseWriter, r *http.Request) error + +func toHTTPHandlerFunc(handler HandlerFunc, errorHandler HandleErrorFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + err := handler(writer, request) + if err != nil { + errorHandler(writer, request, err) + } + } +} + +func (a *NodeApi) routes(opts *RunOptions) (chi.Router, error) { r := chi.NewRouter() - r.NotFound(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - zap.S().Debugf("NodeApi not found %+v, %s", r, r.URL.Path) - if r.Method == "POST" { - rs, err := ioutil.ReadAll(r.Body) - zap.S().Debugf("NodeApi not found post body: %s %+v", string(rs), err) + + if opts.UseRealIPMiddleware { + // nickeskov: for nginx/haproxy specific headers + r.Use(middleware.RealIP) + } + if opts.CollectMetrics { + r.Use(chiHttpApiGeneralMetricsMiddleware) + } + if opts.RateLimiterOpts != nil { + rateLimiter, err := createRateLimiter(opts.RateLimiterOpts) + if err != nil { + return nil, errors.WithStack(err) } - w.WriteHeader(http.StatusNotFound) - })) - r.Get("/blocks/last", a.BlocksLast) - r.Get("/blocks/height", a.BlockHeight) - r.Get("/blocks/first", a.BlocksFirst) - r.Get("/blocks/at/{height:\\d+}", a.BlockAt) - r.Get("/blocks/score/at/{id:\\d+}", a.BlockScoreAt) - r.Get("/blocks/id/{id}", a.BlockIDAt) - r.Get("/blocks/generators", a.BlocksGenerators) - r.Post("/blocks/rollback", RollbackToHeight(a.app)) - r.Get("/pool/transactions", a.poolTransactions) - r.Get("/transactions/unconfirmed/size", a.unconfirmedSize) - r.Route("/peers", func(r chi.Router) { - r.Get("/known", a.PeersAll) - r.Get("/connected", a.PeersConnected) - r.Post("/connect", a.PeersConnect) - r.Get("/suspended", a.PeersSuspended) - r.Get("/spawned", a.PeersSpawned) + r.Use(rateLimiter.RateLimit) + } + if opts.LogHttpRequestOpts { + r.Use(middleware.RequestID, CreateLoggerMiddleware(zap.L())) + } + if opts.RouteNotFoundHandler != nil { + r.NotFound(opts.RouteNotFoundHandler) + } + + // nickeskov: middlewares and custom handlers + errHandler := NewErrorHandler(zap.L()) + checkAuthMiddleware := createCheckAuthMiddleware(a.app, errHandler.Handle) + + wrapper := func(handlerFunc HandlerFunc) http.HandlerFunc { + return toHTTPHandlerFunc(handlerFunc, errHandler.Handle) + } + + if opts.EnableHeartbeatRoute { + r.Get("/go/node/healthz", func(w http.ResponseWriter, r *http.Request) { + if _, err := w.Write([]byte("OK")); err != nil { + zap.S().Errorf("Can't write 'OK' to ResponseWriter: %+v", err) + w.WriteHeader(http.StatusInternalServerError) + } + }) + } + + // nickeskov: go node routes + r.Route("/go", func(r chi.Router) { + r.Route("/blocks", func(r chi.Router) { + r.Get("/score/at/{id:\\d+}", wrapper(a.BlockScoreAt)) + r.Get("/id/{id}", wrapper(a.BlockIDAt)) + r.Get("/generators", wrapper(a.BlocksGenerators)) + + rAuth := r.With(checkAuthMiddleware) + + rAuth.Post("/rollback", wrapper(RollbackToHeight(a.app))) + }) + + r.Route("/peers", func(r chi.Router) { + r.Get("/known", wrapper(a.PeersKnown)) + r.Get("/spawned", wrapper(a.PeersSpawned)) + }) + + r.Route("/wallet", func(r chi.Router) { + r.Get("/accounts", wrapper(a.WalletAccounts)) + + rAuth := r.With(checkAuthMiddleware) + + rAuth.Post("/load", wrapper(WalletLoadKeys(a.app))) + }) + + r.Get("/miner/info", wrapper(a.GoMinerInfo)) + r.Get("/node/processes", wrapper(a.nodeProcesses)) + r.Get("/pool/transactions", wrapper(a.poolTransactions)) }) - r.Get("/miner/info", a.MinerInfo) - r.Post("/transactions/broadcast", a.TransactionsBroadcast) - r.Post("/wallet/load", WalletLoadKeys(a.app)) - r.Get("/wallet/accounts", a.WalletAccounts) + // nickeskov: json api + r.Group(func(r chi.Router) { + r.Route("/blocks", func(r chi.Router) { + r.Get("/last", wrapper(a.BlocksLast)) + r.Get("/height", wrapper(a.BlockHeight)) + r.Get("/first", wrapper(a.BlocksFirst)) + r.Get("/at/{height}", wrapper(a.BlockAt)) + r.Get("/{id}", wrapper(a.BlockIDAt)) + }) + + r.Route("/addresses", func(r chi.Router) { + r.Get("/", wrapper(a.Addresses)) + }) + + r.Route("/transactions", func(r chi.Router) { + r.Get("/unconfirmed/size", wrapper(a.unconfirmedSize)) - r.Get("/node/processes", a.nodeProcesses) - r.Get("/debug/stateHash/{height:\\d+}", a.stateHash) - // enable or disable history sync - //r.Get("/debug/sync/{enabled:\\d+}", a.DebugSyncEnabled) + rAuth := r.With(checkAuthMiddleware) + + rAuth.Post("/broadcast", wrapper(a.TransactionsBroadcast)) + }) + + r.Route("/peers", func(r chi.Router) { + r.Get("/all", wrapper(a.PeersAll)) + r.Get("/connected", wrapper(a.PeersConnected)) + r.Get("/suspended", wrapper(a.PeersSuspended)) + + rAuth := r.With(checkAuthMiddleware) + + rAuth.Post("/connect", wrapper(a.PeersConnect)) + }) + + r.Route("/debug", func(r chi.Router) { + r.Get("/stateHash/{height:\\d+}", wrapper(a.stateHash)) + }) + + // enable or disable history sync + //r.Get("/debug/sync/{enabled:\\d+}", a.DebugSyncEnabled) + }) - return r + return r, nil } diff --git a/pkg/api/settings.go b/pkg/api/settings.go index 778f64ec1..3322c502e 100644 --- a/pkg/api/settings.go +++ b/pkg/api/settings.go @@ -1 +1,47 @@ package api + +import ( + "go.uber.org/zap" + "io/ioutil" + "net/http" +) + +//const ( +// rateLimiterMemoryCacheSize = 65_536 +// rateLimiterMaxRequestsPerSecond = 100 +// rateLimiterMaxBurst = 5 +//) + +type RunOptions struct { + RateLimiterOpts *RateLimiterOptions + LogHttpRequestOpts bool + CollectMetrics bool + UseRealIPMiddleware bool + EnableHeartbeatRoute bool + RouteNotFoundHandler func(w http.ResponseWriter, r *http.Request) +} + +type RateLimiterOptions struct { + MemoryCacheSize int + MaxRequestsPerSecond int + MaxBurst int +} + +func DefaultRunOptions() *RunOptions { + return &RunOptions{ + RateLimiterOpts: nil, + LogHttpRequestOpts: false, + EnableHeartbeatRoute: true, + UseRealIPMiddleware: true, + CollectMetrics: true, + RouteNotFoundHandler: func(w http.ResponseWriter, r *http.Request) { + zap.S().Debugf("NodeApi not found %+v, %s", r, r.URL.Path) + if r.Method == http.MethodPost { + // TODO(nickeskov): it looks vulnerable (memory overflow) + rs, err := ioutil.ReadAll(r.Body) + zap.S().Debugf("NodeApi not found post body: %s %+v", string(rs), err) + } + w.WriteHeader(http.StatusNotFound) + }, + } +} diff --git a/pkg/grpc/generated/waves/amount.pb.go b/pkg/grpc/generated/waves/amount.pb.go index 1e493f9b0..dfcd35aa8 100644 --- a/pkg/grpc/generated/waves/amount.pb.go +++ b/pkg/grpc/generated/waves/amount.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/amount.proto package waves diff --git a/pkg/grpc/generated/waves/block.pb.go b/pkg/grpc/generated/waves/block.pb.go index cbf18f54d..1d5c84a8c 100644 --- a/pkg/grpc/generated/waves/block.pb.go +++ b/pkg/grpc/generated/waves/block.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/block.proto package waves diff --git a/pkg/grpc/generated/waves/invoke_script_result.pb.go b/pkg/grpc/generated/waves/invoke_script_result.pb.go index 1b0871dfa..c68577dda 100644 --- a/pkg/grpc/generated/waves/invoke_script_result.pb.go +++ b/pkg/grpc/generated/waves/invoke_script_result.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/invoke_script_result.proto package waves @@ -30,13 +30,15 @@ type InvokeScriptResult struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Data []*DataTransactionData_DataEntry `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - Transfers []*InvokeScriptResult_Payment `protobuf:"bytes,2,rep,name=transfers,proto3" json:"transfers,omitempty"` - Issues []*InvokeScriptResult_Issue `protobuf:"bytes,3,rep,name=issues,proto3" json:"issues,omitempty"` - Reissues []*InvokeScriptResult_Reissue `protobuf:"bytes,4,rep,name=reissues,proto3" json:"reissues,omitempty"` - Burns []*InvokeScriptResult_Burn `protobuf:"bytes,5,rep,name=burns,proto3" json:"burns,omitempty"` - ErrorMessage *InvokeScriptResult_ErrorMessage `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` - SponsorFees []*InvokeScriptResult_SponsorFee `protobuf:"bytes,7,rep,name=sponsor_fees,json=sponsorFees,proto3" json:"sponsor_fees,omitempty"` + Data []*DataTransactionData_DataEntry `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Transfers []*InvokeScriptResult_Payment `protobuf:"bytes,2,rep,name=transfers,proto3" json:"transfers,omitempty"` + Issues []*InvokeScriptResult_Issue `protobuf:"bytes,3,rep,name=issues,proto3" json:"issues,omitempty"` + Reissues []*InvokeScriptResult_Reissue `protobuf:"bytes,4,rep,name=reissues,proto3" json:"reissues,omitempty"` + Burns []*InvokeScriptResult_Burn `protobuf:"bytes,5,rep,name=burns,proto3" json:"burns,omitempty"` + ErrorMessage *InvokeScriptResult_ErrorMessage `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + SponsorFees []*InvokeScriptResult_SponsorFee `protobuf:"bytes,7,rep,name=sponsor_fees,json=sponsorFees,proto3" json:"sponsor_fees,omitempty"` + Leases []*InvokeScriptResult_Lease `protobuf:"bytes,8,rep,name=leases,proto3" json:"leases,omitempty"` + LeaseCancels []*InvokeScriptResult_LeaseCancel `protobuf:"bytes,9,rep,name=lease_cancels,json=leaseCancels,proto3" json:"lease_cancels,omitempty"` } func (x *InvokeScriptResult) Reset() { @@ -120,6 +122,20 @@ func (x *InvokeScriptResult) GetSponsorFees() []*InvokeScriptResult_SponsorFee { return nil } +func (x *InvokeScriptResult) GetLeases() []*InvokeScriptResult_Lease { + if x != nil { + return x.Leases + } + return nil +} + +func (x *InvokeScriptResult) GetLeaseCancels() []*InvokeScriptResult_LeaseCancel { + if x != nil { + return x.LeaseCancels + } + return nil +} + type InvokeScriptResult_Payment struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -443,6 +459,124 @@ func (x *InvokeScriptResult_SponsorFee) GetMinFee() *Amount { return nil } +type InvokeScriptResult_Lease struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Recipient *Recipient `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` + Nonce int64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"` + LeaseId []byte `protobuf:"bytes,4,opt,name=lease_id,json=leaseId,proto3" json:"lease_id,omitempty"` +} + +func (x *InvokeScriptResult_Lease) Reset() { + *x = InvokeScriptResult_Lease{} + if protoimpl.UnsafeEnabled { + mi := &file_waves_invoke_script_result_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvokeScriptResult_Lease) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvokeScriptResult_Lease) ProtoMessage() {} + +func (x *InvokeScriptResult_Lease) ProtoReflect() protoreflect.Message { + mi := &file_waves_invoke_script_result_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvokeScriptResult_Lease.ProtoReflect.Descriptor instead. +func (*InvokeScriptResult_Lease) Descriptor() ([]byte, []int) { + return file_waves_invoke_script_result_proto_rawDescGZIP(), []int{0, 5} +} + +func (x *InvokeScriptResult_Lease) GetRecipient() *Recipient { + if x != nil { + return x.Recipient + } + return nil +} + +func (x *InvokeScriptResult_Lease) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *InvokeScriptResult_Lease) GetNonce() int64 { + if x != nil { + return x.Nonce + } + return 0 +} + +func (x *InvokeScriptResult_Lease) GetLeaseId() []byte { + if x != nil { + return x.LeaseId + } + return nil +} + +type InvokeScriptResult_LeaseCancel struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LeaseId []byte `protobuf:"bytes,1,opt,name=lease_id,json=leaseId,proto3" json:"lease_id,omitempty"` +} + +func (x *InvokeScriptResult_LeaseCancel) Reset() { + *x = InvokeScriptResult_LeaseCancel{} + if protoimpl.UnsafeEnabled { + mi := &file_waves_invoke_script_result_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvokeScriptResult_LeaseCancel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvokeScriptResult_LeaseCancel) ProtoMessage() {} + +func (x *InvokeScriptResult_LeaseCancel) ProtoReflect() protoreflect.Message { + mi := &file_waves_invoke_script_result_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvokeScriptResult_LeaseCancel.ProtoReflect.Descriptor instead. +func (*InvokeScriptResult_LeaseCancel) Descriptor() ([]byte, []int) { + return file_waves_invoke_script_result_proto_rawDescGZIP(), []int{0, 6} +} + +func (x *InvokeScriptResult_LeaseCancel) GetLeaseId() []byte { + if x != nil { + return x.LeaseId + } + return nil +} + type InvokeScriptResult_ErrorMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -455,7 +589,7 @@ type InvokeScriptResult_ErrorMessage struct { func (x *InvokeScriptResult_ErrorMessage) Reset() { *x = InvokeScriptResult_ErrorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_waves_invoke_script_result_proto_msgTypes[6] + mi := &file_waves_invoke_script_result_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -468,7 +602,7 @@ func (x *InvokeScriptResult_ErrorMessage) String() string { func (*InvokeScriptResult_ErrorMessage) ProtoMessage() {} func (x *InvokeScriptResult_ErrorMessage) ProtoReflect() protoreflect.Message { - mi := &file_waves_invoke_script_result_proto_msgTypes[6] + mi := &file_waves_invoke_script_result_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -481,7 +615,7 @@ func (x *InvokeScriptResult_ErrorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use InvokeScriptResult_ErrorMessage.ProtoReflect.Descriptor instead. func (*InvokeScriptResult_ErrorMessage) Descriptor() ([]byte, []int) { - return file_waves_invoke_script_result_proto_rawDescGZIP(), []int{0, 5} + return file_waves_invoke_script_result_proto_rawDescGZIP(), []int{0, 7} } func (x *InvokeScriptResult_ErrorMessage) GetCode() int32 { @@ -506,79 +640,99 @@ var file_waves_invoke_script_result_proto_rawDesc = []byte{ 0x74, 0x6f, 0x12, 0x05, 0x77, 0x61, 0x76, 0x65, 0x73, 0x1a, 0x17, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88, 0x08, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x6f, 0x6b, - 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x38, 0x0a, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x66, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x61, 0x76, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x72, 0x65, + 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x0a, + 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, + 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x12, + 0x37, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x08, 0x72, 0x65, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, - 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x73, 0x12, 0x3d, 0x0a, 0x08, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, - 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x52, - 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x52, 0x08, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, - 0x12, 0x34, 0x0a, 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x42, 0x75, 0x72, 0x6e, 0x52, - 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x5f, 0x66, - 0x65, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, - 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x53, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x46, 0x65, 0x65, 0x52, - 0x0b, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x46, 0x65, 0x65, 0x73, 0x1a, 0x4a, 0x0a, 0x07, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x25, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xda, 0x01, 0x0a, 0x05, 0x49, 0x73, 0x73, - 0x75, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, - 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, - 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x69, 0x73, 0x73, - 0x75, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x65, 0x69, - 0x73, 0x73, 0x75, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x1a, 0x61, 0x0a, 0x07, 0x52, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, - 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x52, 0x65, - 0x69, 0x73, 0x73, 0x75, 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x39, 0x0a, 0x04, 0x42, 0x75, 0x72, 0x6e, - 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x1a, 0x34, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x46, 0x65, - 0x65, 0x12, 0x26, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x06, 0x6d, 0x69, 0x6e, 0x46, 0x65, 0x65, 0x1a, 0x36, 0x0a, 0x0c, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, - 0x74, 0x42, 0x6b, 0x0a, 0x26, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5a, 0x39, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x67, 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0xaa, 0x02, 0x05, 0x57, 0x61, 0x76, 0x65, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x52, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x52, 0x08, 0x72, + 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2e, 0x42, 0x75, 0x72, 0x6e, 0x52, 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, 0x12, 0x4b, 0x0a, + 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, + 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x53, 0x70, 0x6f, 0x6e, + 0x73, 0x6f, 0x72, 0x46, 0x65, 0x65, 0x52, 0x0b, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x46, + 0x65, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, + 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4c, + 0x65, 0x61, 0x73, 0x65, 0x52, 0x06, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0d, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x18, 0x09, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, + 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4c, + 0x65, 0x61, 0x73, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x1a, 0x4a, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xda, 0x01, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x19, + 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, 0x61, + 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6e, + 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, + 0x65, 0x1a, 0x61, 0x0a, 0x07, 0x52, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x69, 0x73, 0x73, 0x75, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x52, 0x65, 0x69, 0x73, 0x73, 0x75, + 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x39, 0x0a, 0x04, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x19, 0x0a, 0x08, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, + 0x34, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x6e, 0x73, 0x6f, 0x72, 0x46, 0x65, 0x65, 0x12, 0x26, 0x0a, + 0x07, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6d, + 0x69, 0x6e, 0x46, 0x65, 0x65, 0x1a, 0x80, 0x01, 0x0a, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, + 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, + 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x1a, 0x28, 0x0a, 0x0b, 0x4c, 0x65, 0x61, 0x73, + 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x49, 0x64, 0x1a, 0x36, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x42, 0x6b, 0x0a, 0x26, 0x63, 0x6f, + 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x67, + 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0xaa, + 0x02, 0x05, 0x57, 0x61, 0x76, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -593,7 +747,7 @@ func file_waves_invoke_script_result_proto_rawDescGZIP() []byte { return file_waves_invoke_script_result_proto_rawDescData } -var file_waves_invoke_script_result_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_waves_invoke_script_result_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_waves_invoke_script_result_proto_goTypes = []interface{}{ (*InvokeScriptResult)(nil), // 0: waves.InvokeScriptResult (*InvokeScriptResult_Payment)(nil), // 1: waves.InvokeScriptResult.Payment @@ -601,25 +755,31 @@ var file_waves_invoke_script_result_proto_goTypes = []interface{}{ (*InvokeScriptResult_Reissue)(nil), // 3: waves.InvokeScriptResult.Reissue (*InvokeScriptResult_Burn)(nil), // 4: waves.InvokeScriptResult.Burn (*InvokeScriptResult_SponsorFee)(nil), // 5: waves.InvokeScriptResult.SponsorFee - (*InvokeScriptResult_ErrorMessage)(nil), // 6: waves.InvokeScriptResult.ErrorMessage - (*DataTransactionData_DataEntry)(nil), // 7: waves.DataTransactionData.DataEntry - (*Amount)(nil), // 8: waves.Amount + (*InvokeScriptResult_Lease)(nil), // 6: waves.InvokeScriptResult.Lease + (*InvokeScriptResult_LeaseCancel)(nil), // 7: waves.InvokeScriptResult.LeaseCancel + (*InvokeScriptResult_ErrorMessage)(nil), // 8: waves.InvokeScriptResult.ErrorMessage + (*DataTransactionData_DataEntry)(nil), // 9: waves.DataTransactionData.DataEntry + (*Amount)(nil), // 10: waves.Amount + (*Recipient)(nil), // 11: waves.Recipient } var file_waves_invoke_script_result_proto_depIdxs = []int32{ - 7, // 0: waves.InvokeScriptResult.data:type_name -> waves.DataTransactionData.DataEntry - 1, // 1: waves.InvokeScriptResult.transfers:type_name -> waves.InvokeScriptResult.Payment - 2, // 2: waves.InvokeScriptResult.issues:type_name -> waves.InvokeScriptResult.Issue - 3, // 3: waves.InvokeScriptResult.reissues:type_name -> waves.InvokeScriptResult.Reissue - 4, // 4: waves.InvokeScriptResult.burns:type_name -> waves.InvokeScriptResult.Burn - 6, // 5: waves.InvokeScriptResult.error_message:type_name -> waves.InvokeScriptResult.ErrorMessage - 5, // 6: waves.InvokeScriptResult.sponsor_fees:type_name -> waves.InvokeScriptResult.SponsorFee - 8, // 7: waves.InvokeScriptResult.Payment.amount:type_name -> waves.Amount - 8, // 8: waves.InvokeScriptResult.SponsorFee.min_fee:type_name -> waves.Amount - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 9, // 0: waves.InvokeScriptResult.data:type_name -> waves.DataTransactionData.DataEntry + 1, // 1: waves.InvokeScriptResult.transfers:type_name -> waves.InvokeScriptResult.Payment + 2, // 2: waves.InvokeScriptResult.issues:type_name -> waves.InvokeScriptResult.Issue + 3, // 3: waves.InvokeScriptResult.reissues:type_name -> waves.InvokeScriptResult.Reissue + 4, // 4: waves.InvokeScriptResult.burns:type_name -> waves.InvokeScriptResult.Burn + 8, // 5: waves.InvokeScriptResult.error_message:type_name -> waves.InvokeScriptResult.ErrorMessage + 5, // 6: waves.InvokeScriptResult.sponsor_fees:type_name -> waves.InvokeScriptResult.SponsorFee + 6, // 7: waves.InvokeScriptResult.leases:type_name -> waves.InvokeScriptResult.Lease + 7, // 8: waves.InvokeScriptResult.lease_cancels:type_name -> waves.InvokeScriptResult.LeaseCancel + 10, // 9: waves.InvokeScriptResult.Payment.amount:type_name -> waves.Amount + 10, // 10: waves.InvokeScriptResult.SponsorFee.min_fee:type_name -> waves.Amount + 11, // 11: waves.InvokeScriptResult.Lease.recipient:type_name -> waves.Recipient + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_waves_invoke_script_result_proto_init() } @@ -629,6 +789,7 @@ func file_waves_invoke_script_result_proto_init() { } file_waves_transaction_proto_init() file_waves_amount_proto_init() + file_waves_recipient_proto_init() if !protoimpl.UnsafeEnabled { file_waves_invoke_script_result_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InvokeScriptResult); i { @@ -703,6 +864,30 @@ func file_waves_invoke_script_result_proto_init() { } } file_waves_invoke_script_result_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvokeScriptResult_Lease); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_waves_invoke_script_result_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvokeScriptResult_LeaseCancel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_waves_invoke_script_result_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InvokeScriptResult_ErrorMessage); i { case 0: return &v.state @@ -721,7 +906,7 @@ func file_waves_invoke_script_result_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_waves_invoke_script_result_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 9, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/grpc/generated/waves/node/grpc/accounts_api.pb.go b/pkg/grpc/generated/waves/node/grpc/accounts_api.pb.go index 1cf63987b..13ba60e76 100644 --- a/pkg/grpc/generated/waves/node/grpc/accounts_api.pb.go +++ b/pkg/grpc/generated/waves/node/grpc/accounts_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/node/grpc/accounts_api.proto package grpc @@ -9,13 +9,13 @@ package grpc import ( context "context" proto "github.com/golang/protobuf/proto" - wrappers "github.com/golang/protobuf/ptypes/wrappers" waves "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -386,6 +386,93 @@ func (x *ScriptData) GetComplexity() int64 { return 0 } +type LeaseResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LeaseId []byte `protobuf:"bytes,1,opt,name=leaseId,proto3" json:"leaseId,omitempty"` + OriginTransactionId []byte `protobuf:"bytes,2,opt,name=originTransactionId,proto3" json:"originTransactionId,omitempty"` + Sender []byte `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` + Recipient *waves.Recipient `protobuf:"bytes,4,opt,name=recipient,proto3" json:"recipient,omitempty"` + Amount int64 `protobuf:"varint,5,opt,name=amount,proto3" json:"amount,omitempty"` + Height int64 `protobuf:"varint,6,opt,name=height,proto3" json:"height,omitempty"` +} + +func (x *LeaseResponse) Reset() { + *x = LeaseResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LeaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LeaseResponse) ProtoMessage() {} + +func (x *LeaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LeaseResponse.ProtoReflect.Descriptor instead. +func (*LeaseResponse) Descriptor() ([]byte, []int) { + return file_waves_node_grpc_accounts_api_proto_rawDescGZIP(), []int{6} +} + +func (x *LeaseResponse) GetLeaseId() []byte { + if x != nil { + return x.LeaseId + } + return nil +} + +func (x *LeaseResponse) GetOriginTransactionId() []byte { + if x != nil { + return x.OriginTransactionId + } + return nil +} + +func (x *LeaseResponse) GetSender() []byte { + if x != nil { + return x.Sender + } + return nil +} + +func (x *LeaseResponse) GetRecipient() *waves.Recipient { + if x != nil { + return x.Recipient + } + return nil +} + +func (x *LeaseResponse) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *LeaseResponse) GetHeight() int64 { + if x != nil { + return x.Height + } + return 0 +} + type BalanceResponse_WavesBalances struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -402,7 +489,7 @@ type BalanceResponse_WavesBalances struct { func (x *BalanceResponse_WavesBalances) Reset() { *x = BalanceResponse_WavesBalances{} if protoimpl.UnsafeEnabled { - mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[6] + mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -415,7 +502,7 @@ func (x *BalanceResponse_WavesBalances) String() string { func (*BalanceResponse_WavesBalances) ProtoMessage() {} func (x *BalanceResponse_WavesBalances) ProtoReflect() protoreflect.Message { - mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[6] + mi := &file_waves_node_grpc_accounts_api_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -479,94 +566,106 @@ var file_waves_node_grpc_accounts_api_proto_rawDesc = []byte{ 0x0a, 0x22, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x26, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, - 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x77, - 0x61, 0x76, 0x65, 0x73, 0x2f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x17, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, - 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2a, 0x0a, 0x0e, 0x41, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x39, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x22, 0x43, 0x0a, 0x0f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x12, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x15, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, + 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2a, 0x0a, 0x0e, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x39, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, - 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x0f, 0x42, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x05, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x77, 0x61, 0x76, 0x65, - 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x57, 0x61, 0x76, 0x65, - 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x48, 0x00, 0x52, 0x05, 0x77, 0x61, 0x76, - 0x65, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x1a, 0xbd, 0x01, 0x0a, 0x0d, 0x57, 0x61, - 0x76, 0x65, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, - 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, 0x65, - 0x67, 0x75, 0x6c, 0x61, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, - 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x12, 0x1b, 0x0a, 0x09, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x22, 0x69, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x3a, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, - 0x70, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, - 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x65, 0x78, - 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, - 0x79, 0x32, 0xaa, 0x03, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x41, 0x70, - 0x69, 0x12, 0x53, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x12, 0x20, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x49, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x44, 0x61, 0x74, - 0x61, 0x12, 0x5a, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4c, 0x65, - 0x61, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x54, 0x0a, - 0x0e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, - 0x1c, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, - 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x30, 0x01, 0x12, 0x49, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x6c, - 0x69, 0x61, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x73, - 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5a, 0x43, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x67, 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x72, 0x70, - 0x63, 0xaa, 0x02, 0x0f, 0x57, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x47, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x22, 0x43, 0x0a, 0x0f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x0f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x05, 0x77, 0x61, 0x76, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x57, 0x61, 0x76, 0x65, 0x73, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x48, 0x00, 0x52, 0x05, 0x77, 0x61, 0x76, 0x65, + 0x73, 0x12, 0x25, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x1a, 0xbd, 0x01, 0x0a, 0x0d, 0x57, 0x61, 0x76, + 0x65, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, + 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, 0x65, 0x67, + 0x75, 0x6c, 0x61, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x22, 0x69, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x3a, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x70, + 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x65, 0x78, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, + 0x22, 0xd3, 0x01, 0x0a, 0x0d, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x61, 0x76, 0x65, + 0x73, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x32, 0xa4, 0x03, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x41, 0x70, 0x69, 0x12, 0x53, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x49, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x76, 0x65, + 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x76, 0x65, + 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x76, + 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, + 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x1c, + 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, + 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x30, 0x01, 0x12, 0x49, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x6c, 0x69, + 0x61, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x73, 0x0a, + 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5a, 0x43, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x67, 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, 0x6b, + 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, + 0xaa, 0x02, 0x0f, 0x57, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x72, + 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -581,7 +680,7 @@ func file_waves_node_grpc_accounts_api_proto_rawDescGZIP() []byte { return file_waves_node_grpc_accounts_api_proto_rawDescData } -var file_waves_node_grpc_accounts_api_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_waves_node_grpc_accounts_api_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_waves_node_grpc_accounts_api_proto_goTypes = []interface{}{ (*AccountRequest)(nil), // 0: waves.node.grpc.AccountRequest (*DataRequest)(nil), // 1: waves.node.grpc.DataRequest @@ -589,32 +688,34 @@ var file_waves_node_grpc_accounts_api_proto_goTypes = []interface{}{ (*BalanceResponse)(nil), // 3: waves.node.grpc.BalanceResponse (*DataEntryResponse)(nil), // 4: waves.node.grpc.DataEntryResponse (*ScriptData)(nil), // 5: waves.node.grpc.ScriptData - (*BalanceResponse_WavesBalances)(nil), // 6: waves.node.grpc.BalanceResponse.WavesBalances - (*waves.Amount)(nil), // 7: waves.Amount - (*waves.DataTransactionData_DataEntry)(nil), // 8: waves.DataTransactionData.DataEntry - (*wrappers.StringValue)(nil), // 9: google.protobuf.StringValue - (*TransactionResponse)(nil), // 10: waves.node.grpc.TransactionResponse - (*wrappers.BytesValue)(nil), // 11: google.protobuf.BytesValue + (*LeaseResponse)(nil), // 6: waves.node.grpc.LeaseResponse + (*BalanceResponse_WavesBalances)(nil), // 7: waves.node.grpc.BalanceResponse.WavesBalances + (*waves.Amount)(nil), // 8: waves.Amount + (*waves.DataTransactionData_DataEntry)(nil), // 9: waves.DataTransactionData.DataEntry + (*waves.Recipient)(nil), // 10: waves.Recipient + (*wrapperspb.StringValue)(nil), // 11: google.protobuf.StringValue + (*wrapperspb.BytesValue)(nil), // 12: google.protobuf.BytesValue } var file_waves_node_grpc_accounts_api_proto_depIdxs = []int32{ - 6, // 0: waves.node.grpc.BalanceResponse.waves:type_name -> waves.node.grpc.BalanceResponse.WavesBalances - 7, // 1: waves.node.grpc.BalanceResponse.asset:type_name -> waves.Amount - 8, // 2: waves.node.grpc.DataEntryResponse.entry:type_name -> waves.DataTransactionData.DataEntry - 2, // 3: waves.node.grpc.AccountsApi.GetBalances:input_type -> waves.node.grpc.BalancesRequest - 0, // 4: waves.node.grpc.AccountsApi.GetScript:input_type -> waves.node.grpc.AccountRequest - 0, // 5: waves.node.grpc.AccountsApi.GetActiveLeases:input_type -> waves.node.grpc.AccountRequest - 1, // 6: waves.node.grpc.AccountsApi.GetDataEntries:input_type -> waves.node.grpc.DataRequest - 9, // 7: waves.node.grpc.AccountsApi.ResolveAlias:input_type -> google.protobuf.StringValue - 3, // 8: waves.node.grpc.AccountsApi.GetBalances:output_type -> waves.node.grpc.BalanceResponse - 5, // 9: waves.node.grpc.AccountsApi.GetScript:output_type -> waves.node.grpc.ScriptData - 10, // 10: waves.node.grpc.AccountsApi.GetActiveLeases:output_type -> waves.node.grpc.TransactionResponse - 4, // 11: waves.node.grpc.AccountsApi.GetDataEntries:output_type -> waves.node.grpc.DataEntryResponse - 11, // 12: waves.node.grpc.AccountsApi.ResolveAlias:output_type -> google.protobuf.BytesValue - 8, // [8:13] is the sub-list for method output_type - 3, // [3:8] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 7, // 0: waves.node.grpc.BalanceResponse.waves:type_name -> waves.node.grpc.BalanceResponse.WavesBalances + 8, // 1: waves.node.grpc.BalanceResponse.asset:type_name -> waves.Amount + 9, // 2: waves.node.grpc.DataEntryResponse.entry:type_name -> waves.DataTransactionData.DataEntry + 10, // 3: waves.node.grpc.LeaseResponse.recipient:type_name -> waves.Recipient + 2, // 4: waves.node.grpc.AccountsApi.GetBalances:input_type -> waves.node.grpc.BalancesRequest + 0, // 5: waves.node.grpc.AccountsApi.GetScript:input_type -> waves.node.grpc.AccountRequest + 0, // 6: waves.node.grpc.AccountsApi.GetActiveLeases:input_type -> waves.node.grpc.AccountRequest + 1, // 7: waves.node.grpc.AccountsApi.GetDataEntries:input_type -> waves.node.grpc.DataRequest + 11, // 8: waves.node.grpc.AccountsApi.ResolveAlias:input_type -> google.protobuf.StringValue + 3, // 9: waves.node.grpc.AccountsApi.GetBalances:output_type -> waves.node.grpc.BalanceResponse + 5, // 10: waves.node.grpc.AccountsApi.GetScript:output_type -> waves.node.grpc.ScriptData + 6, // 11: waves.node.grpc.AccountsApi.GetActiveLeases:output_type -> waves.node.grpc.LeaseResponse + 4, // 12: waves.node.grpc.AccountsApi.GetDataEntries:output_type -> waves.node.grpc.DataEntryResponse + 12, // 13: waves.node.grpc.AccountsApi.ResolveAlias:output_type -> google.protobuf.BytesValue + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_waves_node_grpc_accounts_api_proto_init() } @@ -622,7 +723,6 @@ func file_waves_node_grpc_accounts_api_proto_init() { if File_waves_node_grpc_accounts_api_proto != nil { return } - file_waves_node_grpc_transactions_api_proto_init() if !protoimpl.UnsafeEnabled { file_waves_node_grpc_accounts_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AccountRequest); i { @@ -697,6 +797,18 @@ func file_waves_node_grpc_accounts_api_proto_init() { } } file_waves_node_grpc_accounts_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LeaseResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_waves_node_grpc_accounts_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BalanceResponse_WavesBalances); i { case 0: return &v.state @@ -719,7 +831,7 @@ func file_waves_node_grpc_accounts_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_waves_node_grpc_accounts_api_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, @@ -749,7 +861,7 @@ type AccountsApiClient interface { GetScript(ctx context.Context, in *AccountRequest, opts ...grpc.CallOption) (*ScriptData, error) GetActiveLeases(ctx context.Context, in *AccountRequest, opts ...grpc.CallOption) (AccountsApi_GetActiveLeasesClient, error) GetDataEntries(ctx context.Context, in *DataRequest, opts ...grpc.CallOption) (AccountsApi_GetDataEntriesClient, error) - ResolveAlias(ctx context.Context, in *wrappers.StringValue, opts ...grpc.CallOption) (*wrappers.BytesValue, error) + ResolveAlias(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*wrapperspb.BytesValue, error) } type accountsApiClient struct { @@ -817,7 +929,7 @@ func (c *accountsApiClient) GetActiveLeases(ctx context.Context, in *AccountRequ } type AccountsApi_GetActiveLeasesClient interface { - Recv() (*TransactionResponse, error) + Recv() (*LeaseResponse, error) grpc.ClientStream } @@ -825,8 +937,8 @@ type accountsApiGetActiveLeasesClient struct { grpc.ClientStream } -func (x *accountsApiGetActiveLeasesClient) Recv() (*TransactionResponse, error) { - m := new(TransactionResponse) +func (x *accountsApiGetActiveLeasesClient) Recv() (*LeaseResponse, error) { + m := new(LeaseResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -865,8 +977,8 @@ func (x *accountsApiGetDataEntriesClient) Recv() (*DataEntryResponse, error) { return m, nil } -func (c *accountsApiClient) ResolveAlias(ctx context.Context, in *wrappers.StringValue, opts ...grpc.CallOption) (*wrappers.BytesValue, error) { - out := new(wrappers.BytesValue) +func (c *accountsApiClient) ResolveAlias(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*wrapperspb.BytesValue, error) { + out := new(wrapperspb.BytesValue) err := c.cc.Invoke(ctx, "/waves.node.grpc.AccountsApi/ResolveAlias", in, out, opts...) if err != nil { return nil, err @@ -880,7 +992,7 @@ type AccountsApiServer interface { GetScript(context.Context, *AccountRequest) (*ScriptData, error) GetActiveLeases(*AccountRequest, AccountsApi_GetActiveLeasesServer) error GetDataEntries(*DataRequest, AccountsApi_GetDataEntriesServer) error - ResolveAlias(context.Context, *wrappers.StringValue) (*wrappers.BytesValue, error) + ResolveAlias(context.Context, *wrapperspb.StringValue) (*wrapperspb.BytesValue, error) } // UnimplementedAccountsApiServer can be embedded to have forward compatible implementations. @@ -899,7 +1011,7 @@ func (*UnimplementedAccountsApiServer) GetActiveLeases(*AccountRequest, Accounts func (*UnimplementedAccountsApiServer) GetDataEntries(*DataRequest, AccountsApi_GetDataEntriesServer) error { return status.Errorf(codes.Unimplemented, "method GetDataEntries not implemented") } -func (*UnimplementedAccountsApiServer) ResolveAlias(context.Context, *wrappers.StringValue) (*wrappers.BytesValue, error) { +func (*UnimplementedAccountsApiServer) ResolveAlias(context.Context, *wrapperspb.StringValue) (*wrapperspb.BytesValue, error) { return nil, status.Errorf(codes.Unimplemented, "method ResolveAlias not implemented") } @@ -955,7 +1067,7 @@ func _AccountsApi_GetActiveLeases_Handler(srv interface{}, stream grpc.ServerStr } type AccountsApi_GetActiveLeasesServer interface { - Send(*TransactionResponse) error + Send(*LeaseResponse) error grpc.ServerStream } @@ -963,7 +1075,7 @@ type accountsApiGetActiveLeasesServer struct { grpc.ServerStream } -func (x *accountsApiGetActiveLeasesServer) Send(m *TransactionResponse) error { +func (x *accountsApiGetActiveLeasesServer) Send(m *LeaseResponse) error { return x.ServerStream.SendMsg(m) } @@ -989,7 +1101,7 @@ func (x *accountsApiGetDataEntriesServer) Send(m *DataEntryResponse) error { } func _AccountsApi_ResolveAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(wrappers.StringValue) + in := new(wrapperspb.StringValue) if err := dec(in); err != nil { return nil, err } @@ -1001,7 +1113,7 @@ func _AccountsApi_ResolveAlias_Handler(srv interface{}, ctx context.Context, dec FullMethod: "/waves.node.grpc.AccountsApi/ResolveAlias", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AccountsApiServer).ResolveAlias(ctx, req.(*wrappers.StringValue)) + return srv.(AccountsApiServer).ResolveAlias(ctx, req.(*wrapperspb.StringValue)) } return interceptor(ctx, in, info, handler) } diff --git a/pkg/grpc/generated/waves/node/grpc/assets_api.pb.go b/pkg/grpc/generated/waves/node/grpc/assets_api.pb.go index 0e385960a..5466a79ae 100644 --- a/pkg/grpc/generated/waves/node/grpc/assets_api.pb.go +++ b/pkg/grpc/generated/waves/node/grpc/assets_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/node/grpc/assets_api.proto package grpc diff --git a/pkg/grpc/generated/waves/node/grpc/blockchain_api.pb.go b/pkg/grpc/generated/waves/node/grpc/blockchain_api.pb.go index dd13a7215..65f6fac81 100644 --- a/pkg/grpc/generated/waves/node/grpc/blockchain_api.pb.go +++ b/pkg/grpc/generated/waves/node/grpc/blockchain_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/node/grpc/blockchain_api.proto package grpc @@ -9,12 +9,12 @@ package grpc import ( context "context" proto "github.com/golang/protobuf/proto" - empty "github.com/golang/protobuf/ptypes/empty" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" ) @@ -549,7 +549,7 @@ var file_waves_node_grpc_blockchain_api_proto_goTypes = []interface{}{ (*FeatureActivationStatus)(nil), // 4: waves.node.grpc.FeatureActivationStatus (*BaseTargetResponse)(nil), // 5: waves.node.grpc.BaseTargetResponse (*ScoreResponse)(nil), // 6: waves.node.grpc.ScoreResponse - (*empty.Empty)(nil), // 7: google.protobuf.Empty + (*emptypb.Empty)(nil), // 7: google.protobuf.Empty } var file_waves_node_grpc_blockchain_api_proto_depIdxs = []int32{ 4, // 0: waves.node.grpc.ActivationStatusResponse.features:type_name -> waves.node.grpc.FeatureActivationStatus @@ -669,8 +669,8 @@ const _ = grpc.SupportPackageIsVersion6 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type BlockchainApiClient interface { GetActivationStatus(ctx context.Context, in *ActivationStatusRequest, opts ...grpc.CallOption) (*ActivationStatusResponse, error) - GetBaseTarget(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*BaseTargetResponse, error) - GetCumulativeScore(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ScoreResponse, error) + GetBaseTarget(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*BaseTargetResponse, error) + GetCumulativeScore(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ScoreResponse, error) } type blockchainApiClient struct { @@ -690,7 +690,7 @@ func (c *blockchainApiClient) GetActivationStatus(ctx context.Context, in *Activ return out, nil } -func (c *blockchainApiClient) GetBaseTarget(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*BaseTargetResponse, error) { +func (c *blockchainApiClient) GetBaseTarget(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*BaseTargetResponse, error) { out := new(BaseTargetResponse) err := c.cc.Invoke(ctx, "/waves.node.grpc.BlockchainApi/GetBaseTarget", in, out, opts...) if err != nil { @@ -699,7 +699,7 @@ func (c *blockchainApiClient) GetBaseTarget(ctx context.Context, in *empty.Empty return out, nil } -func (c *blockchainApiClient) GetCumulativeScore(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ScoreResponse, error) { +func (c *blockchainApiClient) GetCumulativeScore(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ScoreResponse, error) { out := new(ScoreResponse) err := c.cc.Invoke(ctx, "/waves.node.grpc.BlockchainApi/GetCumulativeScore", in, out, opts...) if err != nil { @@ -711,8 +711,8 @@ func (c *blockchainApiClient) GetCumulativeScore(ctx context.Context, in *empty. // BlockchainApiServer is the server API for BlockchainApi service. type BlockchainApiServer interface { GetActivationStatus(context.Context, *ActivationStatusRequest) (*ActivationStatusResponse, error) - GetBaseTarget(context.Context, *empty.Empty) (*BaseTargetResponse, error) - GetCumulativeScore(context.Context, *empty.Empty) (*ScoreResponse, error) + GetBaseTarget(context.Context, *emptypb.Empty) (*BaseTargetResponse, error) + GetCumulativeScore(context.Context, *emptypb.Empty) (*ScoreResponse, error) } // UnimplementedBlockchainApiServer can be embedded to have forward compatible implementations. @@ -722,10 +722,10 @@ type UnimplementedBlockchainApiServer struct { func (*UnimplementedBlockchainApiServer) GetActivationStatus(context.Context, *ActivationStatusRequest) (*ActivationStatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetActivationStatus not implemented") } -func (*UnimplementedBlockchainApiServer) GetBaseTarget(context.Context, *empty.Empty) (*BaseTargetResponse, error) { +func (*UnimplementedBlockchainApiServer) GetBaseTarget(context.Context, *emptypb.Empty) (*BaseTargetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetBaseTarget not implemented") } -func (*UnimplementedBlockchainApiServer) GetCumulativeScore(context.Context, *empty.Empty) (*ScoreResponse, error) { +func (*UnimplementedBlockchainApiServer) GetCumulativeScore(context.Context, *emptypb.Empty) (*ScoreResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetCumulativeScore not implemented") } @@ -752,7 +752,7 @@ func _BlockchainApi_GetActivationStatus_Handler(srv interface{}, ctx context.Con } func _BlockchainApi_GetBaseTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) + in := new(emptypb.Empty) if err := dec(in); err != nil { return nil, err } @@ -764,13 +764,13 @@ func _BlockchainApi_GetBaseTarget_Handler(srv interface{}, ctx context.Context, FullMethod: "/waves.node.grpc.BlockchainApi/GetBaseTarget", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BlockchainApiServer).GetBaseTarget(ctx, req.(*empty.Empty)) + return srv.(BlockchainApiServer).GetBaseTarget(ctx, req.(*emptypb.Empty)) } return interceptor(ctx, in, info, handler) } func _BlockchainApi_GetCumulativeScore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) + in := new(emptypb.Empty) if err := dec(in); err != nil { return nil, err } @@ -782,7 +782,7 @@ func _BlockchainApi_GetCumulativeScore_Handler(srv interface{}, ctx context.Cont FullMethod: "/waves.node.grpc.BlockchainApi/GetCumulativeScore", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BlockchainApiServer).GetCumulativeScore(ctx, req.(*empty.Empty)) + return srv.(BlockchainApiServer).GetCumulativeScore(ctx, req.(*emptypb.Empty)) } return interceptor(ctx, in, info, handler) } diff --git a/pkg/grpc/generated/waves/node/grpc/blocks_api.pb.go b/pkg/grpc/generated/waves/node/grpc/blocks_api.pb.go index 01b2dcb96..27b9107d7 100644 --- a/pkg/grpc/generated/waves/node/grpc/blocks_api.pb.go +++ b/pkg/grpc/generated/waves/node/grpc/blocks_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/node/grpc/blocks_api.proto package grpc @@ -9,14 +9,14 @@ package grpc import ( context "context" proto "github.com/golang/protobuf/proto" - empty "github.com/golang/protobuf/ptypes/empty" - wrappers "github.com/golang/protobuf/ptypes/wrappers" waves "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -359,12 +359,12 @@ func file_waves_node_grpc_blocks_api_proto_rawDescGZIP() []byte { var file_waves_node_grpc_blocks_api_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_waves_node_grpc_blocks_api_proto_goTypes = []interface{}{ - (*BlockRequest)(nil), // 0: waves.node.grpc.BlockRequest - (*BlockRangeRequest)(nil), // 1: waves.node.grpc.BlockRangeRequest - (*BlockWithHeight)(nil), // 2: waves.node.grpc.BlockWithHeight - (*waves.Block)(nil), // 3: waves.Block - (*empty.Empty)(nil), // 4: google.protobuf.Empty - (*wrappers.UInt32Value)(nil), // 5: google.protobuf.UInt32Value + (*BlockRequest)(nil), // 0: waves.node.grpc.BlockRequest + (*BlockRangeRequest)(nil), // 1: waves.node.grpc.BlockRangeRequest + (*BlockWithHeight)(nil), // 2: waves.node.grpc.BlockWithHeight + (*waves.Block)(nil), // 3: waves.Block + (*emptypb.Empty)(nil), // 4: google.protobuf.Empty + (*wrapperspb.UInt32Value)(nil), // 5: google.protobuf.UInt32Value } var file_waves_node_grpc_blocks_api_proto_depIdxs = []int32{ 3, // 0: waves.node.grpc.BlockWithHeight.block:type_name -> waves.Block @@ -466,7 +466,7 @@ const _ = grpc.SupportPackageIsVersion6 type BlocksApiClient interface { GetBlock(ctx context.Context, in *BlockRequest, opts ...grpc.CallOption) (*BlockWithHeight, error) GetBlockRange(ctx context.Context, in *BlockRangeRequest, opts ...grpc.CallOption) (BlocksApi_GetBlockRangeClient, error) - GetCurrentHeight(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*wrappers.UInt32Value, error) + GetCurrentHeight(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.UInt32Value, error) } type blocksApiClient struct { @@ -518,8 +518,8 @@ func (x *blocksApiGetBlockRangeClient) Recv() (*BlockWithHeight, error) { return m, nil } -func (c *blocksApiClient) GetCurrentHeight(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*wrappers.UInt32Value, error) { - out := new(wrappers.UInt32Value) +func (c *blocksApiClient) GetCurrentHeight(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.UInt32Value, error) { + out := new(wrapperspb.UInt32Value) err := c.cc.Invoke(ctx, "/waves.node.grpc.BlocksApi/GetCurrentHeight", in, out, opts...) if err != nil { return nil, err @@ -531,7 +531,7 @@ func (c *blocksApiClient) GetCurrentHeight(ctx context.Context, in *empty.Empty, type BlocksApiServer interface { GetBlock(context.Context, *BlockRequest) (*BlockWithHeight, error) GetBlockRange(*BlockRangeRequest, BlocksApi_GetBlockRangeServer) error - GetCurrentHeight(context.Context, *empty.Empty) (*wrappers.UInt32Value, error) + GetCurrentHeight(context.Context, *emptypb.Empty) (*wrapperspb.UInt32Value, error) } // UnimplementedBlocksApiServer can be embedded to have forward compatible implementations. @@ -544,7 +544,7 @@ func (*UnimplementedBlocksApiServer) GetBlock(context.Context, *BlockRequest) (* func (*UnimplementedBlocksApiServer) GetBlockRange(*BlockRangeRequest, BlocksApi_GetBlockRangeServer) error { return status.Errorf(codes.Unimplemented, "method GetBlockRange not implemented") } -func (*UnimplementedBlocksApiServer) GetCurrentHeight(context.Context, *empty.Empty) (*wrappers.UInt32Value, error) { +func (*UnimplementedBlocksApiServer) GetCurrentHeight(context.Context, *emptypb.Empty) (*wrapperspb.UInt32Value, error) { return nil, status.Errorf(codes.Unimplemented, "method GetCurrentHeight not implemented") } @@ -592,7 +592,7 @@ func (x *blocksApiGetBlockRangeServer) Send(m *BlockWithHeight) error { } func _BlocksApi_GetCurrentHeight_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) + in := new(emptypb.Empty) if err := dec(in); err != nil { return nil, err } @@ -604,7 +604,7 @@ func _BlocksApi_GetCurrentHeight_Handler(srv interface{}, ctx context.Context, d FullMethod: "/waves.node.grpc.BlocksApi/GetCurrentHeight", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BlocksApiServer).GetCurrentHeight(ctx, req.(*empty.Empty)) + return srv.(BlocksApiServer).GetCurrentHeight(ctx, req.(*emptypb.Empty)) } return interceptor(ctx, in, info, handler) } diff --git a/pkg/grpc/generated/waves/node/grpc/transactions_api.pb.go b/pkg/grpc/generated/waves/node/grpc/transactions_api.pb.go index 23a563fad..e0e25a829 100644 --- a/pkg/grpc/generated/waves/node/grpc/transactions_api.pb.go +++ b/pkg/grpc/generated/waves/node/grpc/transactions_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/node/grpc/transactions_api.proto package grpc @@ -204,10 +204,11 @@ type TransactionResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - Transaction *waves.SignedTransaction `protobuf:"bytes,3,opt,name=transaction,proto3" json:"transaction,omitempty"` - ApplicationStatus ApplicationStatus `protobuf:"varint,4,opt,name=application_status,json=applicationStatus,proto3,enum=waves.node.grpc.ApplicationStatus" json:"application_status,omitempty"` + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Transaction *waves.SignedTransaction `protobuf:"bytes,3,opt,name=transaction,proto3" json:"transaction,omitempty"` + ApplicationStatus ApplicationStatus `protobuf:"varint,4,opt,name=application_status,json=applicationStatus,proto3,enum=waves.node.grpc.ApplicationStatus" json:"application_status,omitempty"` + InvokeScriptResult *waves.InvokeScriptResult `protobuf:"bytes,5,opt,name=invoke_script_result,json=invokeScriptResult,proto3" json:"invoke_script_result,omitempty"` } func (x *TransactionResponse) Reset() { @@ -270,6 +271,13 @@ func (x *TransactionResponse) GetApplicationStatus() ApplicationStatus { return ApplicationStatus_UNKNOWN } +func (x *TransactionResponse) GetInvokeScriptResult() *waves.InvokeScriptResult { + if x != nil { + return x.InvokeScriptResult + } + return nil +} + type TransactionsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -573,7 +581,7 @@ var file_waves_node_grpc_transactions_api_proto_rawDesc = []byte{ 0x38, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x0a, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, - 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x13, 0x54, 0x72, + 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x22, 0x99, 0x02, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, @@ -586,87 +594,92 @@ var file_waves_node_grpc_transactions_api_proto_rawDesc = []byte{ 0x0e, 0x32, 0x22, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x13, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, - 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0c, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x73, 0x22, 0x42, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, - 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, - 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0x6f, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x34, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x22, 0x8b, 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x3a, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x06, - 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, - 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2a, - 0x4c, 0x0a, 0x11, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x32, 0x9a, 0x04, - 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x70, - 0x69, 0x12, 0x5f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x76, - 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x30, 0x01, 0x12, 0x66, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4b, 0x0a, 0x14, 0x69, 0x6e, 0x76, 0x6f, + 0x6b, 0x65, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x49, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x12, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x86, 0x01, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0x42, + 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, + 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x46, + 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, + 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, + 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x6f, 0x0a, + 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0b, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x8b, + 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, + 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x61, 0x76, 0x65, + 0x73, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2a, 0x4c, 0x0a, 0x11, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, + 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1b, 0x0a, + 0x17, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x32, 0x9f, 0x04, 0x0a, 0x0f, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x70, 0x69, 0x12, 0x5f, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, + 0x6b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x12, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, + 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x30, 0x01, 0x12, 0x5d, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x77, 0x61, + 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x5d, 0x0a, 0x0b, 0x47, 0x65, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x77, 0x61, 0x76, 0x65, - 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x24, 0x2e, + 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x0e, 0x47, 0x65, 0x74, - 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x24, 0x2e, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x3e, 0x0a, 0x04, 0x53, 0x69, 0x67, - 0x6e, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x09, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x73, 0x0a, 0x1a, 0x63, 0x6f, - 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, - 0x72, 0x6d, 0x2f, 0x67, 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, - 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x77, 0x61, - 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0xaa, 0x02, 0x0f, - 0x57, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x72, 0x70, 0x63, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x3e, 0x0a, 0x04, 0x53, + 0x69, 0x67, 0x6e, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x09, 0x42, + 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x18, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x73, 0x0a, 0x1a, + 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x67, 0x6f, 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, + 0x77, 0x61, 0x76, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0xaa, + 0x02, 0x0f, 0x57, 0x61, 0x76, 0x65, 0x73, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x72, 0x70, + 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -694,36 +707,37 @@ var file_waves_node_grpc_transactions_api_proto_goTypes = []interface{}{ (*SignRequest)(nil), // 7: waves.node.grpc.SignRequest (*InvokeScriptResultResponse)(nil), // 8: waves.node.grpc.InvokeScriptResultResponse (*waves.SignedTransaction)(nil), // 9: waves.SignedTransaction - (*waves.Recipient)(nil), // 10: waves.Recipient - (*waves.Transaction)(nil), // 11: waves.Transaction - (*waves.InvokeScriptResult)(nil), // 12: waves.InvokeScriptResult + (*waves.InvokeScriptResult)(nil), // 10: waves.InvokeScriptResult + (*waves.Recipient)(nil), // 11: waves.Recipient + (*waves.Transaction)(nil), // 12: waves.Transaction } var file_waves_node_grpc_transactions_api_proto_depIdxs = []int32{ 1, // 0: waves.node.grpc.TransactionStatus.status:type_name -> waves.node.grpc.TransactionStatus.Status 0, // 1: waves.node.grpc.TransactionStatus.application_status:type_name -> waves.node.grpc.ApplicationStatus 9, // 2: waves.node.grpc.TransactionResponse.transaction:type_name -> waves.SignedTransaction 0, // 3: waves.node.grpc.TransactionResponse.application_status:type_name -> waves.node.grpc.ApplicationStatus - 10, // 4: waves.node.grpc.TransactionsRequest.recipient:type_name -> waves.Recipient - 11, // 5: waves.node.grpc.SignRequest.transaction:type_name -> waves.Transaction - 9, // 6: waves.node.grpc.InvokeScriptResultResponse.transaction:type_name -> waves.SignedTransaction - 12, // 7: waves.node.grpc.InvokeScriptResultResponse.result:type_name -> waves.InvokeScriptResult - 4, // 8: waves.node.grpc.TransactionsApi.GetTransactions:input_type -> waves.node.grpc.TransactionsRequest - 4, // 9: waves.node.grpc.TransactionsApi.GetStateChanges:input_type -> waves.node.grpc.TransactionsRequest - 5, // 10: waves.node.grpc.TransactionsApi.GetStatuses:input_type -> waves.node.grpc.TransactionsByIdRequest - 4, // 11: waves.node.grpc.TransactionsApi.GetUnconfirmed:input_type -> waves.node.grpc.TransactionsRequest - 7, // 12: waves.node.grpc.TransactionsApi.Sign:input_type -> waves.node.grpc.SignRequest - 9, // 13: waves.node.grpc.TransactionsApi.Broadcast:input_type -> waves.SignedTransaction - 3, // 14: waves.node.grpc.TransactionsApi.GetTransactions:output_type -> waves.node.grpc.TransactionResponse - 8, // 15: waves.node.grpc.TransactionsApi.GetStateChanges:output_type -> waves.node.grpc.InvokeScriptResultResponse - 2, // 16: waves.node.grpc.TransactionsApi.GetStatuses:output_type -> waves.node.grpc.TransactionStatus - 3, // 17: waves.node.grpc.TransactionsApi.GetUnconfirmed:output_type -> waves.node.grpc.TransactionResponse - 9, // 18: waves.node.grpc.TransactionsApi.Sign:output_type -> waves.SignedTransaction - 9, // 19: waves.node.grpc.TransactionsApi.Broadcast:output_type -> waves.SignedTransaction - 14, // [14:20] is the sub-list for method output_type - 8, // [8:14] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 10, // 4: waves.node.grpc.TransactionResponse.invoke_script_result:type_name -> waves.InvokeScriptResult + 11, // 5: waves.node.grpc.TransactionsRequest.recipient:type_name -> waves.Recipient + 12, // 6: waves.node.grpc.SignRequest.transaction:type_name -> waves.Transaction + 9, // 7: waves.node.grpc.InvokeScriptResultResponse.transaction:type_name -> waves.SignedTransaction + 10, // 8: waves.node.grpc.InvokeScriptResultResponse.result:type_name -> waves.InvokeScriptResult + 4, // 9: waves.node.grpc.TransactionsApi.GetTransactions:input_type -> waves.node.grpc.TransactionsRequest + 4, // 10: waves.node.grpc.TransactionsApi.GetStateChanges:input_type -> waves.node.grpc.TransactionsRequest + 5, // 11: waves.node.grpc.TransactionsApi.GetStatuses:input_type -> waves.node.grpc.TransactionsByIdRequest + 4, // 12: waves.node.grpc.TransactionsApi.GetUnconfirmed:input_type -> waves.node.grpc.TransactionsRequest + 7, // 13: waves.node.grpc.TransactionsApi.Sign:input_type -> waves.node.grpc.SignRequest + 9, // 14: waves.node.grpc.TransactionsApi.Broadcast:input_type -> waves.SignedTransaction + 3, // 15: waves.node.grpc.TransactionsApi.GetTransactions:output_type -> waves.node.grpc.TransactionResponse + 8, // 16: waves.node.grpc.TransactionsApi.GetStateChanges:output_type -> waves.node.grpc.InvokeScriptResultResponse + 2, // 17: waves.node.grpc.TransactionsApi.GetStatuses:output_type -> waves.node.grpc.TransactionStatus + 3, // 18: waves.node.grpc.TransactionsApi.GetUnconfirmed:output_type -> waves.node.grpc.TransactionResponse + 9, // 19: waves.node.grpc.TransactionsApi.Sign:output_type -> waves.SignedTransaction + 9, // 20: waves.node.grpc.TransactionsApi.Broadcast:output_type -> waves.SignedTransaction + 15, // [15:21] is the sub-list for method output_type + 9, // [9:15] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_waves_node_grpc_transactions_api_proto_init() } @@ -851,6 +865,7 @@ const _ = grpc.SupportPackageIsVersion6 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type TransactionsApiClient interface { GetTransactions(ctx context.Context, in *TransactionsRequest, opts ...grpc.CallOption) (TransactionsApi_GetTransactionsClient, error) + // Deprecated: Do not use. GetStateChanges(ctx context.Context, in *TransactionsRequest, opts ...grpc.CallOption) (TransactionsApi_GetStateChangesClient, error) GetStatuses(ctx context.Context, in *TransactionsByIdRequest, opts ...grpc.CallOption) (TransactionsApi_GetStatusesClient, error) GetUnconfirmed(ctx context.Context, in *TransactionsRequest, opts ...grpc.CallOption) (TransactionsApi_GetUnconfirmedClient, error) @@ -898,6 +913,7 @@ func (x *transactionsApiGetTransactionsClient) Recv() (*TransactionResponse, err return m, nil } +// Deprecated: Do not use. func (c *transactionsApiClient) GetStateChanges(ctx context.Context, in *TransactionsRequest, opts ...grpc.CallOption) (TransactionsApi_GetStateChangesClient, error) { stream, err := c.cc.NewStream(ctx, &_TransactionsApi_serviceDesc.Streams[1], "/waves.node.grpc.TransactionsApi/GetStateChanges", opts...) if err != nil { @@ -1015,6 +1031,7 @@ func (c *transactionsApiClient) Broadcast(ctx context.Context, in *waves.SignedT // TransactionsApiServer is the server API for TransactionsApi service. type TransactionsApiServer interface { GetTransactions(*TransactionsRequest, TransactionsApi_GetTransactionsServer) error + // Deprecated: Do not use. GetStateChanges(*TransactionsRequest, TransactionsApi_GetStateChangesServer) error GetStatuses(*TransactionsByIdRequest, TransactionsApi_GetStatusesServer) error GetUnconfirmed(*TransactionsRequest, TransactionsApi_GetUnconfirmedServer) error diff --git a/pkg/grpc/generated/waves/order.pb.go b/pkg/grpc/generated/waves/order.pb.go index 77b7f0c1b..97994da69 100644 --- a/pkg/grpc/generated/waves/order.pb.go +++ b/pkg/grpc/generated/waves/order.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/order.proto package waves diff --git a/pkg/grpc/generated/waves/recipient.pb.go b/pkg/grpc/generated/waves/recipient.pb.go index 80ef09fa1..48a88d88a 100644 --- a/pkg/grpc/generated/waves/recipient.pb.go +++ b/pkg/grpc/generated/waves/recipient.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/recipient.proto package waves diff --git a/pkg/grpc/generated/waves/transaction.pb.go b/pkg/grpc/generated/waves/transaction.pb.go index 88d5e2702..8ba418298 100644 --- a/pkg/grpc/generated/waves/transaction.pb.go +++ b/pkg/grpc/generated/waves/transaction.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc v3.14.0 // source: waves/transaction.proto package waves diff --git a/pkg/grpc/protobuf-schemas b/pkg/grpc/protobuf-schemas index c37e88a02..359f1d9c8 160000 --- a/pkg/grpc/protobuf-schemas +++ b/pkg/grpc/protobuf-schemas @@ -1 +1 @@ -Subproject commit c37e88a0272f31c832be082da3bcf0f6c363067a +Subproject commit 359f1d9c802e7fd4898d1732f67ce950c466940e diff --git a/pkg/grpc/server/accounts_api.go b/pkg/grpc/server/accounts_api.go index dd1dcf356..85162d623 100644 --- a/pkg/grpc/server/accounts_api.go +++ b/pkg/grpc/server/accounts_api.go @@ -166,11 +166,50 @@ type getActiveLeasesHandler struct { s *Server } -func (h *getActiveLeasesHandler) handle(tx proto.Transaction, failed bool) error { - res, err := h.s.transactionToTransactionResponse(tx, true, failed) +func (h *getActiveLeasesHandler) handle(tx proto.Transaction, _ bool) error { + var id []byte + var sender proto.Address + var recipient proto.Recipient + var amount int64 + var err error + switch ltx := tx.(type) { + case *proto.LeaseWithSig: + id = ltx.ID.Bytes() + sender, err = proto.NewAddressFromPublicKey(h.s.scheme, ltx.SenderPK) + if err != nil { + return err + } + recipient = ltx.Recipient + amount = int64(ltx.Amount) + case *proto.LeaseWithProofs: + id = ltx.ID.Bytes() + sender, err = proto.NewAddressFromPublicKey(h.s.scheme, ltx.SenderPK) + if err != nil { + return err + } + recipient = ltx.Recipient + amount = int64(ltx.Amount) + default: + return nil + } + + height, err := h.s.state.TransactionHeightByID(id) + if err != nil { + return errors.Wrap(err, "failed to get tx height by ID") + } + rcp, err := recipient.ToProtobuf() if err != nil { - return errors.Wrap(err, "failed to form transaction response") + return err } + res := &g.LeaseResponse{ + LeaseId: id, + OriginTransactionId: id, + Sender: sender.Body(), + Recipient: rcp, + Amount: amount, + Height: int64(height), + } + err = h.srv.Send(res) if err != nil { return errors.Wrap(err, "failed to send") diff --git a/pkg/grpc/server/accounts_api_test.go b/pkg/grpc/server/accounts_api_test.go index a17f34553..8315e1819 100644 --- a/pkg/grpc/server/accounts_api_test.go +++ b/pkg/grpc/server/accounts_api_test.go @@ -96,9 +96,20 @@ func TestGetActiveLeases(t *testing.T) { require.NoError(t, err) tx, err := st.TransactionByID(txId.Bytes()) require.NoError(t, err) - correctRes, err := server.transactionToTransactionResponse(tx, true, false) - require.NoError(t, err) - assertTransactionResponsesEqual(t, correctRes, res) + + ltx, ok := tx.(*proto.LeaseWithSig) + require.True(t, ok) + assert.Equal(t, ltx.ID.Bytes(), res.LeaseId) + assert.Equal(t, ltx.ID.Bytes(), res.OriginTransactionId) + assert.Equal(t, int(ltx.Amount), int(res.Amount)) + expRecipient, err := ltx.Recipient.ToProtobuf() + require.NoError(t, err) + assert.Equal(t, expRecipient, res.Recipient) + expSender := proto.MustAddressFromPublicKey(sets.AddressSchemeCharacter, ltx.SenderPK) + assert.Equal(t, expSender.Body(), res.Sender) + expHeight, err := st.TransactionHeightByID(txId.Bytes()) + require.NoError(t, err) + assert.Equal(t, int(expHeight), int(res.Height)) _, err = stream.Recv() assert.Equal(t, io.EOF, err) } diff --git a/pkg/grpc/server/server_common.go b/pkg/grpc/server/server_common.go index 4dc5dd2eb..29760f240 100644 --- a/pkg/grpc/server/server_common.go +++ b/pkg/grpc/server/server_common.go @@ -5,6 +5,7 @@ import ( g "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves/node/grpc" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/state" + "go.uber.org/zap" ) func (s *Server) transactionToTransactionResponse(tx proto.Transaction, confirmed, failed bool) (*g.TransactionResponse, error) { @@ -47,7 +48,12 @@ type filterFunc = func(tx proto.Transaction) bool type handleFunc = func(tx proto.Transaction, failed bool) error func (s *Server) iterateAndHandleTransactions(iter state.TransactionIterator, filter filterFunc, handle handleFunc) error { - defer iter.Release() + defer func() { + iter.Release() + if err := iter.Error(); err != nil { + zap.S().Fatalf("Iterator error: %v", err) + } + }() for iter.Next() { // Get and send transactions one-by-one. tx, failed, err := iter.Transaction() diff --git a/pkg/keyvalue/leveldb_test.go b/pkg/keyvalue/leveldb_test.go index 7f54baf94..4bcab79d5 100644 --- a/pkg/keyvalue/leveldb_test.go +++ b/pkg/keyvalue/leveldb_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -17,7 +18,7 @@ const ( func TestKeyVal(t *testing.T) { dbDir, err := ioutil.TempDir(os.TempDir(), "dbDir0") - assert.NoError(t, err) + require.NoError(t, err) params := KeyValParams{ CacheParams: CacheParams{cacheSize}, BloomFilterParams: BloomFilterParams{n, falsePositiveProbability, NoOpStore{}, false}, diff --git a/pkg/miner/constraints.go b/pkg/miner/constraints.go index 7ad54e94c..2e55f1197 100644 --- a/pkg/miner/constraints.go +++ b/pkg/miner/constraints.go @@ -1,8 +1,12 @@ package miner +import ( + "github.com/wavesplatform/gowaves/pkg/state" +) + type Constraints struct { MaxScriptRunsInBlock int - MaxScriptsComplexityInBlock int + MaxScriptsComplexityInBlock state.MaxScriptsComplexityInBlock ClassicAmountOfTxsInBlock int MaxTxsSizeInBytes int } @@ -10,7 +14,7 @@ type Constraints struct { func DefaultConstraints() Constraints { return Constraints{ MaxScriptRunsInBlock: 100, - MaxScriptsComplexityInBlock: 1000000, + MaxScriptsComplexityInBlock: state.NewMaxScriptsComplexityInBlock(), ClassicAmountOfTxsInBlock: 100, MaxTxsSizeInBytes: 1 * 1024 * 1024, // 1mb } diff --git a/pkg/miner/miner.go b/pkg/miner/miner.go index bf8d9687a..a99de4913 100644 --- a/pkg/miner/miner.go +++ b/pkg/miner/miner.go @@ -2,7 +2,7 @@ package miner import ( "context" - + "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/miner/scheduler" "github.com/wavesplatform/gowaves/pkg/node/messages" "github.com/wavesplatform/gowaves/pkg/node/peer_manager" @@ -15,13 +15,12 @@ import ( ) type MicroblockMiner struct { - utx types.UtxPool - state state.State - peer peer_manager.PeerManager - constraints Constraints - services services.Services - features Features - // reward vote 600000000 + utx types.UtxPool + state state.State + peer peer_manager.PeerManager + constraints Constraints + services services.Services + features Features reward int64 maxTransactionTimeForwardOffset proto.Timestamp } @@ -71,12 +70,19 @@ func (a *MicroblockMiner) MineKeyBlock(ctx context.Context, t proto.Timestamp, k return nil, proto.MiningLimits{}, err } b := bi.(*proto.Block) + + activated, err := a.state.IsActivated(int16(settings.RideV5)) + if err != nil { + return nil, proto.MiningLimits{}, errors.Wrapf(err, "failed to check if feature %d is activated", settings.RideV5) + } + rest := proto.MiningLimits{ MaxScriptRunsInBlock: a.constraints.MaxScriptRunsInBlock, - MaxScriptsComplexityInBlock: a.constraints.MaxScriptsComplexityInBlock, + MaxScriptsComplexityInBlock: a.constraints.MaxScriptsComplexityInBlock.GetMaxScriptsComplexityInBlock(activated), ClassicAmountOfTxsInBlock: a.constraints.ClassicAmountOfTxsInBlock, MaxTxsSizeInBytes: a.constraints.MaxTxsSizeInBytes - 4, } + return b, rest, nil } diff --git a/pkg/miner/utxpool/pool.go b/pkg/miner/utxpool/pool.go index 6b687db78..ae0287e44 100644 --- a/pkg/miner/utxpool/pool.go +++ b/pkg/miner/utxpool/pool.go @@ -87,11 +87,11 @@ func (a *UtxImpl) AddBytes(bts []byte) error { return a.addWithBytes(t, bts) } -// TODO: add flag here to distinguish adding using API and accepting -// through the network from other nodes. -// When API is used, we should check all scripts completely. -// When adding from the network, only free complexity limit is checked. func (a *UtxImpl) AddWithBytes(t proto.Transaction, b []byte) error { + // TODO: add flag here to distinguish adding using API and accepting + // through the network from other nodes. + // When API is used, we should check all scripts completely. + // When adding from the network, only free complexity limit is checked. a.mu.Lock() defer a.mu.Unlock() return a.addWithBytes(t, b) @@ -136,7 +136,7 @@ func (a *UtxImpl) Count() int { return len(a.transactions) } -func makeDigest(b []byte, e error) crypto.Digest { +func makeDigest(b []byte, _ error) crypto.Digest { d := crypto.Digest{} copy(d[:], b) return d diff --git a/pkg/mock/grpc.go b/pkg/mock/grpc.go index a6b002add..90bcbd523 100644 --- a/pkg/mock/grpc.go +++ b/pkg/mock/grpc.go @@ -7,10 +7,10 @@ package mock import ( context "context" gomock "github.com/golang/mock/gomock" - empty "github.com/golang/protobuf/ptypes/empty" - wrappers "github.com/golang/protobuf/ptypes/wrappers" waves "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" grpc "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves/node/grpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" ) @@ -95,10 +95,10 @@ func (mr *MockGrpcHandlersMockRecorder) GetDataEntries(arg0, arg1 interface{}) * } // ResolveAlias mocks base method -func (m *MockGrpcHandlers) ResolveAlias(arg0 context.Context, arg1 *wrappers.StringValue) (*wrappers.BytesValue, error) { +func (m *MockGrpcHandlers) ResolveAlias(arg0 context.Context, arg1 *wrapperspb.StringValue) (*wrapperspb.BytesValue, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ResolveAlias", arg0, arg1) - ret0, _ := ret[0].(*wrappers.BytesValue) + ret0, _ := ret[0].(*wrapperspb.BytesValue) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -154,7 +154,7 @@ func (mr *MockGrpcHandlersMockRecorder) GetActivationStatus(arg0, arg1 interface } // GetBaseTarget mocks base method -func (m *MockGrpcHandlers) GetBaseTarget(arg0 context.Context, arg1 *empty.Empty) (*grpc.BaseTargetResponse, error) { +func (m *MockGrpcHandlers) GetBaseTarget(arg0 context.Context, arg1 *emptypb.Empty) (*grpc.BaseTargetResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBaseTarget", arg0, arg1) ret0, _ := ret[0].(*grpc.BaseTargetResponse) @@ -169,7 +169,7 @@ func (mr *MockGrpcHandlersMockRecorder) GetBaseTarget(arg0, arg1 interface{}) *g } // GetCumulativeScore mocks base method -func (m *MockGrpcHandlers) GetCumulativeScore(arg0 context.Context, arg1 *empty.Empty) (*grpc.ScoreResponse, error) { +func (m *MockGrpcHandlers) GetCumulativeScore(arg0 context.Context, arg1 *emptypb.Empty) (*grpc.ScoreResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetCumulativeScore", arg0, arg1) ret0, _ := ret[0].(*grpc.ScoreResponse) @@ -213,10 +213,10 @@ func (mr *MockGrpcHandlersMockRecorder) GetBlockRange(arg0, arg1 interface{}) *g } // GetCurrentHeight mocks base method -func (m *MockGrpcHandlers) GetCurrentHeight(arg0 context.Context, arg1 *empty.Empty) (*wrappers.UInt32Value, error) { +func (m *MockGrpcHandlers) GetCurrentHeight(arg0 context.Context, arg1 *emptypb.Empty) (*wrapperspb.UInt32Value, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetCurrentHeight", arg0, arg1) - ret0, _ := ret[0].(*wrappers.UInt32Value) + ret0, _ := ret[0].(*wrapperspb.UInt32Value) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/pkg/mock/peer_manager.go b/pkg/mock/peer_manager.go index 60a069743..a2ba7dcb0 100644 --- a/pkg/mock/peer_manager.go +++ b/pkg/mock/peer_manager.go @@ -6,67 +6,106 @@ package mock import ( context "context" - gomock "github.com/golang/mock/gomock" - peer "github.com/wavesplatform/gowaves/pkg/p2p/peer" - proto "github.com/wavesplatform/gowaves/pkg/proto" big "math/big" net "net" reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + storage "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + peer "github.com/wavesplatform/gowaves/pkg/p2p/peer" + proto "github.com/wavesplatform/gowaves/pkg/proto" ) -// MockPeerManager is a mock of PeerManager interface +// MockPeerManager is a mock of PeerManager interface. type MockPeerManager struct { ctrl *gomock.Controller recorder *MockPeerManagerMockRecorder } -// MockPeerManagerMockRecorder is the mock recorder for MockPeerManager +// MockPeerManagerMockRecorder is the mock recorder for MockPeerManager. type MockPeerManagerMockRecorder struct { mock *MockPeerManager } -// NewMockPeerManager creates a new mock instance +// NewMockPeerManager creates a new mock instance. func NewMockPeerManager(ctrl *gomock.Controller) *MockPeerManager { mock := &MockPeerManager{ctrl: ctrl} mock.recorder = &MockPeerManagerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPeerManager) EXPECT() *MockPeerManagerMockRecorder { return m.recorder } -// Connected mocks base method -func (m *MockPeerManager) Connected(arg0 peer.Peer) (peer.Peer, bool) { +// AddConnected mocks base method. +func (m *MockPeerManager) AddConnected(arg0 peer.Peer) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connected", arg0) - ret0, _ := ret[0].(peer.Peer) - ret1, _ := ret[1].(bool) - return ret0, ret1 + m.ctrl.Call(m, "AddConnected", arg0) } -// Connected indicates an expected call of Connected -func (mr *MockPeerManagerMockRecorder) Connected(arg0 interface{}) *gomock.Call { +// AddConnected indicates an expected call of AddConnected. +func (mr *MockPeerManagerMockRecorder) AddConnected(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockPeerManager)(nil).Connected), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddConnected", reflect.TypeOf((*MockPeerManager)(nil).AddConnected), arg0) } -// NewConnection mocks base method -func (m *MockPeerManager) NewConnection(arg0 peer.Peer) error { +// AskPeers mocks base method. +func (m *MockPeerManager) AskPeers() { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewConnection", arg0) + m.ctrl.Call(m, "AskPeers") +} + +// AskPeers indicates an expected call of AskPeers. +func (mr *MockPeerManagerMockRecorder) AskPeers() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskPeers", reflect.TypeOf((*MockPeerManager)(nil).AskPeers)) +} + +// Close mocks base method. +func (m *MockPeerManager) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockPeerManagerMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeerManager)(nil).Close)) +} + +// Connect mocks base method. +func (m *MockPeerManager) Connect(arg0 context.Context, arg1 proto.TCPAddr) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Connect", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// NewConnection indicates an expected call of NewConnection -func (mr *MockPeerManagerMockRecorder) NewConnection(arg0 interface{}) *gomock.Call { +// Connect indicates an expected call of Connect. +func (mr *MockPeerManagerMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewConnection", reflect.TypeOf((*MockPeerManager)(nil).NewConnection), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockPeerManager)(nil).Connect), arg0, arg1) } -// ConnectedCount mocks base method +// Connected mocks base method. +func (m *MockPeerManager) Connected(arg0 peer.Peer) (peer.Peer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Connected", arg0) + ret0, _ := ret[0].(peer.Peer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// Connected indicates an expected call of Connected. +func (mr *MockPeerManagerMockRecorder) Connected(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockPeerManager)(nil).Connected), arg0) +} + +// ConnectedCount mocks base method. func (m *MockPeerManager) ConnectedCount() int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ConnectedCount") @@ -74,92 +113,94 @@ func (m *MockPeerManager) ConnectedCount() int { return ret0 } -// ConnectedCount indicates an expected call of ConnectedCount +// ConnectedCount indicates an expected call of ConnectedCount. func (mr *MockPeerManagerMockRecorder) ConnectedCount() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnectedCount", reflect.TypeOf((*MockPeerManager)(nil).ConnectedCount)) } -// InOutCount mocks base method -func (m *MockPeerManager) InOutCount() (int, int) { +// Disconnect mocks base method. +func (m *MockPeerManager) Disconnect(arg0 peer.Peer) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InOutCount") - ret0, _ := ret[0].(int) - ret1, _ := ret[1].(int) - return ret0, ret1 + m.ctrl.Call(m, "Disconnect", arg0) } -// InOutCount indicates an expected call of InOutCount -func (mr *MockPeerManagerMockRecorder) InOutCount() *gomock.Call { +// Disconnect indicates an expected call of Disconnect. +func (mr *MockPeerManagerMockRecorder) Disconnect(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InOutCount", reflect.TypeOf((*MockPeerManager)(nil).InOutCount)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnect", reflect.TypeOf((*MockPeerManager)(nil).Disconnect), arg0) } -// EachConnected mocks base method +// EachConnected mocks base method. func (m *MockPeerManager) EachConnected(arg0 func(peer.Peer, *proto.Score)) { m.ctrl.T.Helper() m.ctrl.Call(m, "EachConnected", arg0) } -// EachConnected indicates an expected call of EachConnected +// EachConnected indicates an expected call of EachConnected. func (mr *MockPeerManagerMockRecorder) EachConnected(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EachConnected", reflect.TypeOf((*MockPeerManager)(nil).EachConnected), arg0) } -// IsSuspended mocks base method -func (m *MockPeerManager) IsSuspended(arg0 peer.Peer) bool { +// InOutCount mocks base method. +func (m *MockPeerManager) InOutCount() (int, int) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsSuspended", arg0) - ret0, _ := ret[0].(bool) - return ret0 + ret := m.ctrl.Call(m, "InOutCount") + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(int) + return ret0, ret1 } -// IsSuspended indicates an expected call of IsSuspended -func (mr *MockPeerManagerMockRecorder) IsSuspended(arg0 interface{}) *gomock.Call { +// InOutCount indicates an expected call of InOutCount. +func (mr *MockPeerManagerMockRecorder) InOutCount() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSuspended", reflect.TypeOf((*MockPeerManager)(nil).IsSuspended), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InOutCount", reflect.TypeOf((*MockPeerManager)(nil).InOutCount)) } -// Suspend mocks base method -func (m *MockPeerManager) Suspend(arg0 peer.Peer, arg1 string) { +// IsSuspended mocks base method. +func (m *MockPeerManager) IsSuspended(arg0 peer.Peer) bool { m.ctrl.T.Helper() - m.ctrl.Call(m, "Suspend", arg0, arg1) + ret := m.ctrl.Call(m, "IsSuspended", arg0) + ret0, _ := ret[0].(bool) + return ret0 } -// Suspend indicates an expected call of Suspend -func (mr *MockPeerManagerMockRecorder) Suspend(arg0, arg1 interface{}) *gomock.Call { +// IsSuspended indicates an expected call of IsSuspended. +func (mr *MockPeerManagerMockRecorder) IsSuspended(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspend", reflect.TypeOf((*MockPeerManager)(nil).Suspend), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSuspended", reflect.TypeOf((*MockPeerManager)(nil).IsSuspended), arg0) } -// Suspended mocks base method -func (m *MockPeerManager) Suspended() []string { +// KnownPeers mocks base method. +func (m *MockPeerManager) KnownPeers() []storage.KnownPeer { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Suspended") - ret0, _ := ret[0].([]string) + ret := m.ctrl.Call(m, "KnownPeers") + ret0, _ := ret[0].([]storage.KnownPeer) return ret0 } -// Suspended indicates an expected call of Suspended -func (mr *MockPeerManagerMockRecorder) Suspended() *gomock.Call { +// KnownPeers indicates an expected call of KnownPeers. +func (mr *MockPeerManagerMockRecorder) KnownPeers() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspended", reflect.TypeOf((*MockPeerManager)(nil).Suspended)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownPeers", reflect.TypeOf((*MockPeerManager)(nil).KnownPeers)) } -// AddConnected mocks base method -func (m *MockPeerManager) AddConnected(arg0 peer.Peer) { +// NewConnection mocks base method. +func (m *MockPeerManager) NewConnection(arg0 peer.Peer) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "AddConnected", arg0) + ret := m.ctrl.Call(m, "NewConnection", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// AddConnected indicates an expected call of AddConnected -func (mr *MockPeerManagerMockRecorder) AddConnected(arg0 interface{}) *gomock.Call { +// NewConnection indicates an expected call of NewConnection. +func (mr *MockPeerManagerMockRecorder) NewConnection(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddConnected", reflect.TypeOf((*MockPeerManager)(nil).AddConnected), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewConnection", reflect.TypeOf((*MockPeerManager)(nil).NewConnection), arg0) } -// PeerWithHighestScore mocks base method +// PeerWithHighestScore mocks base method. func (m *MockPeerManager) PeerWithHighestScore() (peer.Peer, *big.Int, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PeerWithHighestScore") @@ -169,94 +210,54 @@ func (m *MockPeerManager) PeerWithHighestScore() (peer.Peer, *big.Int, bool) { return ret0, ret1, ret2 } -// PeerWithHighestScore indicates an expected call of PeerWithHighestScore +// PeerWithHighestScore indicates an expected call of PeerWithHighestScore. func (mr *MockPeerManagerMockRecorder) PeerWithHighestScore() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerWithHighestScore", reflect.TypeOf((*MockPeerManager)(nil).PeerWithHighestScore)) } -// UpdateScore mocks base method -func (m *MockPeerManager) UpdateScore(p peer.Peer, score *proto.Score) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateScore", p, score) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateScore indicates an expected call of UpdateScore -func (mr *MockPeerManagerMockRecorder) UpdateScore(p, score interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScore", reflect.TypeOf((*MockPeerManager)(nil).UpdateScore), p, score) -} - -// UpdateKnownPeers mocks base method -func (m *MockPeerManager) UpdateKnownPeers(arg0 []proto.TCPAddr) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateKnownPeers", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateKnownPeers indicates an expected call of UpdateKnownPeers -func (mr *MockPeerManagerMockRecorder) UpdateKnownPeers(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateKnownPeers", reflect.TypeOf((*MockPeerManager)(nil).UpdateKnownPeers), arg0) -} - -// KnownPeers mocks base method -func (m *MockPeerManager) KnownPeers() ([]proto.TCPAddr, error) { +// Score mocks base method. +func (m *MockPeerManager) Score(p peer.Peer) (*proto.Score, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "KnownPeers") - ret0, _ := ret[0].([]proto.TCPAddr) + ret := m.ctrl.Call(m, "Score", p) + ret0, _ := ret[0].(*proto.Score) ret1, _ := ret[1].(error) return ret0, ret1 } -// KnownPeers indicates an expected call of KnownPeers -func (mr *MockPeerManagerMockRecorder) KnownPeers() *gomock.Call { +// Score indicates an expected call of Score. +func (mr *MockPeerManagerMockRecorder) Score(p interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownPeers", reflect.TypeOf((*MockPeerManager)(nil).KnownPeers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Score", reflect.TypeOf((*MockPeerManager)(nil).Score), p) } -// Close mocks base method -func (m *MockPeerManager) Close() { +// SpawnIncomingConnection mocks base method. +func (m *MockPeerManager) SpawnIncomingConnection(ctx context.Context, conn net.Conn) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "Close") + ret := m.ctrl.Call(m, "SpawnIncomingConnection", ctx, conn) + ret0, _ := ret[0].(error) + return ret0 } -// Close indicates an expected call of Close -func (mr *MockPeerManagerMockRecorder) Close() *gomock.Call { +// SpawnIncomingConnection indicates an expected call of SpawnIncomingConnection. +func (mr *MockPeerManagerMockRecorder) SpawnIncomingConnection(ctx, conn interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeerManager)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnIncomingConnection", reflect.TypeOf((*MockPeerManager)(nil).SpawnIncomingConnection), ctx, conn) } -// SpawnOutgoingConnections mocks base method +// SpawnOutgoingConnections mocks base method. func (m *MockPeerManager) SpawnOutgoingConnections(arg0 context.Context) { m.ctrl.T.Helper() m.ctrl.Call(m, "SpawnOutgoingConnections", arg0) } -// SpawnOutgoingConnections indicates an expected call of SpawnOutgoingConnections +// SpawnOutgoingConnections indicates an expected call of SpawnOutgoingConnections. func (mr *MockPeerManagerMockRecorder) SpawnOutgoingConnections(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnOutgoingConnections", reflect.TypeOf((*MockPeerManager)(nil).SpawnOutgoingConnections), arg0) } -// SpawnIncomingConnection mocks base method -func (m *MockPeerManager) SpawnIncomingConnection(ctx context.Context, conn net.Conn) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnIncomingConnection", ctx, conn) - ret0, _ := ret[0].(error) - return ret0 -} - -// SpawnIncomingConnection indicates an expected call of SpawnIncomingConnection -func (mr *MockPeerManagerMockRecorder) SpawnIncomingConnection(ctx, conn interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnIncomingConnection", reflect.TypeOf((*MockPeerManager)(nil).SpawnIncomingConnection), ctx, conn) -} - -// Spawned mocks base method +// Spawned mocks base method. func (m *MockPeerManager) Spawned() []proto.IpPort { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Spawned") @@ -264,61 +265,62 @@ func (m *MockPeerManager) Spawned() []proto.IpPort { return ret0 } -// Spawned indicates an expected call of Spawned +// Spawned indicates an expected call of Spawned. func (mr *MockPeerManagerMockRecorder) Spawned() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Spawned", reflect.TypeOf((*MockPeerManager)(nil).Spawned)) } -// Connect mocks base method -func (m *MockPeerManager) Connect(arg0 context.Context, arg1 proto.TCPAddr) error { +// Suspend mocks base method. +func (m *MockPeerManager) Suspend(peer peer.Peer, suspendTime time.Time, reason string) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connect", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "Suspend", peer, suspendTime, reason) } -// Connect indicates an expected call of Connect -func (mr *MockPeerManagerMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call { +// Suspend indicates an expected call of Suspend. +func (mr *MockPeerManagerMockRecorder) Suspend(peer, suspendTime, reason interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockPeerManager)(nil).Connect), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspend", reflect.TypeOf((*MockPeerManager)(nil).Suspend), peer, suspendTime, reason) } -// Score mocks base method -func (m *MockPeerManager) Score(p peer.Peer) (*proto.Score, error) { +// Suspended mocks base method. +func (m *MockPeerManager) Suspended() []storage.SuspendedPeer { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Score", p) - ret0, _ := ret[0].(*proto.Score) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "Suspended") + ret0, _ := ret[0].([]storage.SuspendedPeer) + return ret0 } -// Score indicates an expected call of Score -func (mr *MockPeerManagerMockRecorder) Score(p interface{}) *gomock.Call { +// Suspended indicates an expected call of Suspended. +func (mr *MockPeerManagerMockRecorder) Suspended() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Score", reflect.TypeOf((*MockPeerManager)(nil).Score), p) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspended", reflect.TypeOf((*MockPeerManager)(nil).Suspended)) } -// AskPeers mocks base method -func (m *MockPeerManager) AskPeers() { +// UpdateKnownPeers mocks base method. +func (m *MockPeerManager) UpdateKnownPeers(arg0 []storage.KnownPeer) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "AskPeers") + ret := m.ctrl.Call(m, "UpdateKnownPeers", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// AskPeers indicates an expected call of AskPeers -func (mr *MockPeerManagerMockRecorder) AskPeers() *gomock.Call { +// UpdateKnownPeers indicates an expected call of UpdateKnownPeers. +func (mr *MockPeerManagerMockRecorder) UpdateKnownPeers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskPeers", reflect.TypeOf((*MockPeerManager)(nil).AskPeers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateKnownPeers", reflect.TypeOf((*MockPeerManager)(nil).UpdateKnownPeers), arg0) } -// Disconnect mocks base method -func (m *MockPeerManager) Disconnect(arg0 peer.Peer) { +// UpdateScore mocks base method. +func (m *MockPeerManager) UpdateScore(p peer.Peer, score *proto.Score) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "Disconnect", arg0) + ret := m.ctrl.Call(m, "UpdateScore", p, score) + ret0, _ := ret[0].(error) + return ret0 } -// Disconnect indicates an expected call of Disconnect -func (mr *MockPeerManagerMockRecorder) Disconnect(arg0 interface{}) *gomock.Call { +// UpdateScore indicates an expected call of UpdateScore. +func (mr *MockPeerManagerMockRecorder) UpdateScore(p, score interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnect", reflect.TypeOf((*MockPeerManager)(nil).Disconnect), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScore", reflect.TypeOf((*MockPeerManager)(nil).UpdateScore), p, score) } diff --git a/pkg/mock/peer_storage.go b/pkg/mock/peer_storage.go new file mode 100644 index 000000000..b4ce4cb10 --- /dev/null +++ b/pkg/mock/peer_storage.go @@ -0,0 +1,204 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/node/peer_manager/peer_storage.go + +// Package mock is a generated GoMock package. +package mock + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + storage "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" +) + +// MockPeerStorage is a mock of PeerStorage interface. +type MockPeerStorage struct { + ctrl *gomock.Controller + recorder *MockPeerStorageMockRecorder +} + +// MockPeerStorageMockRecorder is the mock recorder for MockPeerStorage. +type MockPeerStorageMockRecorder struct { + mock *MockPeerStorage +} + +// NewMockPeerStorage creates a new mock instance. +func NewMockPeerStorage(ctrl *gomock.Controller) *MockPeerStorage { + mock := &MockPeerStorage{ctrl: ctrl} + mock.recorder = &MockPeerStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPeerStorage) EXPECT() *MockPeerStorageMockRecorder { + return m.recorder +} + +// AddKnown mocks base method. +func (m *MockPeerStorage) AddKnown(known []storage.KnownPeer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddKnown", known) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddKnown indicates an expected call of AddKnown. +func (mr *MockPeerStorageMockRecorder) AddKnown(known interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddKnown", reflect.TypeOf((*MockPeerStorage)(nil).AddKnown), known) +} + +// AddSuspended mocks base method. +func (m *MockPeerStorage) AddSuspended(suspended []storage.SuspendedPeer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSuspended", suspended) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddSuspended indicates an expected call of AddSuspended. +func (mr *MockPeerStorageMockRecorder) AddSuspended(suspended interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSuspended", reflect.TypeOf((*MockPeerStorage)(nil).AddSuspended), suspended) +} + +// DeleteKnown mocks base method. +func (m *MockPeerStorage) DeleteKnown(known []storage.KnownPeer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteKnown", known) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteKnown indicates an expected call of DeleteKnown. +func (mr *MockPeerStorageMockRecorder) DeleteKnown(known interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteKnown", reflect.TypeOf((*MockPeerStorage)(nil).DeleteKnown), known) +} + +// DeleteSuspendedByIP mocks base method. +func (m *MockPeerStorage) DeleteSuspendedByIP(suspended []storage.SuspendedPeer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSuspendedByIP", suspended) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSuspendedByIP indicates an expected call of DeleteSuspendedByIP. +func (mr *MockPeerStorageMockRecorder) DeleteSuspendedByIP(suspended interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSuspendedByIP", reflect.TypeOf((*MockPeerStorage)(nil).DeleteSuspendedByIP), suspended) +} + +// DropKnown mocks base method. +func (m *MockPeerStorage) DropKnown() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DropKnown") + ret0, _ := ret[0].(error) + return ret0 +} + +// DropKnown indicates an expected call of DropKnown. +func (mr *MockPeerStorageMockRecorder) DropKnown() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DropKnown", reflect.TypeOf((*MockPeerStorage)(nil).DropKnown)) +} + +// DropStorage mocks base method. +func (m *MockPeerStorage) DropStorage() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DropStorage") + ret0, _ := ret[0].(error) + return ret0 +} + +// DropStorage indicates an expected call of DropStorage. +func (mr *MockPeerStorageMockRecorder) DropStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DropStorage", reflect.TypeOf((*MockPeerStorage)(nil).DropStorage)) +} + +// DropSuspended mocks base method. +func (m *MockPeerStorage) DropSuspended() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DropSuspended") + ret0, _ := ret[0].(error) + return ret0 +} + +// DropSuspended indicates an expected call of DropSuspended. +func (mr *MockPeerStorageMockRecorder) DropSuspended() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DropSuspended", reflect.TypeOf((*MockPeerStorage)(nil).DropSuspended)) +} + +// IsSuspendedIP mocks base method. +func (m *MockPeerStorage) IsSuspendedIP(ip storage.IP, now time.Time) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsSuspendedIP", ip, now) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsSuspendedIP indicates an expected call of IsSuspendedIP. +func (mr *MockPeerStorageMockRecorder) IsSuspendedIP(ip, now interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSuspendedIP", reflect.TypeOf((*MockPeerStorage)(nil).IsSuspendedIP), ip, now) +} + +// IsSuspendedIPs mocks base method. +func (m *MockPeerStorage) IsSuspendedIPs(ips []storage.IP, now time.Time) []bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsSuspendedIPs", ips, now) + ret0, _ := ret[0].([]bool) + return ret0 +} + +// IsSuspendedIPs indicates an expected call of IsSuspendedIPs. +func (mr *MockPeerStorageMockRecorder) IsSuspendedIPs(ips, now interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSuspendedIPs", reflect.TypeOf((*MockPeerStorage)(nil).IsSuspendedIPs), ips, now) +} + +// Known mocks base method. +func (m *MockPeerStorage) Known() []storage.KnownPeer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Known") + ret0, _ := ret[0].([]storage.KnownPeer) + return ret0 +} + +// Known indicates an expected call of Known. +func (mr *MockPeerStorageMockRecorder) Known() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Known", reflect.TypeOf((*MockPeerStorage)(nil).Known)) +} + +// RefreshSuspended mocks base method. +func (m *MockPeerStorage) RefreshSuspended(now time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RefreshSuspended", now) + ret0, _ := ret[0].(error) + return ret0 +} + +// RefreshSuspended indicates an expected call of RefreshSuspended. +func (mr *MockPeerStorageMockRecorder) RefreshSuspended(now interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshSuspended", reflect.TypeOf((*MockPeerStorage)(nil).RefreshSuspended), now) +} + +// Suspended mocks base method. +func (m *MockPeerStorage) Suspended(now time.Time) []storage.SuspendedPeer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Suspended", now) + ret0, _ := ret[0].([]storage.SuspendedPeer) + return ret0 +} + +// Suspended indicates an expected call of Suspended. +func (mr *MockPeerStorageMockRecorder) Suspended(now interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspended", reflect.TypeOf((*MockPeerStorage)(nil).Suspended), now) +} diff --git a/pkg/mock/state.go b/pkg/mock/state.go index d377cedcf..3c367d936 100644 --- a/pkg/mock/state.go +++ b/pkg/mock/state.go @@ -5,55 +5,54 @@ package mock import ( + big "math/big" + reflect "reflect" + gomock "github.com/golang/mock/gomock" crypto "github.com/wavesplatform/gowaves/pkg/crypto" proto "github.com/wavesplatform/gowaves/pkg/proto" settings "github.com/wavesplatform/gowaves/pkg/settings" state "github.com/wavesplatform/gowaves/pkg/state" - big "math/big" - reflect "reflect" ) -// MockTransactionIterator is a mock of TransactionIterator interface +// MockTransactionIterator is a mock of TransactionIterator interface. type MockTransactionIterator struct { ctrl *gomock.Controller recorder *MockTransactionIteratorMockRecorder } -// MockTransactionIteratorMockRecorder is the mock recorder for MockTransactionIterator +// MockTransactionIteratorMockRecorder is the mock recorder for MockTransactionIterator. type MockTransactionIteratorMockRecorder struct { mock *MockTransactionIterator } -// NewMockTransactionIterator creates a new mock instance +// NewMockTransactionIterator creates a new mock instance. func NewMockTransactionIterator(ctrl *gomock.Controller) *MockTransactionIterator { mock := &MockTransactionIterator{ctrl: ctrl} mock.recorder = &MockTransactionIteratorMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockTransactionIterator) EXPECT() *MockTransactionIteratorMockRecorder { return m.recorder } -// Transaction mocks base method -func (m *MockTransactionIterator) Transaction() (proto.Transaction, bool, error) { +// Error mocks base method. +func (m *MockTransactionIterator) Error() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Transaction") - ret0, _ := ret[0].(proto.Transaction) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 } -// Transaction indicates an expected call of Transaction -func (mr *MockTransactionIteratorMockRecorder) Transaction() *gomock.Call { +// Error indicates an expected call of Error. +func (mr *MockTransactionIteratorMockRecorder) Error() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockTransactionIterator)(nil).Transaction)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockTransactionIterator)(nil).Error)) } -// Next mocks base method +// Next mocks base method. func (m *MockTransactionIterator) Next() bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Next") @@ -61,151 +60,199 @@ func (m *MockTransactionIterator) Next() bool { return ret0 } -// Next indicates an expected call of Next +// Next indicates an expected call of Next. func (mr *MockTransactionIteratorMockRecorder) Next() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockTransactionIterator)(nil).Next)) } -// Release mocks base method +// Release mocks base method. func (m *MockTransactionIterator) Release() { m.ctrl.T.Helper() m.ctrl.Call(m, "Release") } -// Release indicates an expected call of Release +// Release indicates an expected call of Release. func (mr *MockTransactionIteratorMockRecorder) Release() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Release", reflect.TypeOf((*MockTransactionIterator)(nil).Release)) } -// Error mocks base method -func (m *MockTransactionIterator) Error() error { +// Transaction mocks base method. +func (m *MockTransactionIterator) Transaction() (proto.Transaction, bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Error") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "Transaction") + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// Error indicates an expected call of Error -func (mr *MockTransactionIteratorMockRecorder) Error() *gomock.Call { +// Transaction indicates an expected call of Transaction. +func (mr *MockTransactionIteratorMockRecorder) Transaction() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockTransactionIterator)(nil).Error)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockTransactionIterator)(nil).Transaction)) } -// MockStateInfo is a mock of StateInfo interface +// MockStateInfo is a mock of StateInfo interface. type MockStateInfo struct { ctrl *gomock.Controller recorder *MockStateInfoMockRecorder } -// MockStateInfoMockRecorder is the mock recorder for MockStateInfo +// MockStateInfoMockRecorder is the mock recorder for MockStateInfo. type MockStateInfoMockRecorder struct { mock *MockStateInfo } -// NewMockStateInfo creates a new mock instance +// NewMockStateInfo creates a new mock instance. func NewMockStateInfo(ctrl *gomock.Controller) *MockStateInfo { mock := &MockStateInfo{ctrl: ctrl} mock.recorder = &MockStateInfoMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockStateInfo) EXPECT() *MockStateInfoMockRecorder { return m.recorder } -// TopBlock mocks base method -func (m *MockStateInfo) TopBlock() *proto.Block { +// AccountBalance mocks base method. +func (m *MockStateInfo) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TopBlock") - ret0, _ := ret[0].(*proto.Block) - return ret0 + ret := m.ctrl.Call(m, "AccountBalance", account, asset) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TopBlock indicates an expected call of TopBlock -func (mr *MockStateInfoMockRecorder) TopBlock() *gomock.Call { +// AccountBalance indicates an expected call of AccountBalance. +func (mr *MockStateInfoMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockStateInfo)(nil).TopBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockStateInfo)(nil).AccountBalance), account, asset) } -// Block mocks base method -func (m *MockStateInfo) Block(blockID proto.BlockID) (*proto.Block, error) { +// ActivationHeight mocks base method. +func (m *MockStateInfo) ActivationHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Block", blockID) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ActivationHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Block indicates an expected call of Block -func (mr *MockStateInfoMockRecorder) Block(blockID interface{}) *gomock.Call { +// ActivationHeight indicates an expected call of ActivationHeight. +func (mr *MockStateInfoMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockStateInfo)(nil).Block), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockStateInfo)(nil).ActivationHeight), featureID) } -// BlockByHeight mocks base method -func (m *MockStateInfo) BlockByHeight(height proto.Height) (*proto.Block, error) { +// AddrByAlias mocks base method. +func (m *MockStateInfo) AddrByAlias(alias proto.Alias) (proto.Address, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHeight", height) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "AddrByAlias", alias) + ret0, _ := ret[0].(proto.Address) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockByHeight indicates an expected call of BlockByHeight -func (mr *MockStateInfoMockRecorder) BlockByHeight(height interface{}) *gomock.Call { +// AddrByAlias indicates an expected call of AddrByAlias. +func (mr *MockStateInfoMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockStateInfo)(nil).AddrByAlias), alias) } -// Header mocks base method -func (m *MockStateInfo) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { +// AllFeatures mocks base method. +func (m *MockStateInfo) AllFeatures() ([]int16, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Header", blockID) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "AllFeatures") + ret0, _ := ret[0].([]int16) ret1, _ := ret[1].(error) return ret0, ret1 } -// Header indicates an expected call of Header -func (mr *MockStateInfoMockRecorder) Header(blockID interface{}) *gomock.Call { +// AllFeatures indicates an expected call of AllFeatures. +func (mr *MockStateInfoMockRecorder) AllFeatures() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockStateInfo)(nil).Header), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockStateInfo)(nil).AllFeatures)) } -// HeaderByHeight mocks base method -func (m *MockStateInfo) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { +// ApprovalHeight mocks base method. +func (m *MockStateInfo) ApprovalHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHeight", height) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "ApprovalHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// HeaderByHeight indicates an expected call of HeaderByHeight -func (mr *MockStateInfoMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { +// ApprovalHeight indicates an expected call of ApprovalHeight. +func (mr *MockStateInfoMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockStateInfo)(nil).HeaderByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockStateInfo)(nil).ApprovalHeight), featureID) } -// Height mocks base method -func (m *MockStateInfo) Height() (proto.Height, error) { +// AssetInfo mocks base method. +func (m *MockStateInfo) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Height") - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "AssetInfo", assetID) + ret0, _ := ret[0].(*proto.AssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// Height indicates an expected call of Height -func (mr *MockStateInfoMockRecorder) Height() *gomock.Call { +// AssetInfo indicates an expected call of AssetInfo. +func (mr *MockStateInfoMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockStateInfo)(nil).Height)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockStateInfo)(nil).AssetInfo), assetID) +} + +// AssetIsSponsored mocks base method. +func (m *MockStateInfo) AssetIsSponsored(assetID crypto.Digest) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssetIsSponsored indicates an expected call of AssetIsSponsored. +func (mr *MockStateInfoMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockStateInfo)(nil).AssetIsSponsored), assetID) +} + +// Block mocks base method. +func (m *MockStateInfo) Block(blockID proto.BlockID) (*proto.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Block", blockID) + ret0, _ := ret[0].(*proto.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Block indicates an expected call of Block. +func (mr *MockStateInfoMockRecorder) Block(blockID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockStateInfo)(nil).Block), blockID) +} + +// BlockByHeight mocks base method. +func (m *MockStateInfo) BlockByHeight(height proto.Height) (*proto.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockByHeight", height) + ret0, _ := ret[0].(*proto.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BlockByHeight indicates an expected call of BlockByHeight. +func (mr *MockStateInfoMockRecorder) BlockByHeight(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockByHeight), height) } -// BlockIDToHeight mocks base method +// BlockIDToHeight mocks base method. func (m *MockStateInfo) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) @@ -214,43 +261,43 @@ func (m *MockStateInfo) BlockIDToHeight(blockID proto.BlockID) (proto.Height, er return ret0, ret1 } -// BlockIDToHeight indicates an expected call of BlockIDToHeight +// BlockIDToHeight indicates an expected call of BlockIDToHeight. func (mr *MockStateInfoMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockIDToHeight), blockID) } -// HeightToBlockID mocks base method -func (m *MockStateInfo) HeightToBlockID(height proto.Height) (proto.BlockID, error) { +// BlockchainSettings mocks base method. +func (m *MockStateInfo) BlockchainSettings() (*settings.BlockchainSettings, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeightToBlockID", height) - ret0, _ := ret[0].(proto.BlockID) + ret := m.ctrl.Call(m, "BlockchainSettings") + ret0, _ := ret[0].(*settings.BlockchainSettings) ret1, _ := ret[1].(error) return ret0, ret1 } -// HeightToBlockID indicates an expected call of HeightToBlockID -func (mr *MockStateInfoMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { +// BlockchainSettings indicates an expected call of BlockchainSettings. +func (mr *MockStateInfoMockRecorder) BlockchainSettings() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockStateInfo)(nil).HeightToBlockID), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockStateInfo)(nil).BlockchainSettings)) } -// FullWavesBalance mocks base method -func (m *MockStateInfo) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { +// CurrentScore mocks base method. +func (m *MockStateInfo) CurrentScore() (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullWavesBalance", account) - ret0, _ := ret[0].(*proto.FullWavesBalance) + ret := m.ctrl.Call(m, "CurrentScore") + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullWavesBalance indicates an expected call of FullWavesBalance -func (mr *MockStateInfoMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { +// CurrentScore indicates an expected call of CurrentScore. +func (mr *MockStateInfoMockRecorder) CurrentScore() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockStateInfo)(nil).FullWavesBalance), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockStateInfo)(nil).CurrentScore)) } -// EffectiveBalance mocks base method +// EffectiveBalance mocks base method. func (m *MockStateInfo) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) @@ -259,133 +306,148 @@ func (m *MockStateInfo) EffectiveBalance(account proto.Recipient, startHeight, e return ret0, ret1 } -// EffectiveBalance indicates an expected call of EffectiveBalance +// EffectiveBalance indicates an expected call of EffectiveBalance. func (mr *MockStateInfoMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockStateInfo)(nil).EffectiveBalance), account, startHeight, endHeight) } -// AccountBalance mocks base method -func (m *MockStateInfo) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { +// EstimatorVersion mocks base method. +func (m *MockStateInfo) EstimatorVersion() (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccountBalance", account, asset) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "EstimatorVersion") + ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// AccountBalance indicates an expected call of AccountBalance -func (mr *MockStateInfoMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { +// EstimatorVersion indicates an expected call of EstimatorVersion. +func (mr *MockStateInfoMockRecorder) EstimatorVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockStateInfo)(nil).AccountBalance), account, asset) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockStateInfo)(nil).EstimatorVersion)) } -// WavesAddressesNumber mocks base method -func (m *MockStateInfo) WavesAddressesNumber() (uint64, error) { +// FullAssetInfo mocks base method. +func (m *MockStateInfo) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WavesAddressesNumber") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "FullAssetInfo", assetID) + ret0, _ := ret[0].(*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// WavesAddressesNumber indicates an expected call of WavesAddressesNumber -func (mr *MockStateInfoMockRecorder) WavesAddressesNumber() *gomock.Call { +// FullAssetInfo indicates an expected call of FullAssetInfo. +func (mr *MockStateInfoMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockStateInfo)(nil).WavesAddressesNumber)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockStateInfo)(nil).FullAssetInfo), assetID) } -// ScoreAtHeight mocks base method -func (m *MockStateInfo) ScoreAtHeight(height proto.Height) (*big.Int, error) { +// FullWavesBalance mocks base method. +func (m *MockStateInfo) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScoreAtHeight", height) - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "FullWavesBalance", account) + ret0, _ := ret[0].(*proto.FullWavesBalance) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScoreAtHeight indicates an expected call of ScoreAtHeight -func (mr *MockStateInfoMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { +// FullWavesBalance indicates an expected call of FullWavesBalance. +func (mr *MockStateInfoMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockStateInfo)(nil).ScoreAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockStateInfo)(nil).FullWavesBalance), account) } -// CurrentScore mocks base method -func (m *MockStateInfo) CurrentScore() (*big.Int, error) { +// Header mocks base method. +func (m *MockStateInfo) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CurrentScore") - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "Header", blockID) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// CurrentScore indicates an expected call of CurrentScore -func (mr *MockStateInfoMockRecorder) CurrentScore() *gomock.Call { +// Header indicates an expected call of Header. +func (mr *MockStateInfoMockRecorder) Header(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockStateInfo)(nil).CurrentScore)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockStateInfo)(nil).Header), blockID) } -// BlockchainSettings mocks base method -func (m *MockStateInfo) BlockchainSettings() (*settings.BlockchainSettings, error) { +// HeaderByHeight mocks base method. +func (m *MockStateInfo) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockchainSettings") - ret0, _ := ret[0].(*settings.BlockchainSettings) + ret := m.ctrl.Call(m, "HeaderByHeight", height) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockchainSettings indicates an expected call of BlockchainSettings -func (mr *MockStateInfoMockRecorder) BlockchainSettings() *gomock.Call { +// HeaderByHeight indicates an expected call of HeaderByHeight. +func (mr *MockStateInfoMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockStateInfo)(nil).BlockchainSettings)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockStateInfo)(nil).HeaderByHeight), height) } -// Peers mocks base method -func (m *MockStateInfo) Peers() ([]proto.TCPAddr, error) { +// Height mocks base method. +func (m *MockStateInfo) Height() (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Peers") - ret0, _ := ret[0].([]proto.TCPAddr) + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Peers indicates an expected call of Peers -func (mr *MockStateInfoMockRecorder) Peers() *gomock.Call { +// Height indicates an expected call of Height. +func (mr *MockStateInfoMockRecorder) Height() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockStateInfo)(nil).Peers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockStateInfo)(nil).Height)) } -// VotesNum mocks base method -func (m *MockStateInfo) VotesNum(featureID int16) (uint64, error) { +// HeightToBlockID mocks base method. +func (m *MockStateInfo) HeightToBlockID(height proto.Height) (proto.BlockID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNum", featureID) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "HeightToBlockID", height) + ret0, _ := ret[0].(proto.BlockID) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNum indicates an expected call of VotesNum -func (mr *MockStateInfoMockRecorder) VotesNum(featureID interface{}) *gomock.Call { +// HeightToBlockID indicates an expected call of HeightToBlockID. +func (mr *MockStateInfoMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockStateInfo)(nil).VotesNum), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockStateInfo)(nil).HeightToBlockID), height) } -// VotesNumAtHeight mocks base method -func (m *MockStateInfo) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { +// HitSourceAtHeight mocks base method. +func (m *MockStateInfo) HitSourceAtHeight(height proto.Height) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "HitSourceAtHeight", height) + ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNumAtHeight indicates an expected call of VotesNumAtHeight -func (mr *MockStateInfoMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { +// HitSourceAtHeight indicates an expected call of HitSourceAtHeight. +func (mr *MockStateInfoMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockStateInfo)(nil).VotesNumAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockStateInfo)(nil).HitSourceAtHeight), height) +} + +// InvokeResultByID mocks base method. +func (m *MockStateInfo) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) + ret0, _ := ret[0].(*proto.ScriptResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InvokeResultByID indicates an expected call of InvokeResultByID. +func (mr *MockStateInfoMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockStateInfo)(nil).InvokeResultByID), invokeID) } -// IsActivated mocks base method +// IsActivated mocks base method. func (m *MockStateInfo) IsActivated(featureID int16) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsActivated", featureID) @@ -394,13 +456,13 @@ func (m *MockStateInfo) IsActivated(featureID int16) (bool, error) { return ret0, ret1 } -// IsActivated indicates an expected call of IsActivated +// IsActivated indicates an expected call of IsActivated. func (mr *MockStateInfoMockRecorder) IsActivated(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockStateInfo)(nil).IsActivated), featureID) } -// IsActiveAtHeight mocks base method +// IsActiveAtHeight mocks base method. func (m *MockStateInfo) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) @@ -409,28 +471,28 @@ func (m *MockStateInfo) IsActiveAtHeight(featureID int16, height proto.Height) ( return ret0, ret1 } -// IsActiveAtHeight indicates an expected call of IsActiveAtHeight +// IsActiveAtHeight indicates an expected call of IsActiveAtHeight. func (mr *MockStateInfoMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockStateInfo)(nil).IsActiveAtHeight), featureID, height) } -// ActivationHeight mocks base method -func (m *MockStateInfo) ActivationHeight(featureID int16) (proto.Height, error) { +// IsActiveLeasing mocks base method. +func (m *MockStateInfo) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ActivationHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// ActivationHeight indicates an expected call of ActivationHeight -func (mr *MockStateInfoMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { +// IsActiveLeasing indicates an expected call of IsActiveLeasing. +func (mr *MockStateInfoMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockStateInfo)(nil).ActivationHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockStateInfo)(nil).IsActiveLeasing), leaseID) } -// IsApproved mocks base method +// IsApproved mocks base method. func (m *MockStateInfo) IsApproved(featureID int16) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsApproved", featureID) @@ -439,13 +501,13 @@ func (m *MockStateInfo) IsApproved(featureID int16) (bool, error) { return ret0, ret1 } -// IsApproved indicates an expected call of IsApproved +// IsApproved indicates an expected call of IsApproved. func (mr *MockStateInfoMockRecorder) IsApproved(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockStateInfo)(nil).IsApproved), featureID) } -// IsApprovedAtHeight mocks base method +// IsApprovedAtHeight mocks base method. func (m *MockStateInfo) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) @@ -454,73 +516,118 @@ func (m *MockStateInfo) IsApprovedAtHeight(featureID int16, height proto.Height) return ret0, ret1 } -// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight +// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight. func (mr *MockStateInfoMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockStateInfo)(nil).IsApprovedAtHeight), featureID, height) } -// ApprovalHeight mocks base method -func (m *MockStateInfo) ApprovalHeight(featureID int16) (proto.Height, error) { +// MapR mocks base method. +func (m *MockStateInfo) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ApprovalHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "MapR", arg0) + ret0, _ := ret[0].(interface{}) ret1, _ := ret[1].(error) return ret0, ret1 } -// ApprovalHeight indicates an expected call of ApprovalHeight -func (mr *MockStateInfoMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { +// MapR indicates an expected call of MapR. +func (mr *MockStateInfoMockRecorder) MapR(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockStateInfo)(nil).ApprovalHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockStateInfo)(nil).MapR), arg0) } -// AllFeatures mocks base method -func (m *MockStateInfo) AllFeatures() ([]int16, error) { +// NFTList mocks base method. +func (m *MockStateInfo) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllFeatures") - ret0, _ := ret[0].([]int16) + ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) + ret0, _ := ret[0].([]*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// AllFeatures indicates an expected call of AllFeatures -func (mr *MockStateInfoMockRecorder) AllFeatures() *gomock.Call { +// NFTList indicates an expected call of NFTList. +func (mr *MockStateInfoMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockStateInfo)(nil).AllFeatures)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockStateInfo)(nil).NFTList), account, limit, afterAssetID) } -// EstimatorVersion mocks base method -func (m *MockStateInfo) EstimatorVersion() (int, error) { +// NewAddrTransactionsIterator mocks base method. +func (m *MockStateInfo) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatorVersion") - ret0, _ := ret[0].(int) + ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) + ret0, _ := ret[0].(state.TransactionIterator) ret1, _ := ret[1].(error) return ret0, ret1 } -// EstimatorVersion indicates an expected call of EstimatorVersion -func (mr *MockStateInfoMockRecorder) EstimatorVersion() *gomock.Call { +// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator. +func (mr *MockStateInfoMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockStateInfo)(nil).EstimatorVersion)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockStateInfo)(nil).NewAddrTransactionsIterator), addr) } -// AddrByAlias mocks base method -func (m *MockStateInfo) AddrByAlias(alias proto.Alias) (proto.Address, error) { +// ProvidesExtendedApi mocks base method. +func (m *MockStateInfo) ProvidesExtendedApi() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddrByAlias", alias) - ret0, _ := ret[0].(proto.Address) + ret := m.ctrl.Call(m, "ProvidesExtendedApi") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddrByAlias indicates an expected call of AddrByAlias -func (mr *MockStateInfoMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { +// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi. +func (mr *MockStateInfoMockRecorder) ProvidesExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockStateInfo)(nil).AddrByAlias), alias) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockStateInfo)(nil).ProvidesExtendedApi)) +} + +// ProvidesStateHashes mocks base method. +func (m *MockStateInfo) ProvidesStateHashes() (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ProvidesStateHashes") + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ProvidesStateHashes indicates an expected call of ProvidesStateHashes. +func (mr *MockStateInfoMockRecorder) ProvidesStateHashes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockStateInfo)(nil).ProvidesStateHashes)) +} + +// RetrieveBinaryEntry mocks base method. +func (m *MockStateInfo) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) + ret0, _ := ret[0].(*proto.BinaryDataEntry) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry. +func (mr *MockStateInfoMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBinaryEntry), account, key) +} + +// RetrieveBooleanEntry mocks base method. +func (m *MockStateInfo) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) + ret0, _ := ret[0].(*proto.BooleanDataEntry) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry. +func (mr *MockStateInfoMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBooleanEntry), account, key) } -// RetrieveEntries mocks base method +// RetrieveEntries mocks base method. func (m *MockStateInfo) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RetrieveEntries", account) @@ -529,13 +636,13 @@ func (m *MockStateInfo) RetrieveEntries(account proto.Recipient) ([]proto.DataEn return ret0, ret1 } -// RetrieveEntries indicates an expected call of RetrieveEntries +// RetrieveEntries indicates an expected call of RetrieveEntries. func (mr *MockStateInfoMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntries), account) } -// RetrieveEntry mocks base method +// RetrieveEntry mocks base method. func (m *MockStateInfo) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RetrieveEntry", account, key) @@ -544,13 +651,13 @@ func (m *MockStateInfo) RetrieveEntry(account proto.Recipient, key string) (prot return ret0, ret1 } -// RetrieveEntry indicates an expected call of RetrieveEntry +// RetrieveEntry indicates an expected call of RetrieveEntry. func (mr *MockStateInfoMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntry), account, key) } -// RetrieveIntegerEntry mocks base method +// RetrieveIntegerEntry mocks base method. func (m *MockStateInfo) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) @@ -559,58 +666,117 @@ func (m *MockStateInfo) RetrieveIntegerEntry(account proto.Recipient, key string return ret0, ret1 } -// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry +// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry. func (mr *MockStateInfoMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveIntegerEntry), account, key) } -// RetrieveBooleanEntry mocks base method -func (m *MockStateInfo) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { +// RetrieveStringEntry mocks base method. +func (m *MockStateInfo) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) - ret0, _ := ret[0].(*proto.BooleanDataEntry) + ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) + ret0, _ := ret[0].(*proto.StringDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry -func (mr *MockStateInfoMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { +// RetrieveStringEntry indicates an expected call of RetrieveStringEntry. +func (mr *MockStateInfoMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBooleanEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveStringEntry), account, key) } -// RetrieveStringEntry mocks base method -func (m *MockStateInfo) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { +// ScoreAtHeight mocks base method. +func (m *MockStateInfo) ScoreAtHeight(height proto.Height) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) - ret0, _ := ret[0].(*proto.StringDataEntry) + ret := m.ctrl.Call(m, "ScoreAtHeight", height) + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveStringEntry indicates an expected call of RetrieveStringEntry -func (mr *MockStateInfoMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { +// ScoreAtHeight indicates an expected call of ScoreAtHeight. +func (mr *MockStateInfoMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveStringEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockStateInfo)(nil).ScoreAtHeight), height) } -// RetrieveBinaryEntry mocks base method -func (m *MockStateInfo) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { +// ScriptInfoByAccount mocks base method. +func (m *MockStateInfo) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) - ret0, _ := ret[0].(*proto.BinaryDataEntry) + ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry -func (mr *MockStateInfoMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { +// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount. +func (mr *MockStateInfoMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBinaryEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAccount), account) +} + +// ScriptInfoByAsset mocks base method. +func (m *MockStateInfo) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) + ret0, _ := ret[0].(*proto.ScriptInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset. +func (mr *MockStateInfoMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAsset), assetID) +} + +// ShouldPersistAddressTransactions mocks base method. +func (m *MockStateInfo) ShouldPersistAddressTransactions() (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions. +func (mr *MockStateInfoMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockStateInfo)(nil).ShouldPersistAddressTransactions)) +} + +// StateHashAtHeight mocks base method. +func (m *MockStateInfo) StateHashAtHeight(height uint64) (*proto.StateHash, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateHashAtHeight", height) + ret0, _ := ret[0].(*proto.StateHash) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StateHashAtHeight indicates an expected call of StateHashAtHeight. +func (mr *MockStateInfoMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockStateInfo)(nil).StateHashAtHeight), height) +} + +// TopBlock mocks base method. +func (m *MockStateInfo) TopBlock() *proto.Block { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TopBlock") + ret0, _ := ret[0].(*proto.Block) + return ret0 } -// TransactionByID mocks base method +// TopBlock indicates an expected call of TopBlock. +func (mr *MockStateInfoMockRecorder) TopBlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockStateInfo)(nil).TopBlock)) +} + +// TransactionByID mocks base method. func (m *MockStateInfo) TransactionByID(id []byte) (proto.Transaction, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TransactionByID", id) @@ -619,13 +785,13 @@ func (m *MockStateInfo) TransactionByID(id []byte) (proto.Transaction, error) { return ret0, ret1 } -// TransactionByID indicates an expected call of TransactionByID +// TransactionByID indicates an expected call of TransactionByID. func (mr *MockStateInfoMockRecorder) TransactionByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionByID), id) } -// TransactionByIDWithStatus mocks base method +// TransactionByIDWithStatus mocks base method. func (m *MockStateInfo) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) @@ -635,13 +801,13 @@ func (m *MockStateInfo) TransactionByIDWithStatus(id []byte) (proto.Transaction, return ret0, ret1, ret2 } -// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus +// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus. func (mr *MockStateInfoMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockStateInfo)(nil).TransactionByIDWithStatus), id) } -// TransactionHeightByID mocks base method +// TransactionHeightByID mocks base method. func (m *MockStateInfo) TransactionHeightByID(id []byte) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TransactionHeightByID", id) @@ -650,320 +816,140 @@ func (m *MockStateInfo) TransactionHeightByID(id []byte) (uint64, error) { return ret0, ret1 } -// TransactionHeightByID indicates an expected call of TransactionHeightByID +// TransactionHeightByID indicates an expected call of TransactionHeightByID. func (mr *MockStateInfoMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionHeightByID), id) } -// NewAddrTransactionsIterator mocks base method -func (m *MockStateInfo) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { +// VotesNum mocks base method. +func (m *MockStateInfo) VotesNum(featureID int16) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) - ret0, _ := ret[0].(state.TransactionIterator) + ret := m.ctrl.Call(m, "VotesNum", featureID) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator -func (mr *MockStateInfoMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { +// VotesNum indicates an expected call of VotesNum. +func (mr *MockStateInfoMockRecorder) VotesNum(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockStateInfo)(nil).NewAddrTransactionsIterator), addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockStateInfo)(nil).VotesNum), featureID) } -// AssetIsSponsored mocks base method -func (m *MockStateInfo) AssetIsSponsored(assetID crypto.Digest) (bool, error) { +// VotesNumAtHeight mocks base method. +func (m *MockStateInfo) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetIsSponsored indicates an expected call of AssetIsSponsored -func (mr *MockStateInfoMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { +// VotesNumAtHeight indicates an expected call of VotesNumAtHeight. +func (mr *MockStateInfoMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockStateInfo)(nil).AssetIsSponsored), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockStateInfo)(nil).VotesNumAtHeight), featureID, height) } -// AssetInfo mocks base method -func (m *MockStateInfo) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { +// WavesAddressesNumber mocks base method. +func (m *MockStateInfo) WavesAddressesNumber() (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetInfo", assetID) - ret0, _ := ret[0].(*proto.AssetInfo) + ret := m.ctrl.Call(m, "WavesAddressesNumber") + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetInfo indicates an expected call of AssetInfo -func (mr *MockStateInfoMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { +// WavesAddressesNumber indicates an expected call of WavesAddressesNumber. +func (mr *MockStateInfoMockRecorder) WavesAddressesNumber() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockStateInfo)(nil).AssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockStateInfo)(nil).WavesAddressesNumber)) } -// FullAssetInfo mocks base method -func (m *MockStateInfo) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullAssetInfo", assetID) - ret0, _ := ret[0].(*proto.FullAssetInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 +// MockStateModifier is a mock of StateModifier interface. +type MockStateModifier struct { + ctrl *gomock.Controller + recorder *MockStateModifierMockRecorder } -// FullAssetInfo indicates an expected call of FullAssetInfo -func (mr *MockStateInfoMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockStateInfo)(nil).FullAssetInfo), assetID) +// MockStateModifierMockRecorder is the mock recorder for MockStateModifier. +type MockStateModifierMockRecorder struct { + mock *MockStateModifier } -// NFTList mocks base method -func (m *MockStateInfo) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) - ret0, _ := ret[0].([]*proto.FullAssetInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 +// NewMockStateModifier creates a new mock instance. +func NewMockStateModifier(ctrl *gomock.Controller) *MockStateModifier { + mock := &MockStateModifier{ctrl: ctrl} + mock.recorder = &MockStateModifierMockRecorder{mock} + return mock } -// NFTList indicates an expected call of NFTList -func (mr *MockStateInfoMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockStateInfo)(nil).NFTList), account, limit, afterAssetID) +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStateModifier) EXPECT() *MockStateModifierMockRecorder { + return m.recorder } -// ScriptInfoByAccount mocks base method -func (m *MockStateInfo) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { +// AddBlock mocks base method. +func (m *MockStateModifier) AddBlock(block []byte) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "AddBlock", block) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount -func (mr *MockStateInfoMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { +// AddBlock indicates an expected call of AddBlock. +func (mr *MockStateModifierMockRecorder) AddBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAccount), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockStateModifier)(nil).AddBlock), block) } -// ScriptInfoByAsset mocks base method -func (m *MockStateInfo) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { +// AddDeserializedBlock mocks base method. +func (m *MockStateModifier) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "AddDeserializedBlock", block) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset -func (mr *MockStateInfoMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { +// AddDeserializedBlock indicates an expected call of AddDeserializedBlock. +func (mr *MockStateModifierMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAsset), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockStateModifier)(nil).AddDeserializedBlock), block) } -// IsActiveLeasing mocks base method -func (m *MockStateInfo) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { +// AddNewBlocks mocks base method. +func (m *MockStateModifier) AddNewBlocks(blocks [][]byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddNewBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 } -// IsActiveLeasing indicates an expected call of IsActiveLeasing -func (mr *MockStateInfoMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { +// AddNewBlocks indicates an expected call of AddNewBlocks. +func (mr *MockStateModifierMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockStateInfo)(nil).IsActiveLeasing), leaseID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddNewBlocks), blocks) } -// InvokeResultByID mocks base method -func (m *MockStateInfo) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { +// AddNewDeserializedBlocks mocks base method. +func (m *MockStateModifier) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) - ret0, _ := ret[0].(*proto.ScriptResult) + ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// InvokeResultByID indicates an expected call of InvokeResultByID -func (mr *MockStateInfoMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockStateInfo)(nil).InvokeResultByID), invokeID) -} - -// ProvidesExtendedApi mocks base method -func (m *MockStateInfo) ProvidesExtendedApi() (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesExtendedApi") - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi -func (mr *MockStateInfoMockRecorder) ProvidesExtendedApi() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockStateInfo)(nil).ProvidesExtendedApi)) -} - -// ProvidesStateHashes mocks base method -func (m *MockStateInfo) ProvidesStateHashes() (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesStateHashes") - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ProvidesStateHashes indicates an expected call of ProvidesStateHashes -func (mr *MockStateInfoMockRecorder) ProvidesStateHashes() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockStateInfo)(nil).ProvidesStateHashes)) -} - -// StateHashAtHeight mocks base method -func (m *MockStateInfo) StateHashAtHeight(height uint64) (*proto.StateHash, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateHashAtHeight", height) - ret0, _ := ret[0].(*proto.StateHash) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// StateHashAtHeight indicates an expected call of StateHashAtHeight -func (mr *MockStateInfoMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockStateInfo)(nil).StateHashAtHeight), height) -} - -// MapR mocks base method -func (m *MockStateInfo) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MapR", arg0) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// MapR indicates an expected call of MapR -func (mr *MockStateInfoMockRecorder) MapR(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockStateInfo)(nil).MapR), arg0) -} - -// HitSourceAtHeight mocks base method -func (m *MockStateInfo) HitSourceAtHeight(height proto.Height) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HitSourceAtHeight", height) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HitSourceAtHeight indicates an expected call of HitSourceAtHeight -func (mr *MockStateInfoMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockStateInfo)(nil).HitSourceAtHeight), height) -} - -// ShouldPersistAddressTransactions mocks base method -func (m *MockStateInfo) ShouldPersistAddressTransactions() (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions -func (mr *MockStateInfoMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockStateInfo)(nil).ShouldPersistAddressTransactions)) -} - -// MockStateModifier is a mock of StateModifier interface -type MockStateModifier struct { - ctrl *gomock.Controller - recorder *MockStateModifierMockRecorder -} - -// MockStateModifierMockRecorder is the mock recorder for MockStateModifier -type MockStateModifierMockRecorder struct { - mock *MockStateModifier -} - -// NewMockStateModifier creates a new mock instance -func NewMockStateModifier(ctrl *gomock.Controller) *MockStateModifier { - mock := &MockStateModifier{ctrl: ctrl} - mock.recorder = &MockStateModifierMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use -func (m *MockStateModifier) EXPECT() *MockStateModifierMockRecorder { - return m.recorder -} - -// AddBlock mocks base method -func (m *MockStateModifier) AddBlock(block []byte) (*proto.Block, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddBlock", block) - ret0, _ := ret[0].(*proto.Block) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddBlock indicates an expected call of AddBlock -func (mr *MockStateModifierMockRecorder) AddBlock(block interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockStateModifier)(nil).AddBlock), block) -} - -// AddDeserializedBlock mocks base method -func (m *MockStateModifier) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddDeserializedBlock", block) - ret0, _ := ret[0].(*proto.Block) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddDeserializedBlock indicates an expected call of AddDeserializedBlock -func (mr *MockStateModifierMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockStateModifier)(nil).AddDeserializedBlock), block) -} - -// AddNewBlocks mocks base method -func (m *MockStateModifier) AddNewBlocks(blocks [][]byte) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewBlocks", blocks) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddNewBlocks indicates an expected call of AddNewBlocks -func (mr *MockStateModifierMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddNewBlocks), blocks) -} - -// AddNewDeserializedBlocks mocks base method -func (m *MockStateModifier) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) - ret0, _ := ret[0].(*proto.Block) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks +// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks. func (mr *MockStateModifierMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddNewDeserializedBlocks), blocks) } -// AddOldBlocks mocks base method +// AddOldBlocks mocks base method. func (m *MockStateModifier) AddOldBlocks(blocks [][]byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddOldBlocks", blocks) @@ -971,13 +957,13 @@ func (m *MockStateModifier) AddOldBlocks(blocks [][]byte) error { return ret0 } -// AddOldBlocks indicates an expected call of AddOldBlocks +// AddOldBlocks indicates an expected call of AddOldBlocks. func (mr *MockStateModifierMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddOldBlocks), blocks) } -// AddOldDeserializedBlocks mocks base method +// AddOldDeserializedBlocks mocks base method. func (m *MockStateModifier) AddOldDeserializedBlocks(blocks []*proto.Block) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) @@ -985,109 +971,95 @@ func (m *MockStateModifier) AddOldDeserializedBlocks(blocks []*proto.Block) erro return ret0 } -// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks +// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks. func (mr *MockStateModifierMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddOldDeserializedBlocks), blocks) } -// RollbackToHeight mocks base method -func (m *MockStateModifier) RollbackToHeight(height proto.Height) error { +// Close mocks base method. +func (m *MockStateModifier) Close() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackToHeight", height) + ret := m.ctrl.Call(m, "Close") ret0, _ := ret[0].(error) return ret0 } -// RollbackToHeight indicates an expected call of RollbackToHeight -func (mr *MockStateModifierMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { +// Close indicates an expected call of Close. +func (mr *MockStateModifierMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockStateModifier)(nil).RollbackToHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStateModifier)(nil).Close)) } -// RollbackTo mocks base method -func (m *MockStateModifier) RollbackTo(removalEdge proto.BlockID) error { +// Map mocks base method. +func (m *MockStateModifier) Map(arg0 func(state.NonThreadSafeState) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackTo", removalEdge) + ret := m.ctrl.Call(m, "Map", arg0) ret0, _ := ret[0].(error) return ret0 } -// RollbackTo indicates an expected call of RollbackTo -func (mr *MockStateModifierMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { +// Map indicates an expected call of Map. +func (mr *MockStateModifierMockRecorder) Map(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockStateModifier)(nil).RollbackTo), removalEdge) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockStateModifier)(nil).Map), arg0) } -// ValidateNextTx mocks base method -func (m *MockStateModifier) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { +// PersistAddressTransactions mocks base method. +func (m *MockStateModifier) PersistAddressTransactions() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + ret := m.ctrl.Call(m, "PersistAddressTransactions") ret0, _ := ret[0].(error) return ret0 } -// ValidateNextTx indicates an expected call of ValidateNextTx -func (mr *MockStateModifierMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { +// PersistAddressTransactions indicates an expected call of PersistAddressTransactions. +func (mr *MockStateModifierMockRecorder) PersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockStateModifier)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockStateModifier)(nil).PersistAddressTransactions)) } -// ResetValidationList mocks base method +// ResetValidationList mocks base method. func (m *MockStateModifier) ResetValidationList() { m.ctrl.T.Helper() m.ctrl.Call(m, "ResetValidationList") } -// ResetValidationList indicates an expected call of ResetValidationList +// ResetValidationList indicates an expected call of ResetValidationList. func (mr *MockStateModifierMockRecorder) ResetValidationList() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockStateModifier)(nil).ResetValidationList)) } -// TxValidation mocks base method -func (m *MockStateModifier) TxValidation(arg0 func(state.TxValidation) error) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxValidation", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// TxValidation indicates an expected call of TxValidation -func (mr *MockStateModifierMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockStateModifier)(nil).TxValidation), arg0) -} - -// Map mocks base method -func (m *MockStateModifier) Map(arg0 func(state.NonThreadSafeState) error) error { +// RollbackTo mocks base method. +func (m *MockStateModifier) RollbackTo(removalEdge proto.BlockID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Map", arg0) + ret := m.ctrl.Call(m, "RollbackTo", removalEdge) ret0, _ := ret[0].(error) return ret0 } -// Map indicates an expected call of Map -func (mr *MockStateModifierMockRecorder) Map(arg0 interface{}) *gomock.Call { +// RollbackTo indicates an expected call of RollbackTo. +func (mr *MockStateModifierMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockStateModifier)(nil).Map), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockStateModifier)(nil).RollbackTo), removalEdge) } -// SavePeers mocks base method -func (m *MockStateModifier) SavePeers(arg0 []proto.TCPAddr) error { +// RollbackToHeight mocks base method. +func (m *MockStateModifier) RollbackToHeight(height proto.Height) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SavePeers", arg0) + ret := m.ctrl.Call(m, "RollbackToHeight", height) ret0, _ := ret[0].(error) return ret0 } -// SavePeers indicates an expected call of SavePeers -func (mr *MockStateModifierMockRecorder) SavePeers(arg0 interface{}) *gomock.Call { +// RollbackToHeight indicates an expected call of RollbackToHeight. +func (mr *MockStateModifierMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePeers", reflect.TypeOf((*MockStateModifier)(nil).SavePeers), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockStateModifier)(nil).RollbackToHeight), height) } -// StartProvidingExtendedApi mocks base method +// StartProvidingExtendedApi mocks base method. func (m *MockStateModifier) StartProvidingExtendedApi() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StartProvidingExtendedApi") @@ -1095,64 +1067,64 @@ func (m *MockStateModifier) StartProvidingExtendedApi() error { return ret0 } -// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi +// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi. func (mr *MockStateModifierMockRecorder) StartProvidingExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockStateModifier)(nil).StartProvidingExtendedApi)) } -// PersistAddressTransactions mocks base method -func (m *MockStateModifier) PersistAddressTransactions() error { +// TxValidation mocks base method. +func (m *MockStateModifier) TxValidation(arg0 func(state.TxValidation) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PersistAddressTransactions") + ret := m.ctrl.Call(m, "TxValidation", arg0) ret0, _ := ret[0].(error) return ret0 } -// PersistAddressTransactions indicates an expected call of PersistAddressTransactions -func (mr *MockStateModifierMockRecorder) PersistAddressTransactions() *gomock.Call { +// TxValidation indicates an expected call of TxValidation. +func (mr *MockStateModifierMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockStateModifier)(nil).PersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockStateModifier)(nil).TxValidation), arg0) } -// Close mocks base method -func (m *MockStateModifier) Close() error { +// ValidateNextTx mocks base method. +func (m *MockStateModifier) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") + ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) ret0, _ := ret[0].(error) return ret0 } -// Close indicates an expected call of Close -func (mr *MockStateModifierMockRecorder) Close() *gomock.Call { +// ValidateNextTx indicates an expected call of ValidateNextTx. +func (mr *MockStateModifierMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStateModifier)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockStateModifier)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// MockTxValidation is a mock of TxValidation interface +// MockTxValidation is a mock of TxValidation interface. type MockTxValidation struct { ctrl *gomock.Controller recorder *MockTxValidationMockRecorder } -// MockTxValidationMockRecorder is the mock recorder for MockTxValidation +// MockTxValidationMockRecorder is the mock recorder for MockTxValidation. type MockTxValidationMockRecorder struct { mock *MockTxValidation } -// NewMockTxValidation creates a new mock instance +// NewMockTxValidation creates a new mock instance. func NewMockTxValidation(ctrl *gomock.Controller) *MockTxValidation { mock := &MockTxValidation{ctrl: ctrl} mock.recorder = &MockTxValidationMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockTxValidation) EXPECT() *MockTxValidationMockRecorder { return m.recorder } -// ValidateNextTx mocks base method +// ValidateNextTx mocks base method. func (m *MockTxValidation) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) @@ -1160,245 +1132,273 @@ func (m *MockTxValidation) ValidateNextTx(tx proto.Transaction, currentTimestamp return ret0 } -// ValidateNextTx indicates an expected call of ValidateNextTx +// ValidateNextTx indicates an expected call of ValidateNextTx. func (mr *MockTxValidationMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockTxValidation)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// MockState is a mock of State interface +// MockState is a mock of State interface. type MockState struct { ctrl *gomock.Controller recorder *MockStateMockRecorder } -// MockStateMockRecorder is the mock recorder for MockState +// MockStateMockRecorder is the mock recorder for MockState. type MockStateMockRecorder struct { mock *MockState } -// NewMockState creates a new mock instance +// NewMockState creates a new mock instance. func NewMockState(ctrl *gomock.Controller) *MockState { mock := &MockState{ctrl: ctrl} mock.recorder = &MockStateMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockState) EXPECT() *MockStateMockRecorder { return m.recorder } -// TopBlock mocks base method -func (m *MockState) TopBlock() *proto.Block { +// AccountBalance mocks base method. +func (m *MockState) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TopBlock") - ret0, _ := ret[0].(*proto.Block) - return ret0 + ret := m.ctrl.Call(m, "AccountBalance", account, asset) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TopBlock indicates an expected call of TopBlock -func (mr *MockStateMockRecorder) TopBlock() *gomock.Call { +// AccountBalance indicates an expected call of AccountBalance. +func (mr *MockStateMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockState)(nil).TopBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockState)(nil).AccountBalance), account, asset) } -// Block mocks base method -func (m *MockState) Block(blockID proto.BlockID) (*proto.Block, error) { +// ActivationHeight mocks base method. +func (m *MockState) ActivationHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Block", blockID) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ActivationHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Block indicates an expected call of Block -func (mr *MockStateMockRecorder) Block(blockID interface{}) *gomock.Call { +// ActivationHeight indicates an expected call of ActivationHeight. +func (mr *MockStateMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockState)(nil).Block), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockState)(nil).ActivationHeight), featureID) } -// BlockByHeight mocks base method -func (m *MockState) BlockByHeight(height proto.Height) (*proto.Block, error) { +// AddBlock mocks base method. +func (m *MockState) AddBlock(block []byte) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHeight", height) + ret := m.ctrl.Call(m, "AddBlock", block) ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockByHeight indicates an expected call of BlockByHeight -func (mr *MockStateMockRecorder) BlockByHeight(height interface{}) *gomock.Call { +// AddBlock indicates an expected call of AddBlock. +func (mr *MockStateMockRecorder) AddBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockState)(nil).BlockByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockState)(nil).AddBlock), block) } -// Header mocks base method -func (m *MockState) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { +// AddDeserializedBlock mocks base method. +func (m *MockState) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Header", blockID) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "AddDeserializedBlock", block) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// Header indicates an expected call of Header -func (mr *MockStateMockRecorder) Header(blockID interface{}) *gomock.Call { +// AddDeserializedBlock indicates an expected call of AddDeserializedBlock. +func (mr *MockStateMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockState)(nil).Header), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockState)(nil).AddDeserializedBlock), block) } -// HeaderByHeight mocks base method -func (m *MockState) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { +// AddNewBlocks mocks base method. +func (m *MockState) AddNewBlocks(blocks [][]byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHeight", height) - ret0, _ := ret[0].(*proto.BlockHeader) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddNewBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 } -// HeaderByHeight indicates an expected call of HeaderByHeight -func (mr *MockStateMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { +// AddNewBlocks indicates an expected call of AddNewBlocks. +func (mr *MockStateMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockState)(nil).HeaderByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockState)(nil).AddNewBlocks), blocks) } -// Height mocks base method -func (m *MockState) Height() (proto.Height, error) { +// AddNewDeserializedBlocks mocks base method. +func (m *MockState) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Height") - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// Height indicates an expected call of Height -func (mr *MockStateMockRecorder) Height() *gomock.Call { +// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks. +func (mr *MockStateMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockState)(nil).Height)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddNewDeserializedBlocks), blocks) } -// BlockIDToHeight mocks base method -func (m *MockState) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { +// AddOldBlocks mocks base method. +func (m *MockState) AddOldBlocks(blocks [][]byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "AddOldBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddOldBlocks indicates an expected call of AddOldBlocks. +func (mr *MockStateMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockState)(nil).AddOldBlocks), blocks) +} + +// AddOldDeserializedBlocks mocks base method. +func (m *MockState) AddOldDeserializedBlocks(blocks []*proto.Block) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks. +func (mr *MockStateMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddOldDeserializedBlocks), blocks) +} + +// AddrByAlias mocks base method. +func (m *MockState) AddrByAlias(alias proto.Alias) (proto.Address, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddrByAlias", alias) + ret0, _ := ret[0].(proto.Address) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockIDToHeight indicates an expected call of BlockIDToHeight -func (mr *MockStateMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { +// AddrByAlias indicates an expected call of AddrByAlias. +func (mr *MockStateMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockState)(nil).BlockIDToHeight), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockState)(nil).AddrByAlias), alias) } -// HeightToBlockID mocks base method -func (m *MockState) HeightToBlockID(height proto.Height) (proto.BlockID, error) { +// AllFeatures mocks base method. +func (m *MockState) AllFeatures() ([]int16, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeightToBlockID", height) - ret0, _ := ret[0].(proto.BlockID) + ret := m.ctrl.Call(m, "AllFeatures") + ret0, _ := ret[0].([]int16) ret1, _ := ret[1].(error) return ret0, ret1 } -// HeightToBlockID indicates an expected call of HeightToBlockID -func (mr *MockStateMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { +// AllFeatures indicates an expected call of AllFeatures. +func (mr *MockStateMockRecorder) AllFeatures() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockState)(nil).HeightToBlockID), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockState)(nil).AllFeatures)) } -// FullWavesBalance mocks base method -func (m *MockState) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { +// ApprovalHeight mocks base method. +func (m *MockState) ApprovalHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullWavesBalance", account) - ret0, _ := ret[0].(*proto.FullWavesBalance) + ret := m.ctrl.Call(m, "ApprovalHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullWavesBalance indicates an expected call of FullWavesBalance -func (mr *MockStateMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { +// ApprovalHeight indicates an expected call of ApprovalHeight. +func (mr *MockStateMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockState)(nil).FullWavesBalance), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockState)(nil).ApprovalHeight), featureID) } -// EffectiveBalance mocks base method -func (m *MockState) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { +// AssetInfo mocks base method. +func (m *MockState) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "AssetInfo", assetID) + ret0, _ := ret[0].(*proto.AssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// EffectiveBalance indicates an expected call of EffectiveBalance -func (mr *MockStateMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { +// AssetInfo indicates an expected call of AssetInfo. +func (mr *MockStateMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockState)(nil).EffectiveBalance), account, startHeight, endHeight) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockState)(nil).AssetInfo), assetID) } -// AccountBalance mocks base method -func (m *MockState) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { +// AssetIsSponsored mocks base method. +func (m *MockState) AssetIsSponsored(assetID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccountBalance", account, asset) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AccountBalance indicates an expected call of AccountBalance -func (mr *MockStateMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { +// AssetIsSponsored indicates an expected call of AssetIsSponsored. +func (mr *MockStateMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockState)(nil).AccountBalance), account, asset) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockState)(nil).AssetIsSponsored), assetID) } -// WavesAddressesNumber mocks base method -func (m *MockState) WavesAddressesNumber() (uint64, error) { +// Block mocks base method. +func (m *MockState) Block(blockID proto.BlockID) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WavesAddressesNumber") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "Block", blockID) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// WavesAddressesNumber indicates an expected call of WavesAddressesNumber -func (mr *MockStateMockRecorder) WavesAddressesNumber() *gomock.Call { +// Block indicates an expected call of Block. +func (mr *MockStateMockRecorder) Block(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockState)(nil).WavesAddressesNumber)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockState)(nil).Block), blockID) } -// ScoreAtHeight mocks base method -func (m *MockState) ScoreAtHeight(height proto.Height) (*big.Int, error) { +// BlockByHeight mocks base method. +func (m *MockState) BlockByHeight(height proto.Height) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScoreAtHeight", height) - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "BlockByHeight", height) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScoreAtHeight indicates an expected call of ScoreAtHeight -func (mr *MockStateMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { +// BlockByHeight indicates an expected call of BlockByHeight. +func (mr *MockStateMockRecorder) BlockByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockState)(nil).ScoreAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockState)(nil).BlockByHeight), height) } -// CurrentScore mocks base method -func (m *MockState) CurrentScore() (*big.Int, error) { +// BlockIDToHeight mocks base method. +func (m *MockState) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CurrentScore") - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// CurrentScore indicates an expected call of CurrentScore -func (mr *MockStateMockRecorder) CurrentScore() *gomock.Call { +// BlockIDToHeight indicates an expected call of BlockIDToHeight. +func (mr *MockStateMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockState)(nil).CurrentScore)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockState)(nil).BlockIDToHeight), blockID) } -// BlockchainSettings mocks base method +// BlockchainSettings mocks base method. func (m *MockState) BlockchainSettings() (*settings.BlockchainSettings, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockchainSettings") @@ -1407,329 +1407,311 @@ func (m *MockState) BlockchainSettings() (*settings.BlockchainSettings, error) { return ret0, ret1 } -// BlockchainSettings indicates an expected call of BlockchainSettings +// BlockchainSettings indicates an expected call of BlockchainSettings. func (mr *MockStateMockRecorder) BlockchainSettings() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockState)(nil).BlockchainSettings)) } -// Peers mocks base method -func (m *MockState) Peers() ([]proto.TCPAddr, error) { +// Close mocks base method. +func (m *MockState) Close() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Peers") - ret0, _ := ret[0].([]proto.TCPAddr) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 } -// Peers indicates an expected call of Peers -func (mr *MockStateMockRecorder) Peers() *gomock.Call { +// Close indicates an expected call of Close. +func (mr *MockStateMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockState)(nil).Peers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockState)(nil).Close)) } -// VotesNum mocks base method -func (m *MockState) VotesNum(featureID int16) (uint64, error) { +// CurrentScore mocks base method. +func (m *MockState) CurrentScore() (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNum", featureID) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "CurrentScore") + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNum indicates an expected call of VotesNum -func (mr *MockStateMockRecorder) VotesNum(featureID interface{}) *gomock.Call { +// CurrentScore indicates an expected call of CurrentScore. +func (mr *MockStateMockRecorder) CurrentScore() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockState)(nil).VotesNum), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockState)(nil).CurrentScore)) } -// VotesNumAtHeight mocks base method -func (m *MockState) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { +// EffectiveBalance mocks base method. +func (m *MockState) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) + ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNumAtHeight indicates an expected call of VotesNumAtHeight -func (mr *MockStateMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { +// EffectiveBalance indicates an expected call of EffectiveBalance. +func (mr *MockStateMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockState)(nil).VotesNumAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockState)(nil).EffectiveBalance), account, startHeight, endHeight) } -// IsActivated mocks base method -func (m *MockState) IsActivated(featureID int16) (bool, error) { +// EstimatorVersion mocks base method. +func (m *MockState) EstimatorVersion() (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActivated", featureID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "EstimatorVersion") + ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActivated indicates an expected call of IsActivated -func (mr *MockStateMockRecorder) IsActivated(featureID interface{}) *gomock.Call { +// EstimatorVersion indicates an expected call of EstimatorVersion. +func (mr *MockStateMockRecorder) EstimatorVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockState)(nil).IsActivated), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockState)(nil).EstimatorVersion)) } -// IsActiveAtHeight mocks base method -func (m *MockState) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { +// FullAssetInfo mocks base method. +func (m *MockState) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "FullAssetInfo", assetID) + ret0, _ := ret[0].(*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActiveAtHeight indicates an expected call of IsActiveAtHeight -func (mr *MockStateMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { +// FullAssetInfo indicates an expected call of FullAssetInfo. +func (mr *MockStateMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockState)(nil).IsActiveAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockState)(nil).FullAssetInfo), assetID) } -// ActivationHeight mocks base method -func (m *MockState) ActivationHeight(featureID int16) (proto.Height, error) { +// FullWavesBalance mocks base method. +func (m *MockState) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ActivationHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "FullWavesBalance", account) + ret0, _ := ret[0].(*proto.FullWavesBalance) ret1, _ := ret[1].(error) return ret0, ret1 } -// ActivationHeight indicates an expected call of ActivationHeight -func (mr *MockStateMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { +// FullWavesBalance indicates an expected call of FullWavesBalance. +func (mr *MockStateMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockState)(nil).ActivationHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockState)(nil).FullWavesBalance), account) } -// IsApproved mocks base method -func (m *MockState) IsApproved(featureID int16) (bool, error) { +// Header mocks base method. +func (m *MockState) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsApproved", featureID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "Header", blockID) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsApproved indicates an expected call of IsApproved -func (mr *MockStateMockRecorder) IsApproved(featureID interface{}) *gomock.Call { +// Header indicates an expected call of Header. +func (mr *MockStateMockRecorder) Header(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockState)(nil).IsApproved), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockState)(nil).Header), blockID) } -// IsApprovedAtHeight mocks base method -func (m *MockState) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { +// HeaderByHeight mocks base method. +func (m *MockState) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "HeaderByHeight", height) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight -func (mr *MockStateMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { +// HeaderByHeight indicates an expected call of HeaderByHeight. +func (mr *MockStateMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockState)(nil).IsApprovedAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockState)(nil).HeaderByHeight), height) } -// ApprovalHeight mocks base method -func (m *MockState) ApprovalHeight(featureID int16) (proto.Height, error) { +// Height mocks base method. +func (m *MockState) Height() (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ApprovalHeight", featureID) + ret := m.ctrl.Call(m, "Height") ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// ApprovalHeight indicates an expected call of ApprovalHeight -func (mr *MockStateMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { +// Height indicates an expected call of Height. +func (mr *MockStateMockRecorder) Height() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockState)(nil).ApprovalHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockState)(nil).Height)) } -// AllFeatures mocks base method -func (m *MockState) AllFeatures() ([]int16, error) { +// HeightToBlockID mocks base method. +func (m *MockState) HeightToBlockID(height proto.Height) (proto.BlockID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllFeatures") - ret0, _ := ret[0].([]int16) + ret := m.ctrl.Call(m, "HeightToBlockID", height) + ret0, _ := ret[0].(proto.BlockID) ret1, _ := ret[1].(error) return ret0, ret1 } -// AllFeatures indicates an expected call of AllFeatures -func (mr *MockStateMockRecorder) AllFeatures() *gomock.Call { +// HeightToBlockID indicates an expected call of HeightToBlockID. +func (mr *MockStateMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockState)(nil).AllFeatures)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockState)(nil).HeightToBlockID), height) } -// EstimatorVersion mocks base method -func (m *MockState) EstimatorVersion() (int, error) { +// HitSourceAtHeight mocks base method. +func (m *MockState) HitSourceAtHeight(height proto.Height) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatorVersion") - ret0, _ := ret[0].(int) + ret := m.ctrl.Call(m, "HitSourceAtHeight", height) + ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } -// EstimatorVersion indicates an expected call of EstimatorVersion -func (mr *MockStateMockRecorder) EstimatorVersion() *gomock.Call { +// HitSourceAtHeight indicates an expected call of HitSourceAtHeight. +func (mr *MockStateMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockState)(nil).EstimatorVersion)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockState)(nil).HitSourceAtHeight), height) } -// AddrByAlias mocks base method -func (m *MockState) AddrByAlias(alias proto.Alias) (proto.Address, error) { +// InvokeResultByID mocks base method. +func (m *MockState) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddrByAlias", alias) - ret0, _ := ret[0].(proto.Address) + ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) + ret0, _ := ret[0].(*proto.ScriptResult) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddrByAlias indicates an expected call of AddrByAlias -func (mr *MockStateMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { +// InvokeResultByID indicates an expected call of InvokeResultByID. +func (mr *MockStateMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockState)(nil).AddrByAlias), alias) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockState)(nil).InvokeResultByID), invokeID) } -// RetrieveEntries mocks base method -func (m *MockState) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { +// IsActivated mocks base method. +func (m *MockState) IsActivated(featureID int16) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntries", account) - ret0, _ := ret[0].([]proto.DataEntry) + ret := m.ctrl.Call(m, "IsActivated", featureID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntries indicates an expected call of RetrieveEntries -func (mr *MockStateMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { +// IsActivated indicates an expected call of IsActivated. +func (mr *MockStateMockRecorder) IsActivated(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockState)(nil).RetrieveEntries), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockState)(nil).IsActivated), featureID) } -// RetrieveEntry mocks base method -func (m *MockState) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { +// IsActiveAtHeight mocks base method. +func (m *MockState) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntry", account, key) - ret0, _ := ret[0].(proto.DataEntry) + ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntry indicates an expected call of RetrieveEntry -func (mr *MockStateMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { +// IsActiveAtHeight indicates an expected call of IsActiveAtHeight. +func (mr *MockStateMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockState)(nil).RetrieveEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockState)(nil).IsActiveAtHeight), featureID, height) } -// RetrieveIntegerEntry mocks base method -func (m *MockState) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { +// IsActiveLeasing mocks base method. +func (m *MockState) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) - ret0, _ := ret[0].(*proto.IntegerDataEntry) + ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry -func (mr *MockStateMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { +// IsActiveLeasing indicates an expected call of IsActiveLeasing. +func (mr *MockStateMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockState)(nil).RetrieveIntegerEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockState)(nil).IsActiveLeasing), leaseID) } -// RetrieveBooleanEntry mocks base method -func (m *MockState) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { +// IsApproved mocks base method. +func (m *MockState) IsApproved(featureID int16) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) - ret0, _ := ret[0].(*proto.BooleanDataEntry) + ret := m.ctrl.Call(m, "IsApproved", featureID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry -func (mr *MockStateMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { +// IsApproved indicates an expected call of IsApproved. +func (mr *MockStateMockRecorder) IsApproved(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockState)(nil).RetrieveBooleanEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockState)(nil).IsApproved), featureID) } -// RetrieveStringEntry mocks base method -func (m *MockState) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { +// IsApprovedAtHeight mocks base method. +func (m *MockState) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) - ret0, _ := ret[0].(*proto.StringDataEntry) + ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveStringEntry indicates an expected call of RetrieveStringEntry -func (mr *MockStateMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { +// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight. +func (mr *MockStateMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockState)(nil).RetrieveStringEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockState)(nil).IsApprovedAtHeight), featureID, height) } -// RetrieveBinaryEntry mocks base method -func (m *MockState) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { +// Map mocks base method. +func (m *MockState) Map(arg0 func(state.NonThreadSafeState) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) - ret0, _ := ret[0].(*proto.BinaryDataEntry) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "Map", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry -func (mr *MockStateMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { +// Map indicates an expected call of Map. +func (mr *MockStateMockRecorder) Map(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockState)(nil).RetrieveBinaryEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockState)(nil).Map), arg0) } -// TransactionByID mocks base method -func (m *MockState) TransactionByID(id []byte) (proto.Transaction, error) { +// MapR mocks base method. +func (m *MockState) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByID", id) - ret0, _ := ret[0].(proto.Transaction) + ret := m.ctrl.Call(m, "MapR", arg0) + ret0, _ := ret[0].(interface{}) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionByID indicates an expected call of TransactionByID -func (mr *MockStateMockRecorder) TransactionByID(id interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockState)(nil).TransactionByID), id) -} - -// TransactionByIDWithStatus mocks base method -func (m *MockState) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) - ret0, _ := ret[0].(proto.Transaction) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus -func (mr *MockStateMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { +// MapR indicates an expected call of MapR. +func (mr *MockStateMockRecorder) MapR(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockState)(nil).TransactionByIDWithStatus), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockState)(nil).MapR), arg0) } -// TransactionHeightByID mocks base method -func (m *MockState) TransactionHeightByID(id []byte) (uint64, error) { +// NFTList mocks base method. +func (m *MockState) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionHeightByID", id) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) + ret0, _ := ret[0].([]*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionHeightByID indicates an expected call of TransactionHeightByID -func (mr *MockStateMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { +// NFTList indicates an expected call of NFTList. +func (mr *MockStateMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockState)(nil).TransactionHeightByID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockState)(nil).NFTList), account, limit, afterAssetID) } -// NewAddrTransactionsIterator mocks base method +// NewAddrTransactionsIterator mocks base method. func (m *MockState) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) @@ -1738,364 +1720,336 @@ func (m *MockState) NewAddrTransactionsIterator(addr proto.Address) (state.Trans return ret0, ret1 } -// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator +// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator. func (mr *MockStateMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockState)(nil).NewAddrTransactionsIterator), addr) } -// AssetIsSponsored mocks base method -func (m *MockState) AssetIsSponsored(assetID crypto.Digest) (bool, error) { +// PersistAddressTransactions mocks base method. +func (m *MockState) PersistAddressTransactions() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "PersistAddressTransactions") + ret0, _ := ret[0].(error) + return ret0 } -// AssetIsSponsored indicates an expected call of AssetIsSponsored -func (mr *MockStateMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { +// PersistAddressTransactions indicates an expected call of PersistAddressTransactions. +func (mr *MockStateMockRecorder) PersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockState)(nil).AssetIsSponsored), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockState)(nil).PersistAddressTransactions)) } -// AssetInfo mocks base method -func (m *MockState) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { +// ProvidesExtendedApi mocks base method. +func (m *MockState) ProvidesExtendedApi() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetInfo", assetID) - ret0, _ := ret[0].(*proto.AssetInfo) + ret := m.ctrl.Call(m, "ProvidesExtendedApi") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetInfo indicates an expected call of AssetInfo -func (mr *MockStateMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { +// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi. +func (mr *MockStateMockRecorder) ProvidesExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockState)(nil).AssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockState)(nil).ProvidesExtendedApi)) } -// FullAssetInfo mocks base method -func (m *MockState) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { +// ProvidesStateHashes mocks base method. +func (m *MockState) ProvidesStateHashes() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullAssetInfo", assetID) - ret0, _ := ret[0].(*proto.FullAssetInfo) + ret := m.ctrl.Call(m, "ProvidesStateHashes") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullAssetInfo indicates an expected call of FullAssetInfo -func (mr *MockStateMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { +// ProvidesStateHashes indicates an expected call of ProvidesStateHashes. +func (mr *MockStateMockRecorder) ProvidesStateHashes() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockState)(nil).FullAssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockState)(nil).ProvidesStateHashes)) } -// NFTList mocks base method -func (m *MockState) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { +// ResetValidationList mocks base method. +func (m *MockState) ResetValidationList() { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) - ret0, _ := ret[0].([]*proto.FullAssetInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 + m.ctrl.Call(m, "ResetValidationList") } -// NFTList indicates an expected call of NFTList -func (mr *MockStateMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { +// ResetValidationList indicates an expected call of ResetValidationList. +func (mr *MockStateMockRecorder) ResetValidationList() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockState)(nil).NFTList), account, limit, afterAssetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockState)(nil).ResetValidationList)) } -// ScriptInfoByAccount mocks base method -func (m *MockState) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { +// RetrieveBinaryEntry mocks base method. +func (m *MockState) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) + ret0, _ := ret[0].(*proto.BinaryDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount -func (mr *MockStateMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { +// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry. +func (mr *MockStateMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockState)(nil).ScriptInfoByAccount), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockState)(nil).RetrieveBinaryEntry), account, key) } -// ScriptInfoByAsset mocks base method -func (m *MockState) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { +// RetrieveBooleanEntry mocks base method. +func (m *MockState) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) + ret0, _ := ret[0].(*proto.BooleanDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset -func (mr *MockStateMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { +// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry. +func (mr *MockStateMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockState)(nil).ScriptInfoByAsset), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockState)(nil).RetrieveBooleanEntry), account, key) } -// IsActiveLeasing mocks base method -func (m *MockState) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { +// RetrieveEntries mocks base method. +func (m *MockState) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveEntries", account) + ret0, _ := ret[0].([]proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActiveLeasing indicates an expected call of IsActiveLeasing -func (mr *MockStateMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { +// RetrieveEntries indicates an expected call of RetrieveEntries. +func (mr *MockStateMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockState)(nil).IsActiveLeasing), leaseID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockState)(nil).RetrieveEntries), account) } -// InvokeResultByID mocks base method -func (m *MockState) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { +// RetrieveEntry mocks base method. +func (m *MockState) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) - ret0, _ := ret[0].(*proto.ScriptResult) + ret := m.ctrl.Call(m, "RetrieveEntry", account, key) + ret0, _ := ret[0].(proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// InvokeResultByID indicates an expected call of InvokeResultByID -func (mr *MockStateMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { +// RetrieveEntry indicates an expected call of RetrieveEntry. +func (mr *MockStateMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockState)(nil).InvokeResultByID), invokeID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockState)(nil).RetrieveEntry), account, key) } -// ProvidesExtendedApi mocks base method -func (m *MockState) ProvidesExtendedApi() (bool, error) { +// RetrieveIntegerEntry mocks base method. +func (m *MockState) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesExtendedApi") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) + ret0, _ := ret[0].(*proto.IntegerDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi -func (mr *MockStateMockRecorder) ProvidesExtendedApi() *gomock.Call { +// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry. +func (mr *MockStateMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockState)(nil).ProvidesExtendedApi)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockState)(nil).RetrieveIntegerEntry), account, key) } -// ProvidesStateHashes mocks base method -func (m *MockState) ProvidesStateHashes() (bool, error) { +// RetrieveStringEntry mocks base method. +func (m *MockState) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesStateHashes") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) + ret0, _ := ret[0].(*proto.StringDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesStateHashes indicates an expected call of ProvidesStateHashes -func (mr *MockStateMockRecorder) ProvidesStateHashes() *gomock.Call { +// RetrieveStringEntry indicates an expected call of RetrieveStringEntry. +func (mr *MockStateMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockState)(nil).ProvidesStateHashes)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockState)(nil).RetrieveStringEntry), account, key) } -// StateHashAtHeight mocks base method -func (m *MockState) StateHashAtHeight(height uint64) (*proto.StateHash, error) { +// RollbackTo mocks base method. +func (m *MockState) RollbackTo(removalEdge proto.BlockID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateHashAtHeight", height) - ret0, _ := ret[0].(*proto.StateHash) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "RollbackTo", removalEdge) + ret0, _ := ret[0].(error) + return ret0 } -// StateHashAtHeight indicates an expected call of StateHashAtHeight -func (mr *MockStateMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { +// RollbackTo indicates an expected call of RollbackTo. +func (mr *MockStateMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockState)(nil).StateHashAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockState)(nil).RollbackTo), removalEdge) } -// MapR mocks base method -func (m *MockState) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { +// RollbackToHeight mocks base method. +func (m *MockState) RollbackToHeight(height proto.Height) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MapR", arg0) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "RollbackToHeight", height) + ret0, _ := ret[0].(error) + return ret0 } -// MapR indicates an expected call of MapR -func (mr *MockStateMockRecorder) MapR(arg0 interface{}) *gomock.Call { +// RollbackToHeight indicates an expected call of RollbackToHeight. +func (mr *MockStateMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockState)(nil).MapR), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockState)(nil).RollbackToHeight), height) } -// HitSourceAtHeight mocks base method -func (m *MockState) HitSourceAtHeight(height proto.Height) ([]byte, error) { +// ScoreAtHeight mocks base method. +func (m *MockState) ScoreAtHeight(height proto.Height) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HitSourceAtHeight", height) - ret0, _ := ret[0].([]byte) + ret := m.ctrl.Call(m, "ScoreAtHeight", height) + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// HitSourceAtHeight indicates an expected call of HitSourceAtHeight -func (mr *MockStateMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { +// ScoreAtHeight indicates an expected call of ScoreAtHeight. +func (mr *MockStateMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockState)(nil).HitSourceAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockState)(nil).ScoreAtHeight), height) } -// ShouldPersistAddressTransactions mocks base method -func (m *MockState) ShouldPersistAddressTransactions() (bool, error) { +// ScriptInfoByAccount mocks base method. +func (m *MockState) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions -func (mr *MockStateMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { +// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount. +func (mr *MockStateMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockState)(nil).ShouldPersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockState)(nil).ScriptInfoByAccount), account) } -// AddBlock mocks base method -func (m *MockState) AddBlock(block []byte) (*proto.Block, error) { +// ScriptInfoByAsset mocks base method. +func (m *MockState) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddBlock", block) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddBlock indicates an expected call of AddBlock -func (mr *MockStateMockRecorder) AddBlock(block interface{}) *gomock.Call { +// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset. +func (mr *MockStateMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockState)(nil).AddBlock), block) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockState)(nil).ScriptInfoByAsset), assetID) } -// AddDeserializedBlock mocks base method -func (m *MockState) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { +// ShouldPersistAddressTransactions mocks base method. +func (m *MockState) ShouldPersistAddressTransactions() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddDeserializedBlock", block) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddDeserializedBlock indicates an expected call of AddDeserializedBlock -func (mr *MockStateMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { +// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions. +func (mr *MockStateMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockState)(nil).AddDeserializedBlock), block) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockState)(nil).ShouldPersistAddressTransactions)) } -// AddNewBlocks mocks base method -func (m *MockState) AddNewBlocks(blocks [][]byte) error { +// StartProvidingExtendedApi mocks base method. +func (m *MockState) StartProvidingExtendedApi() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewBlocks", blocks) + ret := m.ctrl.Call(m, "StartProvidingExtendedApi") ret0, _ := ret[0].(error) return ret0 } -// AddNewBlocks indicates an expected call of AddNewBlocks -func (mr *MockStateMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { +// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi. +func (mr *MockStateMockRecorder) StartProvidingExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockState)(nil).AddNewBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockState)(nil).StartProvidingExtendedApi)) } -// AddNewDeserializedBlocks mocks base method -func (m *MockState) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { +// StateHashAtHeight mocks base method. +func (m *MockState) StateHashAtHeight(height uint64) (*proto.StateHash, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "StateHashAtHeight", height) + ret0, _ := ret[0].(*proto.StateHash) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks -func (mr *MockStateMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddNewDeserializedBlocks), blocks) -} - -// AddOldBlocks mocks base method -func (m *MockState) AddOldBlocks(blocks [][]byte) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddOldBlocks", blocks) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddOldBlocks indicates an expected call of AddOldBlocks -func (mr *MockStateMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockState)(nil).AddOldBlocks), blocks) -} - -// AddOldDeserializedBlocks mocks base method -func (m *MockState) AddOldDeserializedBlocks(blocks []*proto.Block) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks -func (mr *MockStateMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { +// StateHashAtHeight indicates an expected call of StateHashAtHeight. +func (mr *MockStateMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddOldDeserializedBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockState)(nil).StateHashAtHeight), height) } -// RollbackToHeight mocks base method -func (m *MockState) RollbackToHeight(height proto.Height) error { +// TopBlock mocks base method. +func (m *MockState) TopBlock() *proto.Block { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackToHeight", height) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "TopBlock") + ret0, _ := ret[0].(*proto.Block) return ret0 } -// RollbackToHeight indicates an expected call of RollbackToHeight -func (mr *MockStateMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { +// TopBlock indicates an expected call of TopBlock. +func (mr *MockStateMockRecorder) TopBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockState)(nil).RollbackToHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockState)(nil).TopBlock)) } -// RollbackTo mocks base method -func (m *MockState) RollbackTo(removalEdge proto.BlockID) error { +// TransactionByID mocks base method. +func (m *MockState) TransactionByID(id []byte) (proto.Transaction, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackTo", removalEdge) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "TransactionByID", id) + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// RollbackTo indicates an expected call of RollbackTo -func (mr *MockStateMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { +// TransactionByID indicates an expected call of TransactionByID. +func (mr *MockStateMockRecorder) TransactionByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockState)(nil).RollbackTo), removalEdge) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockState)(nil).TransactionByID), id) } -// ValidateNextTx mocks base method -func (m *MockState) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { +// TransactionByIDWithStatus mocks base method. +func (m *MockState) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// ValidateNextTx indicates an expected call of ValidateNextTx -func (mr *MockStateMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { +// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus. +func (mr *MockStateMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockState)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockState)(nil).TransactionByIDWithStatus), id) } -// ResetValidationList mocks base method -func (m *MockState) ResetValidationList() { +// TransactionHeightByID mocks base method. +func (m *MockState) TransactionHeightByID(id []byte) (uint64, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "ResetValidationList") + ret := m.ctrl.Call(m, "TransactionHeightByID", id) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// ResetValidationList indicates an expected call of ResetValidationList -func (mr *MockStateMockRecorder) ResetValidationList() *gomock.Call { +// TransactionHeightByID indicates an expected call of TransactionHeightByID. +func (mr *MockStateMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockState)(nil).ResetValidationList)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockState)(nil).TransactionHeightByID), id) } -// TxValidation mocks base method +// TxValidation mocks base method. func (m *MockState) TxValidation(arg0 func(state.TxValidation) error) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TxValidation", arg0) @@ -2103,78 +2057,67 @@ func (m *MockState) TxValidation(arg0 func(state.TxValidation) error) error { return ret0 } -// TxValidation indicates an expected call of TxValidation +// TxValidation indicates an expected call of TxValidation. func (mr *MockStateMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockState)(nil).TxValidation), arg0) } -// Map mocks base method -func (m *MockState) Map(arg0 func(state.NonThreadSafeState) error) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Map", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// Map indicates an expected call of Map -func (mr *MockStateMockRecorder) Map(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockState)(nil).Map), arg0) -} - -// SavePeers mocks base method -func (m *MockState) SavePeers(arg0 []proto.TCPAddr) error { +// ValidateNextTx mocks base method. +func (m *MockState) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SavePeers", arg0) + ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) ret0, _ := ret[0].(error) return ret0 } -// SavePeers indicates an expected call of SavePeers -func (mr *MockStateMockRecorder) SavePeers(arg0 interface{}) *gomock.Call { +// ValidateNextTx indicates an expected call of ValidateNextTx. +func (mr *MockStateMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePeers", reflect.TypeOf((*MockState)(nil).SavePeers), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockState)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// StartProvidingExtendedApi mocks base method -func (m *MockState) StartProvidingExtendedApi() error { +// VotesNum mocks base method. +func (m *MockState) VotesNum(featureID int16) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartProvidingExtendedApi") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "VotesNum", featureID) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi -func (mr *MockStateMockRecorder) StartProvidingExtendedApi() *gomock.Call { +// VotesNum indicates an expected call of VotesNum. +func (mr *MockStateMockRecorder) VotesNum(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockState)(nil).StartProvidingExtendedApi)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockState)(nil).VotesNum), featureID) } -// PersistAddressTransactions mocks base method -func (m *MockState) PersistAddressTransactions() error { +// VotesNumAtHeight mocks base method. +func (m *MockState) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PersistAddressTransactions") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// PersistAddressTransactions indicates an expected call of PersistAddressTransactions -func (mr *MockStateMockRecorder) PersistAddressTransactions() *gomock.Call { +// VotesNumAtHeight indicates an expected call of VotesNumAtHeight. +func (mr *MockStateMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockState)(nil).PersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockState)(nil).VotesNumAtHeight), featureID, height) } -// Close mocks base method -func (m *MockState) Close() error { +// WavesAddressesNumber mocks base method. +func (m *MockState) WavesAddressesNumber() (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "WavesAddressesNumber") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// Close indicates an expected call of Close -func (mr *MockStateMockRecorder) Close() *gomock.Call { +// WavesAddressesNumber indicates an expected call of WavesAddressesNumber. +func (mr *MockStateMockRecorder) WavesAddressesNumber() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockState)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockState)(nil).WavesAddressesNumber)) } diff --git a/pkg/node/actions_by_type.go b/pkg/node/actions_by_type.go index cb8e5823d..5680d4c25 100644 --- a/pkg/node/actions_by_type.go +++ b/pkg/node/actions_by_type.go @@ -2,9 +2,10 @@ package node import ( "math/big" - "net" "reflect" + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/node/state_fsm" @@ -25,16 +26,14 @@ func ScoreAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) func GetPeersAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { metricGetPeersMessage.Inc() - rs, err := services.Peers.KnownPeers() - if err != nil { - zap.L().Error("failed got known peers", zap.Error(err)) - return fsm, nil, err - } + rs := services.Peers.KnownPeers() + var out []proto.PeerInfo for _, r := range rs { + ipPort := proto.IpPort(r) out = append(out, proto.PeerInfo{ - Addr: net.IP(r.IP[:]), - Port: uint16(r.Port), + Addr: ipPort.Addr(), + Port: uint16(ipPort.Port()), }) } mess.ID.SendMessage(&proto.PeersMessage{Peers: out}) @@ -43,20 +42,15 @@ func GetPeersAction(services services.Services, mess peer.ProtoMessage, fsm stat func PeersAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { metricPeersMessage.Inc() - rs, err := services.Peers.KnownPeers() - if err != nil { - zap.L().Error("failed got known peers", zap.Error(err)) - return fsm, nil, err - } + rs := services.Peers.KnownPeers() + m := mess.Message.(*proto.PeersMessage).Peers if len(m) == 0 { return fsm, nil, nil } for _, p := range m { - rs = append(rs, proto.TCPAddr{ - IP: p.Addr, - Port: int(p.Port), - }) + known := storage.KnownPeer(proto.NewTCPAddr(p.Addr, int(p.Port)).ToIpPort()) + rs = append(rs, known) } return fsm, nil, services.Peers.UpdateKnownPeers(rs) } @@ -85,17 +79,17 @@ func GetBlockAction(services services.Services, mess peer.ProtoMessage, fsm stat return fsm, nil, nil } -// received asked earlier signatures -func SignaturesAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { - sigs := mess.Message.(*proto.SignaturesMessage).Signatures - blockIDs := make([]proto.BlockID, len(sigs)) - for i, sig := range sigs { +// SignaturesAction receives requested earlier signatures +func SignaturesAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { + signatures := mess.Message.(*proto.SignaturesMessage).Signatures + blockIDs := make([]proto.BlockID, len(signatures)) + for i, sig := range signatures { blockIDs[i] = proto.NewBlockIDFromSignature(sig) } return fsm.BlockIDs(mess.ID, blockIDs) } -// peers asks us about our signatures +// GetSignaturesAction replies to signature requests func GetSignaturesAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { for _, sig := range mess.Message.(*proto.GetSignaturesMessage).Signatures { block, err := services.State.Header(proto.NewBlockIDFromSignature(sig)) @@ -126,7 +120,7 @@ func sendSignatures(services services.Services, block *proto.BlockHeader, p peer out = append(out, b.BlockSignature) } - // if we put smth except first block + // There are block signatures to send in addition to requested one if len(out) > 1 { p.SendMessage(&proto.SignaturesMessage{ Signatures: out, @@ -152,7 +146,7 @@ func sendBlockIds(services services.Services, block *proto.BlockHeader, p peer.P out = append(out, b.BlockID()) } - // if we put smth except first block + // There are block signatures to send in addition to requested one if len(out) > 1 { p.SendMessage(&proto.BlockIdsMessage{ Blocks: out, @@ -160,8 +154,8 @@ func sendBlockIds(services services.Services, block *proto.BlockHeader, p peer.P } } -// remote node mined microblock and sent us info about it. -func MicroBlockInvAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { +// MicroBlockInvAction handles notification about new microblock. +func MicroBlockInvAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { inv := &proto.MicroBlockInv{} err := inv.UnmarshalBinary(mess.Message.(*proto.MicroBlockInvMessage).Body) if err != nil { @@ -170,7 +164,7 @@ func MicroBlockInvAction(services services.Services, mess peer.ProtoMessage, fsm return fsm.MicroBlockInv(mess.ID, inv) } -// Our miner mined microblock, sent MicroblockInv to other nodes, they asked us about Microblock. +// MicroBlockRequestAction handles microblock requests. func MicroBlockRequestAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { blockID, err := proto.NewBlockIDFromBytes(mess.Message.(*proto.MicroBlockRequestMessage).TotalBlockSig) if err != nil { @@ -192,7 +186,7 @@ func MicroBlockAction(services services.Services, mess peer.ProtoMessage, fsm st return fsm.MicroBlock(mess.ID, micro) } -// arrived protobuf block +// PBBlockAction handles protobuf block message. func PBBlockAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { b := &proto.Block{} err := b.UnmarshalFromProtobuf(mess.Message.(*proto.PBBlockMessage).PBBlockBytes) @@ -204,7 +198,7 @@ func PBBlockAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FS return fsm.Block(mess.ID, b) } -func PBMicroBlockAction(services services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { +func PBMicroBlockAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { micro := &proto.MicroBlock{} err := micro.UnmarshalFromProtobuf(mess.Message.(*proto.PBMicroBlockMessage).MicroBlockBytes) if err != nil { @@ -229,23 +223,24 @@ func BlockIdsAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.F return fsm.BlockIDs(mess.ID, mess.Message.(*proto.BlockIdsMessage).Blocks) } -// TODO broadcast +// TransactionAction handles new transaction message. func TransactionAction(s services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { - tbts := mess.Message.(*proto.TransactionMessage).Transaction - t, err := proto.BytesToTransaction(tbts, s.Scheme) + b := mess.Message.(*proto.TransactionMessage).Transaction + tx, err := proto.BytesToTransaction(b, s.Scheme) if err != nil { return fsm, nil, err } - return fsm.Transaction(mess.ID, t) + return fsm.Transaction(mess.ID, tx) } -// TODO broadcast transaction +// PBTransactionAction handles protobuf transaction message. func PBTransactionAction(_ services.Services, mess peer.ProtoMessage, fsm state_fsm.FSM) (state_fsm.FSM, state_fsm.Async, error) { b := mess.Message.(*proto.PBTransactionMessage).Transaction t, err := proto.SignedTxFromProtobuf(b) if err != nil { return fsm, nil, err } + // TODO add transaction re-broadcast return fsm.Transaction(mess.ID, t) } diff --git a/pkg/node/actions_by_type_test.go b/pkg/node/actions_by_type_test.go index 42f9d2256..72ed4bc61 100644 --- a/pkg/node/actions_by_type_test.go +++ b/pkg/node/actions_by_type_test.go @@ -1,6 +1,7 @@ package node import ( + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" "net" "testing" @@ -16,8 +17,9 @@ func TestPeersAction(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := mock.NewMockPeerManager(ctrl) - m.EXPECT().KnownPeers().Return([]proto.TCPAddr{}, nil) - m.EXPECT().UpdateKnownPeers([]proto.TCPAddr{{IP: net.ParseIP("127.0.0.1"), Port: 6868}}) + m.EXPECT().KnownPeers().Return([]storage.KnownPeer{}) + addr := proto.NewTCPAddr(net.ParseIP("127.0.0.1"), 6868).ToIpPort() + m.EXPECT().UpdateKnownPeers([]storage.KnownPeer{storage.KnownPeer(addr)}) _, _, err := PeersAction(services.Services{ Peers: m, diff --git a/pkg/node/blocks_applier/blocks_applier_test.go b/pkg/node/blocks_applier/blocks_applier_test.go index bb026f695..314accf33 100644 --- a/pkg/node/blocks_applier/blocks_applier_test.go +++ b/pkg/node/blocks_applier/blocks_applier_test.go @@ -104,5 +104,6 @@ func TestApply_InvalidBlockWithRollback(t *testing.T) { ba := innerBlocksApplier{} _, err := ba.apply(stateMock, []*proto.Block{block2}) + require.NotNil(t, err) require.Equal(t, "failed add deserialized blocks, first block id sV8beveiVKCiUn9BGZRgZj7V5tRRWPMRj1V9WWzKWnigtfQyZ2eErVXHi7vyGXj5hPuaxF9sGxowZr5XuD4UAwW: error message", err.Error()) } diff --git a/pkg/node/peer_manager/memory_peer_storage.go b/pkg/node/peer_manager/memory_peer_storage.go deleted file mode 100644 index 4af8f04f2..000000000 --- a/pkg/node/peer_manager/memory_peer_storage.go +++ /dev/null @@ -1,18 +0,0 @@ -package peer_manager - -import "github.com/wavesplatform/gowaves/pkg/proto" - -type MemoryPeerStorage struct { - peers []proto.TCPAddr -} - -func (a *MemoryPeerStorage) SavePeers(peers []proto.TCPAddr) error { - b := make([]proto.TCPAddr, len(peers)) - copy(b, peers) - a.peers = b - return nil -} - -func (a *MemoryPeerStorage) Peers() ([]proto.TCPAddr, error) { - return a.peers, nil -} diff --git a/pkg/node/peer_manager/peer_manager.go b/pkg/node/peer_manager/peer_manager.go index 63eed1661..5688f401a 100644 --- a/pkg/node/peer_manager/peer_manager.go +++ b/pkg/node/peer_manager/peer_manager.go @@ -2,6 +2,7 @@ package peer_manager import ( "context" + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" "math/big" "net" "sort" @@ -14,6 +15,8 @@ import ( "go.uber.org/zap" ) +const suspendDuration = 5 * time.Minute + type peerInfo struct { score *big.Int peer peer.Peer @@ -39,13 +42,13 @@ type PeerManager interface { InOutCount() (in int, out int) EachConnected(func(peer.Peer, *proto.Score)) IsSuspended(peer.Peer) bool - Suspend(peer.Peer, string) - Suspended() []string + Suspend(peer peer.Peer, suspendTime time.Time, reason string) + Suspended() []storage.SuspendedPeer AddConnected(peer.Peer) PeerWithHighestScore() (peer.Peer, *big.Int, bool) UpdateScore(p peer.Peer, score *proto.Score) error - UpdateKnownPeers([]proto.TCPAddr) error - KnownPeers() ([]proto.TCPAddr, error) + UpdateKnownPeers([]storage.KnownPeer) error + KnownPeers() []storage.KnownPeer Close() SpawnOutgoingConnections(context.Context) SpawnIncomingConnection(ctx context.Context, conn net.Conn) error @@ -53,79 +56,31 @@ type PeerManager interface { Connect(context.Context, proto.TCPAddr) error Score(p peer.Peer) (*proto.Score, error) - // for all connected node send GetPeersMessage + // AskPeers sends GetPeersMessage message to all connected nodes. AskPeers() Disconnect(peer.Peer) } -type Ip = [net.IPv6len]byte - -type suspended map[Ip]time.Time - -func (a suspended) Blocked(ipPort proto.IpPort, now time.Time) bool { - ip := Ip{} - copy(ip[:], ipPort[:net.IPv6len]) - v, ok := a[ip] - if !ok { - return false - } - if v.Add(5 * time.Minute).After(now) { //suspended - return true - } else { - return false - } -} - -func (a suspended) AllBlocked() []string { - out := make([]string, 0, len(a)) - for ip := range a { - out = append(out, net.IP(ip[:]).String()) - } - return out -} - -func (a suspended) clear(now time.Time) { - for ip, v := range a { - if v.Add(5 * time.Minute).Before(now) { - delete(a, ip) - } - } -} - -func (a suspended) Block(ip proto.IpPort, d time.Duration) { - a[ipPortToIp(ip)] = time.Now().Add(d) -} - -func ipPortToIp(ipPort proto.IpPort) [net.IPv6len]byte { - ip := Ip{} - copy(ip[:], ipPort[:net.IPv6len]) - return ip -} - -func (a suspended) Len() int { - return len(a) -} - type PeerManagerImpl struct { spawner PeerSpawner active map[peer.Peer]peerInfo mu sync.RWMutex - state PeerStorage + peerStorage PeerStorage spawned map[proto.IpPort]struct{} - suspended suspended connectPeers bool // spawn outgoing limitConnections int version proto.Version } -func NewPeerManager(spawner PeerSpawner, storage PeerStorage, limitConnections int, version proto.Version) *PeerManagerImpl { +func NewPeerManager(spawner PeerSpawner, storage PeerStorage, + limitConnections int, version proto.Version) *PeerManagerImpl { + return &PeerManagerImpl{ spawner: spawner, active: make(map[peer.Peer]peerInfo), - state: storage, + peerStorage: storage, spawned: make(map[proto.IpPort]struct{}), - suspended: suspended{}, connectPeers: true, limitConnections: limitConnections, version: version, @@ -159,11 +114,11 @@ func (a *PeerManagerImpl) Connected(p peer.Peer) (peer.Peer, bool) { func (a *PeerManagerImpl) ConnectedCount() int { a.mu.RLock() defer a.mu.RUnlock() - return a.connectedCount() + return a.unsafeConnectedCount() } // non thread safe -func (a *PeerManagerImpl) connectedCount() int { +func (a *PeerManagerImpl) unsafeConnectedCount() int { return len(a.active) } @@ -183,7 +138,7 @@ func (a *PeerManagerImpl) NewConnection(p peer.Peer) error { a.version.String(), p.Handshake().Version.String(), ) - a.Suspend(p, err.Error()) + a.Suspend(p, time.Now(), err.Error()) _ = p.Close() return proto.NewInfoMsg(err) } @@ -197,7 +152,9 @@ func (a *PeerManagerImpl) NewConnection(p peer.Peer) error { } case peer.Outgoing: if !p.Handshake().DeclaredAddr.Empty() { - _ = a.state.AddKnown(proto.TCPAddr(p.Handshake().DeclaredAddr)) + known := storage.KnownPeer(proto.TCPAddr(p.Handshake().DeclaredAddr).ToIpPort()) + // TODO(nickeskov): maybe log error? + _ = a.peerStorage.AddKnown([]storage.KnownPeer{known}) } if out >= a.limitConnections { _ = p.Close() @@ -211,15 +168,21 @@ func (a *PeerManagerImpl) NewConnection(p peer.Peer) error { return nil } +func (a *PeerManagerImpl) ClearSuspended(now time.Time) { + a.mu.Lock() + defer a.mu.Unlock() + if err := a.peerStorage.RefreshSuspended(now); err != nil { + zap.S().Errorf("failed to clear suspended peers: %v", err) + } +} + func (a *PeerManagerImpl) Run(ctx context.Context) { for { select { case <-ctx.Done(): return case <-time.After(1 * time.Minute): - a.mu.Lock() - a.suspended.clear(time.Now()) - a.mu.Unlock() + a.ClearSuspended(time.Now()) } } } @@ -263,10 +226,11 @@ func (a *PeerManagerImpl) UpdateScore(p peer.Peer, score *big.Int) error { func (a *PeerManagerImpl) IsSuspended(p peer.Peer) bool { a.mu.RLock() defer a.mu.RUnlock() - return a.suspended.Blocked(p.RemoteAddr().ToIpPort(), time.Now()) + ip := storage.IpFromIpPort(p.RemoteAddr().ToIpPort()) + return a.peerStorage.IsSuspendedIP(ip, time.Now()) } -// Count connected peers, +// InOutCount counts connected peers, // in - incoming connections // out - outgoing connections func (a *PeerManagerImpl) InOutCount() (in int, out int) { @@ -282,53 +246,74 @@ func (a *PeerManagerImpl) InOutCount() (in int, out int) { return in, out } -func (a *PeerManagerImpl) Suspend(p peer.Peer, reason string) { +func (a *PeerManagerImpl) Suspend(p peer.Peer, suspendTime time.Time, reason string) { a.Disconnect(p) a.mu.Lock() - a.suspended.Block(p.RemoteAddr().ToIpPort(), 5*time.Minute) - a.mu.Unlock() - zap.S().Debugf("[%s] Suspend peer, reason: %s ", p.ID(), reason) + defer a.mu.Unlock() + suspended := storage.SuspendedPeer{ + IP: storage.IpFromIpPort(p.RemoteAddr().ToIpPort()), + SuspendTimestampMillis: unixMillis(suspendTime), + SuspendDuration: suspendDuration, + Reason: reason, + } + if err := a.peerStorage.AddSuspended([]storage.SuspendedPeer{suspended}); err != nil { + zap.S().Errorf("[%s] Failed to suspend peer, reason %q: %v", p.ID(), reason, err) + } else { + zap.S().Debugf("[%s] Suspend peer, reason: %s ", p.ID(), reason) + } } -func (a *PeerManagerImpl) Suspended() []string { +func (a *PeerManagerImpl) Suspended() []storage.SuspendedPeer { a.mu.RLock() defer a.mu.RUnlock() - return a.suspended.AllBlocked() + return a.peerStorage.Suspended(time.Now()) } -func (a *PeerManagerImpl) AddAddress(ctx context.Context, addr string) { - _ = a.state.Add([]proto.TCPAddr{proto.NewTCPAddrFromString(addr)}) +func (a *PeerManagerImpl) AddAddress(ctx context.Context, addr proto.TCPAddr) error { + known := storage.KnownPeer(addr.ToIpPort()) + if err := a.peerStorage.AddKnown([]storage.KnownPeer{known}); err != nil { + return errors.Wrapf(err, "failed to add addr %q into known peers storage", addr.String()) + } go func() { - if err := a.spawner.SpawnOutgoing(ctx, proto.NewTCPAddrFromString(addr)); err != nil { + if err := a.spawner.SpawnOutgoing(ctx, addr); err != nil { + // TODO(nickeskov): maybe don't remove from known peers in this case? + if removeErr := a.peerStorage.DeleteKnown([]storage.KnownPeer{known}); removeErr != nil { + zap.S().Errorf("Failed to remove peer %q from known peers storage", known.String()) + } zap.S().Debug(err) } }() + return nil } -func (a *PeerManagerImpl) UpdateKnownPeers(known []proto.TCPAddr) error { +func (a *PeerManagerImpl) UpdateKnownPeers(known []storage.KnownPeer) error { if len(known) == 0 { return nil } - return a.state.Add(known) + + if err := a.peerStorage.AddKnown(known); err != nil { + return errors.Wrap(err, "failed to update known peers") + } + return nil } -func (a *PeerManagerImpl) KnownPeers() ([]proto.TCPAddr, error) { - return a.state.Known() +func (a *PeerManagerImpl) KnownPeers() []storage.KnownPeer { + return a.peerStorage.Known() } func (a *PeerManagerImpl) Close() { a.mu.Lock() + defer a.mu.Unlock() for _, v := range a.active { _ = v.peer.Close() } - a.mu.Unlock() } func (a *PeerManagerImpl) SpawnOutgoingConnections(ctx context.Context) { a.mu.Lock() defer a.mu.Unlock() - if a.connectedCount() > a.limitConnections*2 { + if a.unsafeConnectedCount() > a.limitConnections*2 { return } var outCnt int @@ -346,11 +331,7 @@ func (a *PeerManagerImpl) SpawnOutgoingConnections(ctx context.Context) { return } - known, err := a.KnownPeers() - if err != nil { - zap.S().Error(err) - return - } + known := a.KnownPeers() active := map[proto.IpPort]struct{}{} for _, p := range a.active { @@ -363,24 +344,26 @@ func (a *PeerManagerImpl) SpawnOutgoingConnections(ctx context.Context) { } } - for _, addr := range known { - addrIpPort := addr.ToIpPort() - if _, ok := active[addrIpPort]; ok { + for _, knowPeer := range known { + ipPort := knowPeer.IpPort() + if _, ok := active[ipPort]; ok { continue } - if _, ok := a.spawned[addrIpPort]; ok { + if _, ok := a.spawned[ipPort]; ok { continue } - if a.suspended.Blocked(addrIpPort, time.Now()) { + if a.peerStorage.IsSuspendedIP(knowPeer.IP(), time.Now()) { continue } - a.spawned[addr.ToIpPort()] = struct{}{} + a.spawned[ipPort] = struct{}{} - go func(addr proto.TCPAddr) { + go func(ipPort proto.IpPort) { + addr := proto.NewTCPAddr(ipPort.Addr(), ipPort.Port()) defer a.RemoveSpawned(addr) + // TODO(nickeskov): maybe log error? _ = a.spawner.SpawnOutgoing(ctx, addr) - }(addr) + }(ipPort) } } @@ -465,3 +448,7 @@ func (a *PeerManagerImpl) Connect(ctx context.Context, addr proto.TCPAddr) error return nil } + +func unixMillis(now time.Time) int64 { + return now.UnixNano() / 1_000_000 +} diff --git a/pkg/node/peer_manager/peer_manager_test.go b/pkg/node/peer_manager/peer_manager_test.go deleted file mode 100644 index bd8d3f0de..000000000 --- a/pkg/node/peer_manager/peer_manager_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package peer_manager - -import ( - "net" - "testing" - "time" - - "github.com/stretchr/testify/require" - "github.com/wavesplatform/gowaves/pkg/proto" -) - -func TestSuspended_Block(t *testing.T) { - addr := proto.NewTCPAddr(net.IPv4(8, 8, 8, 8), 80).ToIpPort() - - t.Run("check with same port", func(t *testing.T) { - b := suspended{} - require.False(t, b.Blocked(addr, time.Now())) - - b.Block(addr, 5*time.Minute) - - require.True(t, b.Blocked(addr, time.Now())) - require.False(t, b.Blocked(addr, time.Now().Add(10*time.Minute))) - - require.Equal(t, 1, b.Len()) - - b.clear(time.Now().Add(10 * time.Minute)) - require.Equal(t, 0, b.Len()) - }) - - t.Run("check with different ports", func(t *testing.T) { - b := suspended{} - addr2 := proto.NewTCPAddr(net.IPv4(8, 8, 8, 8), 180).ToIpPort() - - b.Block(addr, 5*time.Minute) - - require.True(t, b.Blocked(addr2, time.Now()), "should be suspended, ignore port") - }) -} diff --git a/pkg/node/peer_manager/peer_storage.go b/pkg/node/peer_manager/peer_storage.go index 82f113714..cb909fe58 100644 --- a/pkg/node/peer_manager/peer_storage.go +++ b/pkg/node/peer_manager/peer_storage.go @@ -1,12 +1,23 @@ package peer_manager import ( - "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + "time" ) type PeerStorage interface { - All() ([]proto.TCPAddr, error) - Known() ([]proto.TCPAddr, error) - AddKnown(proto.TCPAddr) error - Add([]proto.TCPAddr) error + Known() []storage.KnownPeer + AddKnown(known []storage.KnownPeer) error + DeleteKnown(known []storage.KnownPeer) error + DropKnown() error + + Suspended(now time.Time) []storage.SuspendedPeer + AddSuspended(suspended []storage.SuspendedPeer) error + IsSuspendedIP(ip storage.IP, now time.Time) bool + IsSuspendedIPs(ips []storage.IP, now time.Time) []bool + DeleteSuspendedByIP(suspended []storage.SuspendedPeer) error + RefreshSuspended(now time.Time) error + DropSuspended() error + + DropStorage() error } diff --git a/pkg/node/peer_manager/peer_storage_test.go b/pkg/node/peer_manager/peer_storage_test.go new file mode 100644 index 000000000..c1bc4268f --- /dev/null +++ b/pkg/node/peer_manager/peer_storage_test.go @@ -0,0 +1,40 @@ +package peer_manager + +import ( + "github.com/golang/mock/gomock" + "github.com/wavesplatform/gowaves/pkg/mock" + "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" + "github.com/wavesplatform/gowaves/pkg/proto" + "testing" + "time" +) + +func TestPeerManagerImpl_Suspend(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + now := time.Now() + tcpAddr := proto.NewTCPAddrFromString("32.34.46.1:4535") + reason := "some-reason" + + p := mock.NewMockPeer(ctrl) + gomock.InOrder( + p.EXPECT().Close(), + p.EXPECT().RemoteAddr().Return(tcpAddr), + p.EXPECT().ID().Return("some-id"), + ) + + peerStorage := mock.NewMockPeerStorage(ctrl) + peerStorage.EXPECT().AddSuspended([]storage.SuspendedPeer{{ + IP: storage.IpFromIpPort(tcpAddr.ToIpPort()), + SuspendTimestampMillis: unixMillis(now), + SuspendDuration: suspendDuration, + Reason: reason, + }}) + + manager := PeerManagerImpl{ + peerStorage: peerStorage, + } + + manager.Suspend(p, now, reason) +} diff --git a/pkg/node/peer_manager/storage/binary.go b/pkg/node/peer_manager/storage/binary.go deleted file mode 100644 index a90b4431d..000000000 --- a/pkg/node/peer_manager/storage/binary.go +++ /dev/null @@ -1,138 +0,0 @@ -package storage - -import ( - "bytes" - "encoding/binary" - "io/ioutil" - "os" - "path" - "sort" - "sync" - - "github.com/wavesplatform/gowaves/pkg/proto" -) - -type Peers []proto.TCPAddr - -func (a Peers) Len() int { return len(a) } -func (a Peers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a Peers) Less(i, j int) bool { return a[i].ToUint64() < a[j].ToUint64() } - -type BinaryStorage struct { - lock sync.Mutex - statePath string - allCache Peers - knownCache Peers -} - -func (a *BinaryStorage) all() string { - known := path.Join(a.statePath, "blocks_storage", "peers_all.dat") - return known -} - -func (a *BinaryStorage) known() string { - known := path.Join(a.statePath, "blocks_storage", "peers_known.dat") - return known -} - -func (a *BinaryStorage) All() ([]proto.TCPAddr, error) { - a.lock.Lock() - defer a.lock.Unlock() - err := a.loadCache(&a.allCache, a.all()) - if err != nil { - return nil, err - } - out := make([]proto.TCPAddr, len(a.allCache)) - copy(out, a.allCache) - return out, nil -} - -func (a *BinaryStorage) loadCache(cache *Peers, file string) error { - if len(*cache) > 0 { - return nil - } - bts, err := ioutil.ReadFile(file) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - var peers Peers - for len(bts) >= 8 { - val := binary.BigEndian.Uint64(bts[:8]) - peers = append(peers, proto.NewTcpAddrFromUint64(val)) - bts = bts[8:] - } - *cache = peers - return nil -} - -func (a *BinaryStorage) Known() ([]proto.TCPAddr, error) { - a.lock.Lock() - defer a.lock.Unlock() - err := a.loadCache(&a.knownCache, a.known()) - if err != nil { - return nil, err - } - out := make([]proto.TCPAddr, len(a.knownCache)) - copy(out, a.knownCache) - return out, nil -} - -func (a *BinaryStorage) AddKnown(new proto.TCPAddr) error { - a.lock.Lock() - defer a.lock.Unlock() - err := a.loadCache(&a.knownCache, a.known()) - if err != nil { - return err - } - a.knownCache = append(a.knownCache, new) - sort.Sort(a.knownCache) - err = a.save(a.known(), a.knownCache) - if err != nil { - return err - } - a.knownCache = nil - return nil -} - -func (a *BinaryStorage) Add(addrs []proto.TCPAddr) error { - a.lock.Lock() - defer a.lock.Unlock() - err := a.loadCache(&a.allCache, a.all()) - if err != nil { - return err - } - a.allCache = append(a.allCache, addrs...) - sort.Sort(a.allCache) - err = a.save(a.all(), a.allCache) - if err != nil { - return err - } - a.allCache = nil - return nil -} - -func (a *BinaryStorage) save(file string, peers Peers) error { - buf := bytes.Buffer{} - prev := uint64(0) - for _, peer := range peers { - cur := peer.ToUint64() - if cur == prev { - continue - } - prev = cur - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, cur) - buf.Write(b) - } - return ioutil.WriteFile(file, buf.Bytes(), 0644) -} - -func NewBinaryStorage(statePath string) *BinaryStorage { - return &BinaryStorage{ - statePath: statePath, - lock: sync.Mutex{}, - } -} diff --git a/pkg/node/peer_manager/storage/binary_test.go b/pkg/node/peer_manager/storage/binary_test.go deleted file mode 100644 index e1f19b114..000000000 --- a/pkg/node/peer_manager/storage/binary_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package storage_test - -import ( - "io/ioutil" - "os" - "path" - "testing" - - "github.com/stretchr/testify/require" - "github.com/wavesplatform/gowaves/pkg/node/peer_manager/storage" - "github.com/wavesplatform/gowaves/pkg/proto" -) - -func TestBinaryStorage_Known(t *testing.T) { - d, err := ioutil.TempDir("", "abc") - require.NoError(t, err) - defer os.RemoveAll(d) - - err = os.Mkdir(path.Join(d, "blocks_storage"), 0755) - require.NoError(t, err) - - s := storage.NewBinaryStorage(d) - known, err := s.Known() - require.NoError(t, err) - require.Len(t, known, 0) - - err = s.AddKnown(proto.NewTCPAddrFromString("127.0.0.1:6868")) - require.NoError(t, err) - - // should return 1 peer - known, err = s.Known() - require.NoError(t, err) - require.Len(t, known, 1) - - // add duplicate peer - err = s.AddKnown(proto.NewTCPAddrFromString("127.0.0.1:6868")) - require.NoError(t, err) - - // should return 1 peer too - known, err = s.Known() - require.NoError(t, err) - require.Len(t, known, 1) -} - -func TestBinaryStorage_All(t *testing.T) { - d, err := ioutil.TempDir("", "all") - require.NoError(t, err) - defer os.RemoveAll(d) - - err = os.Mkdir(path.Join(d, "blocks_storage"), 0755) - require.NoError(t, err) - - s := storage.NewBinaryStorage(d) - known, err := s.All() - require.NoError(t, err) - require.Len(t, known, 0) - - err = s.Add([]proto.TCPAddr{proto.NewTCPAddrFromString("127.0.0.1:6868")}) - require.NoError(t, err) - - // should return 1 peer - known, err = s.All() - require.NoError(t, err) - require.Len(t, known, 1) - - // add duplicate peer - err = s.Add([]proto.TCPAddr{proto.NewTCPAddrFromString("127.0.0.1:6868")}) - require.NoError(t, err) - - // should return 1 peer too - known, err = s.All() - require.NoError(t, err) - require.Len(t, known, 1) -} diff --git a/pkg/node/peer_manager/storage/cbor.go b/pkg/node/peer_manager/storage/cbor.go new file mode 100644 index 000000000..c2aad3779 --- /dev/null +++ b/pkg/node/peer_manager/storage/cbor.go @@ -0,0 +1,411 @@ +package storage + +import ( + "github.com/fxamacker/cbor/v2" + "github.com/pkg/errors" + "io" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" +) + +const ( + peersStorageDir = "peers_storage" +) + +type CBORStorage struct { + rwMutex sync.RWMutex + storageDir string + suspended suspendedPeers + suspendedFilePath string + known knownPeers // nickeskov: list of all ever known peers with a publicly available declared address + knownFilePath string +} + +func NewCBORStorage(baseDir string, now time.Time) (*CBORStorage, error) { + storageDir := filepath.Join(baseDir, peersStorageDir) + return newCBORStorageInDir(storageDir, now) +} + +func newCBORStorageInDir(storageDir string, now time.Time) (*CBORStorage, error) { + if err := os.MkdirAll(storageDir, os.ModePerm); err != nil { + return nil, errors.Wrapf(err, "failed to create peers storage directory %q", storageDir) + } + + knownFile := knownFilePath(storageDir) + if err := createFileIfNotExist(knownFile); err != nil { + return nil, errors.Wrap(err, "failed to create known peers storage file") + } + + suspendedFile := suspendedFilePath(storageDir) + if err := createFileIfNotExist(suspendedFile); err != nil { + return nil, errors.Wrap(err, "failed to create suspended peers storage file") + } + + known := knownPeers{} + if err := unmarshalCborFromFile(knownFile, &known); err != nil && err != io.EOF { + return nil, errors.Wrapf(err, "failed to load known peers from file %q", knownFile) + } + + suspended := suspendedPeers{} + if err := unmarshalCborFromFile(suspendedFile, &suspended); err != nil && err != io.EOF { + return nil, errors.Wrapf(err, "failed to load suspended peers from file %q", suspendedFile) + } + + storage := &CBORStorage{ + storageDir: storageDir, + suspended: suspended, + suspendedFilePath: suspendedFile, + known: known, + knownFilePath: knownFile, + } + + if len(storage.suspended) != 0 { + // nickeskov: remove expired peers + if err := storage.RefreshSuspended(now); err != nil { + return nil, errors.Wrapf(err, + "failed to refresh suspended peers while opening peers storage with path %q", storageDir) + } + } + return storage, nil +} + +func (bs *CBORStorage) Known() []KnownPeer { + bs.rwMutex.RLock() + defer bs.rwMutex.RUnlock() + + known := make([]KnownPeer, 0, len(bs.known)) + for k := range bs.known { + known = append(known, k) + } + return known +} + +// AddKnown adds known peers into peers storage with strong error guarantees. +func (bs *CBORStorage) AddKnown(known []KnownPeer) error { + if len(known) == 0 { + return nil + } + + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + // nickeskov: save old values in backup + backup := bs.unsafeKnownIntersection(known) + // nickeskov: fast path if all known peers already in storage + if len(backup) == len(known) { + return nil + } + + // nickeskov: add new values into known map + for _, k := range known { + bs.known[k] = struct{}{} + } + + if err := bs.unsafeSyncKnown(known, backup); err != nil { + return errors.Wrapf(err, "failed to add known peers") + } + return nil +} + +// DeleteKnown removes known peers from peers storage with strong error guarantees. +func (bs *CBORStorage) DeleteKnown(known []KnownPeer) error { + if len(known) == 0 { + return nil + } + + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + // nickeskov: save old values in backup + backup := bs.unsafeKnownIntersection(known) + // nickeskov: delete entries from known map + for _, k := range known { + delete(bs.known, k) + } + + // nickeskov: newEntries is nil because there no new entries + if err := bs.unsafeSyncKnown(nil, backup); err != nil { + return errors.Wrap(err, "failed to delete known peers") + } + return nil +} + +// DropKnown clear known in memory cache and truncates known peers storage file with strong error guarantee. +func (bs *CBORStorage) DropKnown() error { + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + return bs.unsafeDropKnown() +} + +func (bs *CBORStorage) Suspended(now time.Time) []SuspendedPeer { + bs.rwMutex.RLock() + defer bs.rwMutex.RUnlock() + + suspended := make([]SuspendedPeer, 0, len(bs.suspended)) + for _, s := range bs.suspended { + if s.IsSuspended(now) { + suspended = append(suspended, s) + } + } + return suspended +} + +// AddSuspended adds suspended peers into peers storage with strong error guarantees. +func (bs *CBORStorage) AddSuspended(suspended []SuspendedPeer) error { + if len(suspended) == 0 { + return nil + } + + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + // nickeskov: save old values in backup + backup := bs.unsafeSuspendedIntersection(suspended) + // nickeskov: add new values into suspended map + for _, s := range suspended { + bs.suspended[s.IP] = s + } + + if err := bs.unsafeSyncSuspended(suspended, backup); err != nil { + return errors.Wrap(err, "failed to add suspended peers") + } + return nil +} + +func (bs *CBORStorage) IsSuspendedIP(ip IP, now time.Time) bool { + bs.rwMutex.RLock() + defer bs.rwMutex.RUnlock() + return bs.unsafeIsSuspendedIP(ip, now) +} + +func (bs *CBORStorage) IsSuspendedIPs(ips []IP, now time.Time) []bool { + if len(ips) == 0 { + return nil + } + + bs.rwMutex.RLock() + defer bs.rwMutex.RUnlock() + + isSuspended := make([]bool, 0, len(ips)) + for _, ip := range ips { + isSuspended = append(isSuspended, bs.unsafeIsSuspendedIP(ip, now)) + } + return isSuspended +} + +// DeleteSuspendedByIP removes suspended peers from peers storage with strong error guarantees. +// Note, that only IP field in input parameter will be used. +func (bs *CBORStorage) DeleteSuspendedByIP(suspended []SuspendedPeer) error { + if len(suspended) == 0 { + return nil + } + + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + // nickeskov: save old values in backup + backup := bs.unsafeSuspendedIntersection(suspended) + // nickeskov: delete entries from known map + for _, s := range suspended { + delete(bs.suspended, s.IP) + } + + // nickeskov: newEntries is nil because there no new entries + if err := bs.unsafeSyncSuspended(nil, backup); err != nil { + return errors.Wrap(err, "failed to delete suspended peers") + } + return nil +} + +// RefreshSuspended removes expired peers from suspended peers storage with strong error guarantee. +func (bs *CBORStorage) RefreshSuspended(now time.Time) error { + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + var backup []SuspendedPeer + for _, s := range bs.suspended { + if !s.IsSuspended(now) { + backup = append(backup, s) + delete(bs.suspended, s.IP) + } + } + if len(backup) == 0 { + // nickeskov: peers don't expired + return nil + } + + if err := marshalToCborAndSyncToFile(bs.suspendedFilePath, bs.suspended); err != nil { + // nickeskov: restore previous values into map to eliminate side effects + for _, b := range backup { + bs.suspended[b.IP] = b + } + return errors.Wrap(err, "failed to refresh suspended peers and sync storage") + } + return nil +} + +// DropSuspended clear suspended in memory cache and truncates suspended peers storage file with strong error guarantee. +func (bs *CBORStorage) DropSuspended() error { + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + return bs.unsafeDropSuspended() +} + +// DropStorage clear storage memory cache and truncates storage files. +// In case of error we can loose suspended peers storage file, but honestly it's almost impossible case. +func (bs *CBORStorage) DropStorage() error { + bs.rwMutex.Lock() + defer bs.rwMutex.Unlock() + + suspendedBackup := bs.suspended + if err := bs.unsafeDropSuspended(); err != nil { + return errors.Wrap(err, "failed to drop suspended peers storage") + } + + if err := bs.unsafeDropKnown(); err != nil { + bs.suspended = suspendedBackup + // nickeskov: it's almost impossible case, but if it happens we have inconsistency in suspended peers + // but honestly it's not fatal error + if syncErr := marshalToCborAndSyncToFile(bs.suspendedFilePath, bs.suspended); syncErr != nil { + return errors.Wrapf(err, "failed to sync suspended peers storage from backup: %v", syncErr) + } + return errors.Wrap(err, "failed to drop known peers storage") + } + return nil +} + +func (bs *CBORStorage) unsafeSyncKnown(newEntries, backup []KnownPeer) error { + err := marshalToCborAndSyncToFile(bs.knownFilePath, bs.known) + if err == nil { + return nil + } + // nickeskov: remove known from map to eliminate side effects + for _, k := range newEntries { + delete(bs.known, k) + } + // nickeskov: restore from backup + for _, b := range backup { + bs.known[b] = struct{}{} + } + return errors.Wrap(err, "failed to marshal known peers and sync storage") +} + +func (bs *CBORStorage) unsafeDropKnown() error { + // nickeskov: truncate suspendedStorageFile to zero size + if err := os.Truncate(bs.knownFilePath, 0); err != nil { + return errors.Wrapf(err, "failed to drop known storage file %q", bs.knownFilePath) + } + // nickeskov: clear map + bs.known = knownPeers{} + return nil +} + +func (bs *CBORStorage) unsafeSyncSuspended(newEntries, backup []SuspendedPeer) error { + err := marshalToCborAndSyncToFile(bs.suspendedFilePath, bs.suspended) + if err == nil { + return nil + } + // nickeskov: remove suspended from map to eliminate side effects + for _, s := range newEntries { + delete(bs.suspended, s.IP) + } + // nickeskov: restore from backup + for _, s := range backup { + bs.suspended[s.IP] = s + } + return errors.Wrap(err, "failed to marshal suspended peers and sync storage") +} + +func (bs *CBORStorage) unsafeDropSuspended() error { + // nickeskov: truncate suspendedStorageFile to zero size + if err := os.Truncate(bs.suspendedFilePath, 0); err != nil { + return errors.Wrapf(err, "failed to drop suspended storage file %q", bs.suspendedFilePath) + } + // nickeskov: clear map + bs.suspended = suspendedPeers{} + return nil +} + +// unsafeKnownIntersection returns values from known map which intersects with input values +func (bs *CBORStorage) unsafeKnownIntersection(known []KnownPeer) []KnownPeer { + var intersection []KnownPeer + for _, k := range known { + if _, in := bs.known[k]; in { + intersection = append(intersection, k) + } + } + return intersection +} + +// unsafeSuspendedIntersection returns values from suspended map which intersects with input values +func (bs *CBORStorage) unsafeSuspendedIntersection(suspended []SuspendedPeer) []SuspendedPeer { + var intersection []SuspendedPeer + for _, newSuspended := range suspended { + if storedPeer, in := bs.suspended[newSuspended.IP]; in { + intersection = append(intersection, storedPeer) + } + bs.suspended[newSuspended.IP] = newSuspended + } + return intersection +} + +func (bs *CBORStorage) unsafeIsSuspendedIP(ip IP, now time.Time) bool { + s, in := bs.suspended[ip] + if !in { + return false + } + return s.IsSuspended(now) +} + +func marshalToCborAndSyncToFile(filePath string, value interface{}) error { + data, err := cbor.Marshal(value) + if err != nil { + return errors.Wrapf(err, "failed to marshal %T to CBOR", value) + } + + if err := ioutil.WriteFile(filePath, data, 0644); err != nil { + return errors.Wrapf(err, "failed to write %T in file %q", value, filePath) + } + return nil +} + +// unmarshalCborFromFile read file content and trying unmarshall it into out parameter. It also +// returns error if file is empty. +func unmarshalCborFromFile(filePath string, out interface{}) error { + data, err := ioutil.ReadFile(filePath) + if err != nil { + return errors.Wrapf(err, "failed to read from file with name %q", filePath) + } + + switch err := cbor.Unmarshal(data, out); { + case err == io.EOF: + return io.EOF + case err != nil: + return errors.Wrapf(err, "failed to unmarshall CBOR into %T from file %q", out, filePath) + } + return nil +} + +func knownFilePath(storageDir string) string { + return filepath.Join(storageDir, "peers_known.cbor") +} + +func suspendedFilePath(storageDir string) string { + return filepath.Join(storageDir, "peers_suspended.cbor") +} + +func createFileIfNotExist(path string) (err error) { + knownFile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644) + if err != nil { + return errors.Wrapf(err, "failed to create if not exist file %q", path) + } + defer func() { + if closeErr := knownFile.Close(); closeErr != nil { + err = errors.Wrapf(err, "failed to close file %q", path) + } + }() + return nil +} diff --git a/pkg/node/peer_manager/storage/cbor_test.go b/pkg/node/peer_manager/storage/cbor_test.go new file mode 100644 index 000000000..81ba0e9bd --- /dev/null +++ b/pkg/node/peer_manager/storage/cbor_test.go @@ -0,0 +1,424 @@ +package storage + +import ( + "github.com/fxamacker/cbor/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/wavesplatform/gowaves/pkg/proto" + "io" + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" +) + +func TestMarshalUnmarshalCborFromFile(t *testing.T) { + tmpFile, err := ioutil.TempFile("", "test_marshal_to_cbor_*.cbor") + require.NoError(t, err) + defer func() { + filename := tmpFile.Name() + assert.NoError(t, tmpFile.Close()) + require.NoError(t, os.Remove(filename)) + }() + + expected := SuspendedPeer{ + IP: IPFromString("13.3.4.1"), + SuspendTimestampMillis: time.Now().UnixNano() / 1_000_000, + SuspendDuration: time.Minute * 5, + Reason: "some reason", + } + + err = marshalToCborAndSyncToFile(tmpFile.Name(), &expected) + require.NoError(t, err) + err = tmpFile.Sync() + require.NoError(t, err) + + // nickeskov: check marshalling + actual := SuspendedPeer{} + err = cbor.NewDecoder(tmpFile).Decode(&actual) + require.NoError(t, err) + require.Equal(t, expected, actual) + + // nickeskov: check unmarshalling + err = unmarshalCborFromFile(tmpFile.Name(), &actual) + require.NoError(t, err) + require.Equal(t, expected, actual) + + // nickeskov: check error when file not exist + err = unmarshalCborFromFile(tmpFile.Name()+"_not_exist_", &actual) + assert.Error(t, err) +} + +func TestUnmarshalCborFromEmptyFile(t *testing.T) { + tmpFile, err := ioutil.TempFile("", "peers_storage_test_*.cbor") + require.NoError(t, err) + defer func() { + filename := tmpFile.Name() + assert.NoError(t, tmpFile.Close()) + require.NoError(t, os.Remove(filename)) + }() + + dummy := SuspendedPeer{} + err = unmarshalCborFromFile(tmpFile.Name(), &dummy) + assert.Equal(t, io.EOF, err) +} + +func TestCborMarshalUnmarshalWithEmptyData(t *testing.T) { + tmpFile, err := ioutil.TempFile("", "*.cbor") + require.NoError(t, err) + defer func() { + filename := tmpFile.Name() + assert.NoError(t, tmpFile.Close()) + require.NoError(t, os.Remove(filename)) + }() + + dummy := suspendedPeers{} + err = marshalToCborAndSyncToFile(tmpFile.Name(), dummy) + require.NoError(t, err) + + err = unmarshalCborFromFile(tmpFile.Name(), &dummy) + require.NoError(t, err) +} + +type binaryStorageCborSuite struct { + suite.Suite + storage *CBORStorage + now time.Time +} + +func (s *binaryStorageCborSuite) SetupTest() { + tmpdir, err := ioutil.TempDir("", "peers_storage_test_suite_*") + require.NoError(s.T(), err) + defer func() { + if err != nil { + assert.NoError(s.T(), os.Remove(tmpdir)) + } + }() + now := time.Now() + storage, err := newCBORStorageInDir(tmpdir, now) + require.NoError(s.T(), err) + + s.storage = storage + s.now = now +} + +func (s *binaryStorageCborSuite) TearDownTest() { + tmpdir := s.storage.storageDir + s.storage = nil + require.NoError(s.T(), os.RemoveAll(tmpdir)) +} + +func TestBinaryStorageCborTestSuite(t *testing.T) { + suite.Run(t, new(binaryStorageCborSuite)) +} + +func (s *binaryStorageCborSuite) TestCBORStorageKnown() { + known := []KnownPeer{ + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.3.4.1:2345"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("3.54.1.9:1454"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("23.43.7.43:4234"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("42.54.1.6:54356"))), + } + + check := func(known []KnownPeer) { + var unmarshalled knownPeers + require.NoError(s.T(), unmarshalCborFromFile(s.storage.knownFilePath, &unmarshalled)) + assert.Equal(s.T(), len(known), len(unmarshalled)) + // nickeskov: check that all marshaled data saved in file + for _, expected := range known { + _, in := unmarshalled[expected] + require.True(s.T(), in) + } + + // nickeskov: check that all data saved in cache + cachedKnown := make(knownPeers) + for _, k := range s.storage.Known() { + cachedKnown[k] = struct{}{} + } + + for k := range cachedKnown { + _, in := unmarshalled[k] + require.True(s.T(), in) + } + } + + s.Run("add and get known peers", func() { + // nickeskov: check empty input + require.NoError(s.T(), s.storage.AddKnown(nil)) + // nickeskov: check same input + require.NoError(s.T(), s.storage.AddKnown(known)) + + err := s.storage.AddKnown(known) + require.NoError(s.T(), err) + check(known) + }) + + s.Run("delete and get known peers", func() { + // nickeskov: check empty input + require.NoError(s.T(), s.storage.DeleteKnown(nil)) + + // nickeskov: remove first entry + err := s.storage.DeleteKnown(known[:1]) + require.NoError(s.T(), err) + check(known[1:]) + }) + + s.Run("unsafe sync known peers bad storage file", func() { + defer func(knownStorageFile string) { + require.NoError(s.T(), os.Remove(s.storage.knownFilePath)) + s.storage.knownFilePath = knownStorageFile + }(s.storage.knownFilePath) + + badFilePath := filepath.Join(s.storage.storageDir, "test_invalid_known_storage_file") + f, err := os.OpenFile(badFilePath, os.O_CREATE, 0100) + require.NoError(s.T(), err) + defer func() { + require.NoError(s.T(), f.Chmod(0644)) + require.NoError(s.T(), f.Close()) + }() + + s.storage.knownFilePath = badFilePath + err = s.storage.unsafeSyncKnown(nil, nil) + require.Error(s.T(), err) + }) +} + +func (s *binaryStorageCborSuite) TestCBORStorageSuspended() { + suspendDuration := time.Minute * 5 + now := s.now.Truncate(time.Millisecond) + suspended := []SuspendedPeer{ + { + IP: IPFromString("13.3.4.1"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration, + Reason: "some reason #1", + }, + { + IP: IPFromString("3.54.1.9"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration, + Reason: "some reason #2", + }, + { + IP: IPFromString("23.43.7.43"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration + time.Minute*2, + Reason: "some reason #3", + }, + { + IP: IPFromString("42.54.1.6"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration + time.Minute*2, + Reason: "some reason #4", + }, + } + + check := func(suspended []SuspendedPeer) { + var unmarshalled suspendedPeers + require.NoError(s.T(), unmarshalCborFromFile(s.storage.suspendedFilePath, &unmarshalled)) + assert.Equal(s.T(), len(suspended), len(unmarshalled)) + // nickeskov: check that all marshaled data saved in file + for _, expected := range suspended { + _, in := unmarshalled[expected.IP] + require.True(s.T(), in) + } + + // nickeskov: check that all data saved in cache + cachedSuspended := make(suspendedPeers) + for _, suspendedPeer := range s.storage.Suspended(now) { + cachedSuspended[suspendedPeer.IP] = suspendedPeer + } + + for k := range cachedSuspended { + _, in := unmarshalled[k] + require.True(s.T(), in) + } + } + + s.Run("add and get suspended peers", func() { + // nickeskov: check empty input + require.NoError(s.T(), s.storage.AddSuspended(nil)) + + err := s.storage.AddSuspended(suspended) + require.NoError(s.T(), err) + check(suspended) + }) + + s.Run("ip is suspended", func() { + for _, peer := range suspended { + require.True(s.T(), s.storage.IsSuspendedIP(peer.IP, now)) + } + }) + + s.Run("ips is suspended", func() { + // nickeskov: check empty input + empty := s.storage.IsSuspendedIPs(nil, now) + assert.Empty(s.T(), empty) + + ips := make([]IP, 0, len(suspended)) + for _, peer := range suspended { + ips = append(ips, peer.IP) + } + res := s.storage.IsSuspendedIPs(ips, now.Add(suspendDuration)) + assert.False(s.T(), res[0]) + assert.False(s.T(), res[1]) + assert.True(s.T(), res[2]) + assert.True(s.T(), res[3]) + }) + + s.Run("delete and get suspended peers", func() { + defer func() { + // nickeskov: set previous values + require.NoError(s.T(), s.storage.AddSuspended(suspended)) + }() + + // nickeskov: check empty input + require.NoError(s.T(), s.storage.DeleteSuspendedByIP(nil)) + + // nickeskov: remove first entry + err := s.storage.DeleteSuspendedByIP(suspended[:1]) + require.NoError(s.T(), err) + check(suspended[1:]) + }) + + s.Run("refresh suspended peers", func() { + err := s.storage.RefreshSuspended(now.Add(suspendDuration)) + require.NoError(s.T(), err) + check(suspended[2:]) + }) + + s.Run("new cbor storage with suspended refreshing", func() { + defer func() { + // nickeskov: set previous values + require.NoError(s.T(), s.storage.AddSuspended(suspended)) + }() + + newNow := now.Add(suspendDuration) + storage, err := newCBORStorageInDir(s.storage.storageDir, newNow) + require.NoError(s.T(), err) + s.storage = storage + + testMap := make(suspendedPeers) + for _, peer := range s.storage.Suspended(newNow) { + testMap[peer.IP] = peer + } + + for _, peer := range suspended[2:] { + inMapPeer, in := testMap[peer.IP] + assert.True(s.T(), in) + assert.Equal(s.T(), peer, inMapPeer) + } + }) + + s.Run("unsafe sync suspended peers bad storage file", func() { + defer func(suspendedStorageFile string) { + require.NoError(s.T(), os.Remove(s.storage.suspendedFilePath)) + s.storage.suspendedFilePath = suspendedStorageFile + }(s.storage.suspendedFilePath) + + badFilePath := filepath.Join(s.storage.storageDir, "test_invalid_suspended_storage_file") + f, err := os.OpenFile(badFilePath, os.O_CREATE, 0100) + require.NoError(s.T(), err) + defer func() { + require.NoError(s.T(), f.Chmod(0644)) + require.NoError(s.T(), f.Close()) + }() + + s.storage.suspendedFilePath = badFilePath + err = s.storage.unsafeSyncSuspended(nil, nil) + require.Error(s.T(), err) + }) +} + +func (s *binaryStorageCborSuite) TestCBORStorageDrops() { + suspendDuration := time.Minute * 5 + now := s.now.Truncate(time.Millisecond) + suspended := []SuspendedPeer{ + { + IP: IPFromString("13.3.4.1"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration, + Reason: "some reason #1", + }, + { + IP: IPFromString("3.54.1.9"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration, + Reason: "some reason #2", + }, + { + IP: IPFromString("23.43.7.43"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration + time.Minute*2, + Reason: "some reason #3", + }, + { + IP: IPFromString("42.54.1.6"), + SuspendTimestampMillis: now.UnixNano() / 1_000_000, + SuspendDuration: suspendDuration + time.Minute*2, + Reason: "some reason #4", + }, + } + + known := []KnownPeer{ + // nickeskov: this peers can be found in suspended peers + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.3.4.1:2345"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("3.54.1.9:1454"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("23.43.7.43:4234"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("42.54.1.6:54356"))), + + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.8.4.1:2334"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("3.5.13.91:14554"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("3.43.7.47:4234"))), + KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("4.54.1.65:5356"))), + } + + checkSuspendedStorageFile := func() { + var unmarshalled suspendedPeers + require.Equal(s.T(), io.EOF, unmarshalCborFromFile(s.storage.suspendedFilePath, &unmarshalled)) + require.Empty(s.T(), s.storage.Suspended(now)) + } + + checkKnownStorageFile := func() { + var unmarshalled knownPeers + require.Equal(s.T(), io.EOF, unmarshalCborFromFile(s.storage.knownFilePath, &unmarshalled)) + require.Empty(s.T(), s.storage.Known()) + } + + s.Run("drop suspended peers", func() { + defer func() { + require.NoError(s.T(), s.storage.AddSuspended(suspended)) + }() + + err := s.storage.DropSuspended() + require.NoError(s.T(), err) + + checkSuspendedStorageFile() + }) + + s.Run("drop known peers", func() { + defer func() { + require.NoError(s.T(), s.storage.AddKnown(known)) + }() + + err := s.storage.DropKnown() + require.NoError(s.T(), err) + + checkKnownStorageFile() + }) + + s.Run("drop peers storage", func() { + defer func() { + require.NoError(s.T(), s.storage.AddSuspended(suspended)) + require.NoError(s.T(), s.storage.AddKnown(known)) + }() + + err := s.storage.DropStorage() + require.NoError(s.T(), err) + + checkSuspendedStorageFile() + checkKnownStorageFile() + }) +} diff --git a/pkg/node/peer_manager/storage/types.go b/pkg/node/peer_manager/storage/types.go new file mode 100644 index 000000000..2fbd44001 --- /dev/null +++ b/pkg/node/peer_manager/storage/types.go @@ -0,0 +1,70 @@ +package storage + +import ( + "github.com/wavesplatform/gowaves/pkg/proto" + "net" + "time" +) + +type IP [net.IPv6len]byte + +func (i *IP) String() string { + return net.IP(i[:]).String() +} + +func IPFromString(s string) IP { + parsed := net.ParseIP(s) + ip := IP{} + copy(ip[:], parsed[:net.IPv6len]) + return ip +} + +func IpFromIpPort(ipPort proto.IpPort) IP { + ip := IP{} + copy(ip[:], ipPort[:net.IPv6len]) + return ip +} + +type KnownPeer proto.IpPort + +func (kp *KnownPeer) IP() IP { + return IpFromIpPort(proto.IpPort(*kp)) +} + +func (kp *KnownPeer) IpPort() proto.IpPort { + return proto.IpPort(*kp) +} + +func (kp *KnownPeer) String() string { + ipPort := kp.IpPort() + return ipPort.String() +} + +type SuspendedPeer struct { + IP IP `cbor:"0,keyasint,omitemtpy"` + SuspendTimestampMillis int64 `cbor:"1,keyasint,omitemtpy"` + SuspendDuration time.Duration `cbor:"2,keyasint,omitemtpy"` + Reason string `cbor:"3,keyasint,omitemtpy"` +} + +func (sp *SuspendedPeer) SuspendTime() time.Time { + return fromUnixMillis(sp.SuspendTimestampMillis) +} + +func (sp *SuspendedPeer) AwakeTime() time.Time { + return sp.SuspendTime().Add(sp.SuspendDuration) +} + +func (sp *SuspendedPeer) IsSuspended(now time.Time) bool { + awakeTime := sp.AwakeTime() + return awakeTime.After(now) +} + +type suspendedPeers map[IP]SuspendedPeer +type knownPeers map[KnownPeer]struct{} + +func fromUnixMillis(timestampMillis int64) time.Time { + sec := timestampMillis / 1_000 + nsec := (timestampMillis % 1_000) * 1_000_000 + return time.Unix(sec, nsec) +} diff --git a/pkg/node/peer_manager/storage/types_test.go b/pkg/node/peer_manager/storage/types_test.go new file mode 100644 index 000000000..eb2786c59 --- /dev/null +++ b/pkg/node/peer_manager/storage/types_test.go @@ -0,0 +1,37 @@ +package storage + +import ( + "github.com/stretchr/testify/require" + "github.com/wavesplatform/gowaves/pkg/proto" + "testing" + "time" +) + +func TestFromUnixMillis(t *testing.T) { + ts := time.Now().Truncate(time.Millisecond) + tsMillis := ts.UnixNano() / 1_000_000 + + require.Equal(t, ts.String(), fromUnixMillis(tsMillis).String()) +} + +func TestIpFromIpPort(t *testing.T) { + ip := IpFromIpPort(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.3.4.1:2345"))) + require.Equal(t, "13.3.4.1", ip.String()) +} + +func TestIPFromString(t *testing.T) { + ip := IPFromString("13.3.4.1") + require.Equal(t, "13.3.4.1", ip.String()) +} + +func TestKnownPeerIP(t *testing.T) { + k := KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.3.4.1:2345"))) + ip := k.IP() + require.Equal(t, "13.3.4.1", ip.String()) +} + +func TestKnownPeer_IpPort(t *testing.T) { + k := KnownPeer(proto.NewIpPortFromTcpAddr(proto.NewTCPAddrFromString("13.3.4.1:2345"))) + ipPort := k.IpPort() + require.Equal(t, ipPort.String(), k.String()) +} diff --git a/pkg/node/state_fsm/fsm.go b/pkg/node/state_fsm/fsm.go index ccca39a1c..63ec1b7d0 100644 --- a/pkg/node/state_fsm/fsm.go +++ b/pkg/node/state_fsm/fsm.go @@ -85,17 +85,15 @@ type FSM interface { Block(p peer.Peer, block *proto.Block) (FSM, Async, error) MinedBlock(block *proto.Block, limits proto.MiningLimits, keyPair proto.KeyPair, vrf []byte) (FSM, Async, error) - // Received signatures after asking by GetSignatures + // BlockIDs receives signatures that was requested by GetSignatures BlockIDs(peer.Peer, []proto.BlockID) (FSM, Async, error) Task(task AsyncTask) (FSM, Async, error) - // micro MicroBlock(p peer.Peer, micro *proto.MicroBlock) (FSM, Async, error) MicroBlockInv(p peer.Peer, inv *proto.MicroBlockInv) (FSM, Async, error) Transaction(p peer.Peer, t proto.Transaction) (FSM, Async, error) - // Halt() (FSM, Async, error) } diff --git a/pkg/node/state_fsm/fsm_ng.go b/pkg/node/state_fsm/fsm_ng.go index a1eb3820d..46f4b3ae7 100644 --- a/pkg/node/state_fsm/fsm_ng.go +++ b/pkg/node/state_fsm/fsm_ng.go @@ -155,7 +155,7 @@ func (a *NGFsm) BlockIDs(_ peer.Peer, _ []proto.BlockID) (FSM, Async, error) { return noop(a) } -// MicroBlock handles new microblock received from the network. +// MicroBlock handles new microblock message. func (a *NGFsm) MicroBlock(p peer.Peer, micro *proto.MicroBlock) (FSM, Async, error) { metrics.FSMMicroBlockReceived("ng", micro, p.Handshake().NodeName) block, err := a.checkAndAppendMicroblock(micro) // the TopBlock() is used here diff --git a/pkg/node/state_fsm/fsm_sync.go b/pkg/node/state_fsm/fsm_sync.go index 84267f895..fc6d227fa 100644 --- a/pkg/node/state_fsm/fsm_sync.go +++ b/pkg/node/state_fsm/fsm_sync.go @@ -184,7 +184,7 @@ func (a *SyncFsm) applyBlocks(baseInfo BaseInfo, conf conf, internal sync_intern }) if err != nil { if errs.IsValidationError(err) || errs.IsValidationError(errors.Cause(err)) { - a.baseInfo.peers.Suspend(conf.peerSyncWith, err.Error()) + a.baseInfo.peers.Suspend(conf.peerSyncWith, time.Now(), err.Error()) } for _, b := range blocks { metrics.FSMKeyBlockDeclined("sync", b, err) diff --git a/pkg/node/state_fsm/tasks/tasks.go b/pkg/node/state_fsm/tasks/tasks.go index da76d019b..19855614c 100644 --- a/pkg/node/state_fsm/tasks/tasks.go +++ b/pkg/node/state_fsm/tasks/tasks.go @@ -15,7 +15,7 @@ const ( PersistComplete ) -// Sends task into channel with overflow check. +// SendAsyncTask sends task into channel with overflow check. func SendAsyncTask(output chan AsyncTask, task AsyncTask) { select { case output <- task: diff --git a/pkg/p2p/peer/handle.go b/pkg/p2p/peer/handle.go index 3da477339..675e14722 100644 --- a/pkg/p2p/peer/handle.go +++ b/pkg/p2p/peer/handle.go @@ -55,7 +55,7 @@ type HandlerParams struct { DuplicateChecker DuplicateChecker } -// for Handle doesn't matter outgoing or incoming Connection, it just send and receive messages +// Handle sends and receives messages no matter outgoing or incoming connection. func Handle(params HandlerParams) error { for { select { diff --git a/pkg/proto/errors.go b/pkg/proto/errors.go index dafe31cf0..f7cb95c3d 100644 --- a/pkg/proto/errors.go +++ b/pkg/proto/errors.go @@ -11,10 +11,7 @@ func NewInfoMsg(err error) error { } func (im *InfoMsg) Error() string { - if !im.IsNil() { - return im.err.Error() - } - return "" + return im.err.Error() } func (im *InfoMsg) IsNil() bool { diff --git a/pkg/proto/lease.go b/pkg/proto/lease.go new file mode 100644 index 000000000..33bebe711 --- /dev/null +++ b/pkg/proto/lease.go @@ -0,0 +1,8 @@ +package proto + +type LeaseInfo struct { + IsActive bool + LeaseAmount uint64 + Recipient Address + Sender Address +} diff --git a/pkg/proto/microblock.go b/pkg/proto/microblock.go index 779221390..f8aead661 100644 --- a/pkg/proto/microblock.go +++ b/pkg/proto/microblock.go @@ -320,7 +320,7 @@ func (a *MicroBlockInvMessage) MarshalBinary() ([]byte, error) { return out, nil } -// ?? total block sig or id +// MicroBlockRequestMessage total block signature or ID. type MicroBlockRequestMessage struct { TotalBlockSig []byte } diff --git a/pkg/proto/proto.go b/pkg/proto/proto.go index d09d4c131..f492eb7cc 100644 --- a/pkg/proto/proto.go +++ b/pkg/proto/proto.go @@ -185,7 +185,7 @@ func (a Version) Cmp(other Version) int { return 0 } -// Compare minor version. +// CmpMinor compares minor version. // If equal return 0. // If diff only 1 version (for example 1.14 and 1.13), then 1 // If more then 1 version, then return 2. @@ -340,7 +340,7 @@ func (a TCPAddr) WriteTo(w io.Writer) (int64, error) { return int64(n + n2), nil } -// ToStaticSize converts TCPAddr to 8-byte array. +// ToUint64 converts TCPAddr to uint64 number. func (a TCPAddr) ToUint64() uint64 { ip := uint64(a.ipToUint32()) << 32 ip = ip | uint64(a.Port) @@ -501,7 +501,7 @@ func (a U8String) MarshalBinary() ([]byte, error) { return data, nil } -// MarshalBinary encodes U8String to binary form +// WriteTo writes U8String into io.Writer w in binary form. func (a U8String) WriteTo(w io.Writer) (int64, error) { l := len(a.S) if l > 255 { diff --git a/pkg/proto/protobuf_converters.go b/pkg/proto/protobuf_converters.go index 551019c50..8df47b91e 100644 --- a/pkg/proto/protobuf_converters.go +++ b/pkg/proto/protobuf_converters.go @@ -591,6 +591,46 @@ func (c *ProtobufConverter) SponsorshipScriptActions(sponsorships []*g.InvokeScr return res, nil } +func (c *ProtobufConverter) LeaseScriptActions(scheme byte, leases []*g.InvokeScriptResult_Lease) ([]*LeaseScriptAction, error) { + if c.err != nil { + return nil, c.err + } + res := make([]*LeaseScriptAction, len(leases)) + for i, x := range leases { + rcp, err := c.Recipient(scheme, x.Recipient) + if err != nil { + c.err = err + return nil, err + } + res[i] = &LeaseScriptAction{ + ID: c.digest(x.LeaseId), + Recipient: rcp, + Amount: x.Amount, + Nonce: x.Nonce, + } + if c.err != nil { + return nil, c.err + } + } + return res, nil +} + +func (c *ProtobufConverter) LeaseCancelScriptActions(cancels []*g.InvokeScriptResult_LeaseCancel) ([]*LeaseCancelScriptAction, error) { + if c.err != nil { + return nil, c.err + } + res := make([]*LeaseCancelScriptAction, len(cancels)) + for i, x := range cancels { + res[i] = &LeaseCancelScriptAction{ + LeaseID: c.digest(x.LeaseId), + } + if c.err != nil { + return nil, c.err + } + } + return res, nil +} + func (c *ProtobufConverter) ErrorMessage(msg *g.InvokeScriptResult_ErrorMessage) (*ScriptErrorMessage, error) { if c.err != nil { return nil, c.err diff --git a/pkg/proto/scripting.go b/pkg/proto/scripting.go index fd744a59d..b93eed2f5 100644 --- a/pkg/proto/scripting.go +++ b/pkg/proto/scripting.go @@ -13,21 +13,28 @@ import ( // ScriptAction common interface of script invocation actions. type ScriptAction interface { scriptAction() + SenderPK() *crypto.PublicKey } // DataEntryScriptAction is an action to manipulate account data state. type DataEntryScriptAction struct { - Entry DataEntry + Sender *crypto.PublicKey + Entry DataEntry } func (a DataEntryScriptAction) scriptAction() {} +func (a DataEntryScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *DataEntryScriptAction) ToProtobuf() *g.DataTransactionData_DataEntry { return a.Entry.ToProtobuf() } // TransferScriptAction is an action to emit transfer of asset. type TransferScriptAction struct { + Sender *crypto.PublicKey Recipient Recipient Amount int64 Asset OptionalAsset @@ -35,6 +42,10 @@ type TransferScriptAction struct { func (a TransferScriptAction) scriptAction() {} +func (a TransferScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *TransferScriptAction) ToProtobuf() (*g.InvokeScriptResult_Payment, error) { amount := &g.Amount{ AssetId: a.Asset.ToID(), @@ -49,6 +60,7 @@ func (a *TransferScriptAction) ToProtobuf() (*g.InvokeScriptResult_Payment, erro // IssueScriptAction is an action to issue a new asset as a result of script invocation. type IssueScriptAction struct { + Sender *crypto.PublicKey ID crypto.Digest // calculated field Name string // name Description string // description @@ -61,6 +73,10 @@ type IssueScriptAction struct { func (a IssueScriptAction) scriptAction() {} +func (a IssueScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *IssueScriptAction) ToProtobuf() *g.InvokeScriptResult_Issue { return &g.InvokeScriptResult_Issue{ AssetId: a.ID.Bytes(), @@ -102,6 +118,7 @@ func GenerateIssueScriptActionID(name, description string, decimals, quantity in // ReissueScriptAction is an action to emit Reissue transaction as a result of script invocation. type ReissueScriptAction struct { + Sender *crypto.PublicKey AssetID crypto.Digest // assetId Quantity int64 // quantity Reissuable bool // isReissuable @@ -109,6 +126,10 @@ type ReissueScriptAction struct { func (a ReissueScriptAction) scriptAction() {} +func (a ReissueScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *ReissueScriptAction) ToProtobuf() *g.InvokeScriptResult_Reissue { return &g.InvokeScriptResult_Reissue{ AssetId: a.AssetID.Bytes(), @@ -119,12 +140,17 @@ func (a *ReissueScriptAction) ToProtobuf() *g.InvokeScriptResult_Reissue { // BurnScriptAction is an action to burn some assets in response to script invocation. type BurnScriptAction struct { + Sender *crypto.PublicKey AssetID crypto.Digest // assetId Quantity int64 // quantity } func (a BurnScriptAction) scriptAction() {} +func (a BurnScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *BurnScriptAction) ToProtobuf() *g.InvokeScriptResult_Burn { return &g.InvokeScriptResult_Burn{ AssetId: a.AssetID.Bytes(), @@ -134,12 +160,17 @@ func (a *BurnScriptAction) ToProtobuf() *g.InvokeScriptResult_Burn { // SponsorshipScriptAction is an action to set sponsorship for given asset in response to script invocation. type SponsorshipScriptAction struct { + Sender *crypto.PublicKey AssetID crypto.Digest // assetId MinFee int64 // minSponsoredAssetFee } func (a SponsorshipScriptAction) scriptAction() {} +func (a SponsorshipScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + func (a *SponsorshipScriptAction) ToProtobuf() *g.InvokeScriptResult_SponsorFee { return &g.InvokeScriptResult_SponsorFee{ MinFee: &g.Amount{ @@ -149,6 +180,74 @@ func (a *SponsorshipScriptAction) ToProtobuf() *g.InvokeScriptResult_SponsorFee } } +// LeaseScriptAction is an action to lease Waves to given account. +type LeaseScriptAction struct { + Sender *crypto.PublicKey + ID crypto.Digest + Recipient Recipient + Amount int64 + Nonce int64 +} + +func (a LeaseScriptAction) scriptAction() {} + +func (a LeaseScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + +func (a *LeaseScriptAction) ToProtobuf() (*g.InvokeScriptResult_Lease, error) { + rcp, err := a.Recipient.ToProtobuf() + if err != nil { + return nil, err + } + return &g.InvokeScriptResult_Lease{ + Recipient: rcp, + Amount: a.Amount, + Nonce: a.Nonce, + LeaseId: a.ID.Bytes(), + }, nil +} + +// GenerateLeaseScriptActionID implements ID generation used in RIDE to create new ID for a Lease action. +func GenerateLeaseScriptActionID(recipient Recipient, amount int64, nonce int64, txID crypto.Digest) crypto.Digest { + rl := AddressSize + if recipient.Alias != nil { + rl = 4 + len(recipient.Alias.Alias) + } + buf := make([]byte, rl+crypto.DigestSize+8+8) + pos := 0 + if recipient.Alias != nil { + PutStringWithUInt32Len(buf[pos:], recipient.Alias.Alias) + } else { + copy(buf[pos:], recipient.Address[:]) + } + pos += rl + copy(buf[pos:], txID[:]) + pos += crypto.DigestSize + binary.BigEndian.PutUint64(buf[pos:], uint64(nonce)) + pos += 8 + binary.BigEndian.PutUint64(buf[pos:], uint64(amount)) + return crypto.MustFastHash(buf) +} + +// LeaseCancelScriptAction is an action that cancels previously created lease. +type LeaseCancelScriptAction struct { + Sender *crypto.PublicKey + LeaseID crypto.Digest +} + +func (a *LeaseCancelScriptAction) scriptAction() {} + +func (a LeaseCancelScriptAction) SenderPK() *crypto.PublicKey { + return a.Sender +} + +func (a *LeaseCancelScriptAction) ToProtobuf() *g.InvokeScriptResult_LeaseCancel { + return &g.InvokeScriptResult_LeaseCancel{ + LeaseId: a.LeaseID.Bytes(), + } +} + type ScriptErrorMessage struct { Code TxFailureReason Text string @@ -168,6 +267,8 @@ type ScriptResult struct { Reissues []*ReissueScriptAction Burns []*BurnScriptAction Sponsorships []*SponsorshipScriptAction + Leases []*LeaseScriptAction + LeaseCancels []*LeaseCancelScriptAction ErrorMsg ScriptErrorMessage } @@ -179,6 +280,8 @@ func NewScriptResult(actions []ScriptAction, msg ScriptErrorMessage) (*ScriptRes reissues := make([]*ReissueScriptAction, 0) burns := make([]*BurnScriptAction, 0) sponsorships := make([]*SponsorshipScriptAction, 0) + leases := make([]*LeaseScriptAction, 0) + leaseCancels := make([]*LeaseCancelScriptAction, 0) for _, a := range actions { switch ta := a.(type) { case *DataEntryScriptAction: @@ -193,6 +296,10 @@ func NewScriptResult(actions []ScriptAction, msg ScriptErrorMessage) (*ScriptRes burns = append(burns, ta) case *SponsorshipScriptAction: sponsorships = append(sponsorships, ta) + case *LeaseScriptAction: + leases = append(leases, ta) + case *LeaseCancelScriptAction: + leaseCancels = append(leaseCancels, ta) default: return nil, errors.Errorf("unsupported action type '%T'", a) } @@ -204,6 +311,8 @@ func NewScriptResult(actions []ScriptAction, msg ScriptErrorMessage) (*ScriptRes Reissues: reissues, Burns: burns, Sponsorships: sponsorships, + Leases: leases, + LeaseCancels: leaseCancels, ErrorMsg: msg, }, nil } @@ -237,6 +346,17 @@ func (sr *ScriptResult) ToProtobuf() (*g.InvokeScriptResult, error) { for i := range sr.Sponsorships { sponsorships[i] = sr.Sponsorships[i].ToProtobuf() } + leases := make([]*g.InvokeScriptResult_Lease, len(sr.Leases)) + for i := range sr.Leases { + leases[i], err = sr.Leases[i].ToProtobuf() + if err != nil { + return nil, err + } + } + leaseCancels := make([]*g.InvokeScriptResult_LeaseCancel, len(sr.LeaseCancels)) + for i := range sr.LeaseCancels { + leaseCancels[i] = sr.LeaseCancels[i].ToProtobuf() + } return &g.InvokeScriptResult{ Data: data, Transfers: transfers, @@ -244,6 +364,8 @@ func (sr *ScriptResult) ToProtobuf() (*g.InvokeScriptResult, error) { Reissues: reissues, Burns: burns, SponsorFees: sponsorships, + Leases: leases, + LeaseCancels: leaseCancels, ErrorMessage: sr.ErrorMsg.ToProtobuf(), }, nil } @@ -283,6 +405,14 @@ func (sr *ScriptResult) FromProtobuf(scheme byte, msg *g.InvokeScriptResult) err if err != nil { return err } + sr.Leases, err = c.LeaseScriptActions(scheme, msg.Leases) + if err != nil { + return err + } + sr.LeaseCancels, err = c.LeaseCancelScriptActions(msg.LeaseCancels) + if err != nil { + return err + } errMsg, err := c.ErrorMessage(msg.ErrorMessage) if err != nil { return err @@ -295,9 +425,15 @@ type ActionsValidationRestrictions struct { DisableSelfTransfers bool ScriptAddress Address KeySizeValidationVersion byte + Scheme byte +} + +func getMaxScriptActions(libVersion int) int { + maxScriptActionInstance := NewMaxScriptActions() + return maxScriptActionInstance.GetMaxScriptsComplexityInBlock(libVersion) } -func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestrictions) error { +func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestrictions, libVersion int) error { dataEntriesCount := 0 dataEntriesSize := 0 otherActionsCount := 0 @@ -305,26 +441,28 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr switch ta := a.(type) { case *DataEntryScriptAction: dataEntriesCount++ - if dataEntriesCount > maxDataEntryScriptActions { - return errors.Errorf("number of data entries produced by script is more than allowed %d", maxDataEntryScriptActions) + if dataEntriesCount > MaxDataEntryScriptActions { + return errors.Errorf("number of data entries produced by script is more than allowed %d", MaxDataEntryScriptActions) } switch restrictions.KeySizeValidationVersion { case 1: - if len(utf16.Encode([]rune(ta.Entry.GetKey()))) > maxKeySize { + if len(utf16.Encode([]rune(ta.Entry.GetKey()))) > MaxKeySize { return errs.NewTooBigArray("key is too large") } default: - if len([]byte(ta.Entry.GetKey())) > maxPBKeySize { + if len([]byte(ta.Entry.GetKey())) > MaxPBKeySize { return errs.NewTooBigArray("key is too large") } } dataEntriesSize += ta.Entry.BinarySize() - if dataEntriesSize > maxDataEntryScriptActionsSizeInBytes { - return errors.Errorf("total size of data entries produced by script is more than %d bytes", maxDataEntryScriptActionsSizeInBytes) + if dataEntriesSize > MaxDataEntryScriptActionsSizeInBytes { + return errors.Errorf("total size of data entries produced by script is more than %d bytes", MaxDataEntryScriptActionsSizeInBytes) } case *TransferScriptAction: otherActionsCount++ + + maxScriptActions := getMaxScriptActions(libVersion) if otherActionsCount > maxScriptActions { return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) } @@ -332,31 +470,41 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr return errors.New("negative transfer amount") } if restrictions.DisableSelfTransfers { - if ta.Recipient.Address.Eq(restrictions.ScriptAddress) { + senderAddress := restrictions.ScriptAddress + if ta.SenderPK() != nil { + var err error + senderAddress, err = NewAddressFromPublicKey(restrictions.Scheme, *ta.SenderPK()) + if err != nil { + return errors.Wrap(err, "failed to validate TransferScriptAction") + } + } + if ta.Recipient.Address.Eq(senderAddress) { return errors.New("transfers to DApp itself are forbidden since activation of RIDE V4") } } case *IssueScriptAction: otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) if otherActionsCount > maxScriptActions { return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) } if ta.Quantity < 0 { return errors.New("negative quantity") } - if ta.Decimals < 0 || ta.Decimals > maxDecimals { + if ta.Decimals < 0 || ta.Decimals > MaxDecimals { return errors.New("invalid decimals") } - if l := len(ta.Name); l < minAssetNameLen || l > maxAssetNameLen { + if l := len(ta.Name); l < MinAssetNameLen || l > MaxAssetNameLen { return errors.New("invalid asset's name") } - if l := len(ta.Description); l > maxDescriptionLen { + if l := len(ta.Description); l > MaxDescriptionLen { return errors.New("invalid asset's description") } case *ReissueScriptAction: otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) if otherActionsCount > maxScriptActions { return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) } @@ -366,6 +514,7 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr case *BurnScriptAction: otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) if otherActionsCount > maxScriptActions { return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) } @@ -375,6 +524,7 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr case *SponsorshipScriptAction: otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) if otherActionsCount > maxScriptActions { return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) } @@ -382,6 +532,34 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr return errors.New("negative minimal fee") } + case *LeaseScriptAction: + otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) + if otherActionsCount > maxScriptActions { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) + } + if ta.Amount < 0 { + return errors.New("negative leasing amount") + } + senderAddress := restrictions.ScriptAddress + if ta.SenderPK() != nil { + var err error + senderAddress, err = NewAddressFromPublicKey(restrictions.Scheme, *ta.SenderPK()) + if err != nil { + return errors.Wrap(err, "failed to validate TransferScriptAction") + } + } + if ta.Recipient.Address.Eq(senderAddress) { + return errors.New("leasing to DApp itself is forbidden") + } + + case *LeaseCancelScriptAction: + otherActionsCount++ + maxScriptActions := getMaxScriptActions(libVersion) + if otherActionsCount > maxScriptActions { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptActions) + } + default: return errors.Errorf("unsupported script action type '%T'", a) } diff --git a/pkg/proto/scripting_test.go b/pkg/proto/scripting_test.go index 62ba0c1d8..81c27f6c2 100644 --- a/pkg/proto/scripting_test.go +++ b/pkg/proto/scripting_test.go @@ -6,9 +6,10 @@ import ( "strings" "testing" + "github.com/wavesplatform/gowaves/pkg/crypto" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/wavesplatform/gowaves/pkg/crypto" g "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" pb "google.golang.org/protobuf/proto" ) @@ -29,18 +30,20 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { emptyReissues := make([]*ReissueScriptAction, 0) emptyBurns := make([]*BurnScriptAction, 0) emptySponsorships := make([]*SponsorshipScriptAction, 0) + emptyLeases := make([]*LeaseScriptAction, 0) + emptyLeaseCancels := make([]*LeaseCancelScriptAction, 0) for i, test := range []ScriptResult{ { DataEntries: []*DataEntryScriptAction{ - {&IntegerDataEntry{"some key", 12345}}, - {&BooleanDataEntry{"negative value", false}}, - {&StringDataEntry{"some key", "some value string"}}, - {&BinaryDataEntry{Key: "k3", Value: []byte{0x24, 0x7f, 0x71, 0x14, 0x1d}}}, - {&IntegerDataEntry{"some key2", -12345}}, - {&BooleanDataEntry{"negative value2", true}}, - {&StringDataEntry{"some key143", "some value2 string"}}, - {&BinaryDataEntry{Key: "k5", Value: []byte{0x24, 0x7f, 0x71, 0x10, 0x1d}}}, - {&DeleteDataEntry{Key: "xxx"}}, + {Entry: &IntegerDataEntry{"some key", 12345}}, + {Entry: &BooleanDataEntry{"negative value", false}}, + {Entry: &StringDataEntry{"some key", "some value string"}}, + {Entry: &BinaryDataEntry{Key: "k3", Value: []byte{0x24, 0x7f, 0x71, 0x14, 0x1d}}}, + {Entry: &IntegerDataEntry{"some key2", -12345}}, + {Entry: &BooleanDataEntry{"negative value2", true}}, + {Entry: &StringDataEntry{"some key143", "some value2 string"}}, + {Entry: &BinaryDataEntry{Key: "k5", Value: []byte{0x24, 0x7f, 0x71, 0x10, 0x1d}}}, + {Entry: &DeleteDataEntry{Key: "xxx"}}, }, Transfers: []*TransferScriptAction{ {Amount: math.MaxInt64, Asset: *waves, Recipient: rcp}, @@ -52,16 +55,20 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { Reissues: emptyReissues, Burns: emptyBurns, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: []*DataEntryScriptAction{ - {&IntegerDataEntry{"some key", 12345}}, + {Entry: &IntegerDataEntry{"some key", 12345}}, }, Transfers: emptyTransfers, Issues: emptyIssues, Reissues: emptyReissues, Burns: emptyBurns, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: emptyDataEntries, @@ -74,6 +81,8 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { Reissues: emptyReissues, Burns: emptyBurns, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: emptyDataEntries, @@ -85,6 +94,8 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { Reissues: emptyReissues, Burns: emptyBurns, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: emptyDataEntries, @@ -99,6 +110,8 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { }, Burns: emptyBurns, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: emptyDataEntries, @@ -113,6 +126,8 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { {AssetID: asset0.ID, Quantity: 0}, }, Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, }, { DataEntries: emptyDataEntries, @@ -124,6 +139,44 @@ func TestScriptResultBinaryRoundTrip(t *testing.T) { {AssetID: asset0.ID, MinFee: 12345}, {AssetID: asset1.ID, MinFee: 0}, }, + Leases: emptyLeases, + LeaseCancels: emptyLeaseCancels, + }, + { + DataEntries: emptyDataEntries, + Transfers: emptyTransfers, + Issues: emptyIssues, + Reissues: emptyReissues, + Burns: emptyBurns, + Sponsorships: emptySponsorships, + Leases: []*LeaseScriptAction{ + { + ID: asset0.ID, + Recipient: rcp, + Amount: 12345, + Nonce: 67890, + }, + { + ID: asset1.ID, + Recipient: rcp, + Amount: 0, + Nonce: 0, + }, + }, + LeaseCancels: emptyLeaseCancels, + }, + { + DataEntries: emptyDataEntries, + Transfers: emptyTransfers, + Issues: emptyIssues, + Reissues: emptyReissues, + Burns: emptyBurns, + Sponsorships: emptySponsorships, + Leases: emptyLeases, + LeaseCancels: []*LeaseCancelScriptAction{ + {LeaseID: asset0.ID}, + {LeaseID: asset1.ID}, + }, }, } { if msg, err := test.ToProtobuf(); assert.NoError(t, err) { @@ -170,8 +223,15 @@ func TestActionsValidation(t *testing.T) { &DataEntryScriptAction{Entry: &DeleteDataEntry{Key: "xxx"}}, &TransferScriptAction{Recipient: rcp0, Amount: 100, Asset: OptionalAsset{}}, }, restrictions: ActionsValidationRestrictions{DisableSelfTransfers: true, ScriptAddress: addr0}, valid: false}, + {actions: []ScriptAction{ + &LeaseScriptAction{Recipient: rcp0, Amount: 100}, + }, restrictions: ActionsValidationRestrictions{ScriptAddress: addr0}, valid: false}, + {actions: []ScriptAction{ + &LeaseScriptAction{Recipient: rcp0, Amount: 0}, + &LeaseScriptAction{Recipient: rcp0, Amount: -100}, + }, restrictions: ActionsValidationRestrictions{}, valid: false}, } { - err := ValidateActions(test.actions, test.restrictions) + err := ValidateActions(test.actions, test.restrictions, 5) if test.valid { require.NoError(t, err, fmt.Sprintf("#%d", i)) } else { @@ -180,6 +240,34 @@ func TestActionsValidation(t *testing.T) { } } +func TestGenerateLeaseScriptActionID(t *testing.T) { + for _, test := range []struct { + recipient Recipient + amount int64 + nonce int64 + tx crypto.Digest + id string + }{ + {mustRecipientFromString("3Me8JF8fhugSSa2Kx4w7v2tX377sTVtKSU5"), 100000000, 0, crypto.MustDigestFromBase58("3JGcEMaASHc7zcJwpkuFTU3WScKtMU6KDQ5KFr53GQhV"), "HrvHDiegqPhcoKamTeTsNUcQiFot8D1KqyBirsEuCMG9"}, + {mustRecipientFromString("3Me8JF8fhugSSa2Kx4w7v2tX377sTVtKSU5"), 100000000, 0, crypto.MustDigestFromBase58("45R9UJrmCmZu1HtofbHyEmaFr2r1u5xXThGmESszVuFV"), "28yGDS82NrYBC1B4XTVYbwWpJyW7JPYTX7UtVQd1Prkw"}, + {mustRecipientFromString("3Me8JF8fhugSSa2Kx4w7v2tX377sTVtKSU5"), 50000000, 0, crypto.MustDigestFromBase58("45R9UJrmCmZu1HtofbHyEmaFr2r1u5xXThGmESszVuFV"), "GmqQBZPPAHb1u7mQJ8vVp89mcaii23jAyrbDfqYiGo6U"}, + {mustRecipientFromString("3Me8JF8fhugSSa2Kx4w7v2tX377sTVtKSU5"), 100000000, 0, crypto.MustDigestFromBase58("FBmMUrQ5GXun9LrGtHPcJYWSkkfToMReux14iSb2zf4c"), "5PmSmWMmCGh7zjf8SgvzmrUZrEKVeNL2wK12p7Y3Rezi"}, + {mustRecipientFromString("3Me8JF8fhugSSa2Kx4w7v2tX377sTVtKSU5"), 50000000, 0, crypto.MustDigestFromBase58("FBmMUrQ5GXun9LrGtHPcJYWSkkfToMReux14iSb2zf4c"), "2EgitLRfQmYckjmi16b2h3YFLBz7yKS877tb1TQRXR6Y"}, + } { + id := GenerateLeaseScriptActionID(test.recipient, test.amount, test.nonce, test.tx) + assert.Equal(t, test.id, id.String()) + } +} + +// This function is for tests only! Could produce invalid recipient. +func mustRecipientFromString(s string) Recipient { + r, err := recipientFromString(s) + if err != nil { + panic(err) + } + return r +} + func TestAssetIDGeneration(t *testing.T) { for _, test := range []struct { name string diff --git a/pkg/proto/transactions.go b/pkg/proto/transactions.go index fbb684b9b..ae389a956 100644 --- a/pkg/proto/transactions.go +++ b/pkg/proto/transactions.go @@ -52,10 +52,10 @@ const ( const ( maxAttachmentLengthBytes = 140 - maxDescriptionLen = 1000 - maxAssetNameLen = 16 - minAssetNameLen = 4 - maxDecimals = 8 + MaxDescriptionLen = 1000 + MaxAssetNameLen = 16 + MinAssetNameLen = 4 + MaxDecimals = 8 maxLongValue = ^uint64(0) >> 1 genesisBodyLen = 1 + 8 + AddressSize + 8 @@ -189,7 +189,7 @@ type Transaction interface { Validate() (Transaction, error) // Set transaction ID. - // For most transacions ID is hash of transaction body. + // For most transactions ID is hash of transaction body. // For Payment transactions ID is Signature. GenerateID(scheme Scheme) error // Sign transaction with given secret key. @@ -449,7 +449,7 @@ func (tx *Genesis) GenerateID(scheme Scheme) error { return tx.generateID(scheme) } -func (tx *Genesis) Sign(scheme Scheme, sk crypto.SecretKey) error { +func (tx *Genesis) Sign(scheme Scheme, _ crypto.SecretKey) error { if err := tx.generateID(scheme); err != nil { return err } @@ -701,7 +701,7 @@ func (tx Payment) GetVersion() byte { return tx.Version } -func (tx *Payment) GenerateID(scheme Scheme) error { +func (tx *Payment) GenerateID(_ Scheme) error { if tx.ID == nil { tx.ID = tx.Signature } @@ -1010,14 +1010,14 @@ func (i Issue) Valid() (bool, error) { if !validJVMLong(i.Fee) { return false, errors.New("fee is too big") } - if l := len(i.Name); l < minAssetNameLen || l > maxAssetNameLen { + if l := len(i.Name); l < MinAssetNameLen || l > MaxAssetNameLen { return false, errs.NewInvalidName("incorrect number of bytes in the asset's name") } - if l := len(i.Description); l > maxDescriptionLen { + if l := len(i.Description); l > MaxDescriptionLen { return false, errs.NewTooBigArray("incorrect number of bytes in the asset's description") } - if i.Decimals > maxDecimals { - return false, errs.NewTooBigArray(fmt.Sprintf("incorrect decimals, should be no more then %d", maxDecimals)) + if i.Decimals > MaxDecimals { + return false, errs.NewTooBigArray(fmt.Sprintf("incorrect decimals, should be no more then %d", MaxDecimals)) } return true, nil } diff --git a/pkg/proto/transactions_test.go b/pkg/proto/transactions_test.go index 7b085a72c..a2cd645c8 100644 --- a/pkg/proto/transactions_test.go +++ b/pkg/proto/transactions_test.go @@ -432,7 +432,7 @@ func TestIssueWithSigValidations(t *testing.T) { {"TOKEN", strings.Repeat("x", 1010), 1000000, 2, 100000, "incorrect number of bytes in the asset's description"}, {"TOKEN", "This is a valid description for the token", 0, 2, 100000, "quantity should be positive"}, {"TOKEN", "This is a valid description for the token", math.MaxInt64 + 100, 2, 100000, "quantity is too big"}, - {"TOKEN", "This is a valid description for the token", 100000, 12, 100000, fmt.Sprintf("incorrect decimals, should be no more then %d", maxDecimals)}, + {"TOKEN", "This is a valid description for the token", 100000, 12, 100000, fmt.Sprintf("incorrect decimals, should be no more then %d", MaxDecimals)}, {"TOKEN", "This is a valid description for the token", 100000, 2, 0, "fee should be positive"}, {"TOKEN", "This is a valid description for the token", 100000, 2, math.MaxInt64 + 100, "fee is too big"}, } @@ -610,7 +610,7 @@ func TestIssueWithProofsValidations(t *testing.T) { {"TOKEN", strings.Repeat("x", 1010), 1000000, 2, 100000, "incorrect number of bytes in the asset's description"}, {"TOKEN", "This is a valid description for the token", 0, 2, 100000, "quantity should be positive"}, {"TOKEN", "This is a valid description for the token", math.MaxInt64 + 1, 2, 100000, "quantity is too big"}, - {"TOKEN", "This is a valid description for the token", 100000, 12, 100000, fmt.Sprintf("incorrect decimals, should be no more then %d", maxDecimals)}, + {"TOKEN", "This is a valid description for the token", 100000, 12, 100000, fmt.Sprintf("incorrect decimals, should be no more then %d", MaxDecimals)}, {"TOKEN", "This is a valid description for the token", 100000, 2, 0, "fee should be positive"}, {"TOKEN", "This is a valid description for the token", 100000, 2, math.MaxInt64 + 1, "fee is too big"}, //TODO: add tests on script validation diff --git a/pkg/proto/transactions_with_proofs.go b/pkg/proto/transactions_with_proofs.go index 002458893..ed2d98ff1 100644 --- a/pkg/proto/transactions_with_proofs.go +++ b/pkg/proto/transactions_with_proofs.go @@ -4688,10 +4688,10 @@ func (tx *UpdateAssetInfoWithProofs) Validate() (Transaction, error) { if !validJVMLong(tx.Fee) { return tx, errors.New("fee is too big") } - if l := len(tx.Name); l < minAssetNameLen || l > maxAssetNameLen { + if l := len(tx.Name); l < MinAssetNameLen || l > MaxAssetNameLen { return tx, errs.NewInvalidName("incorrect number of bytes in the asset's name") } - if l := len(tx.Description); l > maxDescriptionLen { + if l := len(tx.Description); l > MaxDescriptionLen { return tx, errs.NewTooBigArray("incorrect number of bytes in the asset's description") } return tx, nil diff --git a/pkg/proto/types.go b/pkg/proto/types.go index f2be41ad6..a09b7fee1 100644 --- a/pkg/proto/types.go +++ b/pkg/proto/types.go @@ -25,32 +25,46 @@ import ( const ( //WavesAssetName is the default name for basic WAVES asset. - WavesAssetName = "WAVES" - quotedWavesAssetName = "\"" + WavesAssetName + "\"" - orderLen = crypto.PublicKeySize + crypto.PublicKeySize + 1 + 1 + 1 + 8 + 8 + 8 + 8 + 8 - orderV2FixedBodyLen = 1 + orderLen - orderV3FixedBodyLen = 1 + orderLen + 1 - orderV1MinLen = crypto.SignatureSize + orderLen - orderV2MinLen = orderV2FixedBodyLen + proofsMinLen - orderV3MinLen = orderV3FixedBodyLen + proofsMinLen - jsonNull = "null" - integerArgumentLen = 1 + 8 - booleanArgumentLen = 1 - binaryArgumentMinLen = 1 + 4 - stringArgumentMinLen = 1 + 4 - listArgumentMinLen = 1 + 4 - PriceConstant = 100000000 - MaxOrderAmount = 100 * PriceConstant * PriceConstant - MaxOrderTTL = uint64((30 * 24 * time.Hour) / time.Millisecond) - maxKeySize = 100 - maxPBKeySize = 400 - maxValueSize = 32767 - - maxScriptActions = 10 - maxDataEntryScriptActions = 100 - maxDataEntryScriptActionsSizeInBytes = 5 * 1024 + WavesAssetName = "WAVES" + quotedWavesAssetName = "\"" + WavesAssetName + "\"" + orderLen = crypto.PublicKeySize + crypto.PublicKeySize + 1 + 1 + 1 + 8 + 8 + 8 + 8 + 8 + orderV2FixedBodyLen = 1 + orderLen + orderV3FixedBodyLen = 1 + orderLen + 1 + orderV1MinLen = crypto.SignatureSize + orderLen + orderV2MinLen = orderV2FixedBodyLen + proofsMinLen + orderV3MinLen = orderV3FixedBodyLen + proofsMinLen + jsonNull = "null" + integerArgumentLen = 1 + 8 + booleanArgumentLen = 1 + binaryArgumentMinLen = 1 + 4 + stringArgumentMinLen = 1 + 4 + listArgumentMinLen = 1 + 4 + PriceConstant = 100000000 + MaxOrderAmount = 100 * PriceConstant * PriceConstant + MaxOrderTTL = uint64((30 * 24 * time.Hour) / time.Millisecond) + MaxKeySize = 100 + MaxPBKeySize = 400 + maxValueSize = 32767 + MaxDataEntryScriptActions = 100 + MaxDataEntryScriptActionsSizeInBytes = 5 * 1024 ) +type MaxScriptActions struct { + BeforeRideScriptV5 int + AfterRideScriptV5 int +} + +func NewMaxScriptActions() MaxScriptActions { + return MaxScriptActions{BeforeRideScriptV5: 10, AfterRideScriptV5: 30} +} + +func (a MaxScriptActions) GetMaxScriptsComplexityInBlock(scriptVersion int) int { + if scriptVersion > 5 { + return a.AfterRideScriptV5 + } + return a.BeforeRideScriptV5 +} + type Timestamp = uint64 type Score = big.Int type Scheme = byte @@ -145,15 +159,23 @@ func NewOptionalAssetFromBytes(b []byte) (*OptionalAsset, error) { a, err := crypto.NewDigestFromBytes(b) if err != nil { - return nil, errors.Wrap(err, "failed to create OptionalAsset from Base58 string") + return nil, errors.Wrap(err, "failed to create OptionalAsset from bytes") } return &OptionalAsset{Present: true, ID: a}, nil } func NewOptionalAssetFromDigest(d crypto.Digest) *OptionalAsset { + waves := crypto.Digest{} + if d == waves { + return &OptionalAsset{Present: false} + } return &OptionalAsset{Present: true, ID: d} } +func NewOptionalAssetWaves() OptionalAsset { + return OptionalAsset{Present: false} +} + // String method converts OptionalAsset to its text representation func (a OptionalAsset) String() string { if a.Present { @@ -1799,11 +1821,11 @@ func (e IntegerDataEntry) Valid(version byte) error { } switch version { case 1: - if len(utf16.Encode([]rune(e.Key))) > maxKeySize { + if len(utf16.Encode([]rune(e.Key))) > MaxKeySize { return errs.NewTooBigArray("key is too large") } default: - if len([]byte(e.Key)) > maxPBKeySize { + if len([]byte(e.Key)) > MaxPBKeySize { return errs.NewTooBigArray("key is too large") } } @@ -1927,11 +1949,11 @@ func (e BooleanDataEntry) Valid(version byte) error { } switch version { case 1: - if len(utf16.Encode([]rune(e.Key))) > maxKeySize { + if len(utf16.Encode([]rune(e.Key))) > MaxKeySize { return errs.NewTooBigArray("key is too large11") } default: - if len([]byte(e.Key)) > maxPBKeySize { + if len([]byte(e.Key)) > MaxPBKeySize { return errs.NewTooBigArray("key is too large22") } } @@ -2059,11 +2081,11 @@ func (e BinaryDataEntry) Valid(version byte) error { } switch version { case 1: - if len(utf16.Encode([]rune(e.Key))) > maxKeySize { + if len(utf16.Encode([]rune(e.Key))) > MaxKeySize { return errs.NewTooBigArray("key is too large") } default: - if len([]byte(e.Key)) > maxPBKeySize { + if len([]byte(e.Key)) > MaxPBKeySize { return errs.NewTooBigArray("key is too large") } } @@ -2194,11 +2216,11 @@ func (e StringDataEntry) Valid(version byte) error { } switch version { case 1: - if len(utf16.Encode([]rune(e.Key))) > maxKeySize { + if len(utf16.Encode([]rune(e.Key))) > MaxKeySize { return errs.NewTooBigArray("key is too large") } default: - if len([]byte(e.Key)) > maxPBKeySize { + if len([]byte(e.Key)) > MaxPBKeySize { return errs.NewTooBigArray("key is too large") } } @@ -2328,11 +2350,11 @@ func (e DeleteDataEntry) Valid(version byte) error { } switch version { case 1: - if len(utf16.Encode([]rune(e.Key))) > maxKeySize { + if len(utf16.Encode([]rune(e.Key))) > MaxKeySize { return errs.NewTooBigArray("key is too large") } default: - if len([]byte(e.Key)) > maxPBKeySize { + if len([]byte(e.Key)) > MaxPBKeySize { return errs.NewTooBigArray("key is too large") } } diff --git a/pkg/ride/constants.go b/pkg/ride/constants.go index 5715bae36..df678c154 100644 --- a/pkg/ride/constants.go +++ b/pkg/ride/constants.go @@ -90,162 +90,184 @@ func checkConstantV4(name string) (uint16, bool) { return 0, false } -func newFloor(RideEnvironment) rideType { - return rideNamedType{name: "Floor"} -} +var ConstantsV5 = []string{"Buy", "CEILING", "DOWN", "FLOOR", "HALFEVEN", "HALFUP", "MD5", "NOALG", "SHA1", "SHA224", "SHA256", "SHA3224", "SHA3256", "SHA3384", "SHA3512", "SHA384", "SHA512", "Sell", "height", "lastBlock", "nil", "this", "tx", "unit"} -func createFloor(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Floor"}, nil +const _constants_V5 = "BuyCEILINGDOWNFLOORHALFEVENHALFUPMD5NOALGSHA1SHA224SHA256SHA3224SHA3256SHA3384SHA3512SHA384SHA512SellheightlastBlocknilthistxunit" + +var _constructors_V5 = [...]rideConstructor{newBuy, newCeiling, newDown, newFloor, newHalfEven, newHalfUp, newMd5, newNoAlg, newSha1, newSha224, newSha256, newSha3224, newSha3256, newSha3384, newSha3512, newSha384, newSha512, newSell, newHeight, newLastBlock, newNil, newThis, newTx, newUnit} +var _c_index_V5 = [...]int{0, 3, 10, 14, 19, 27, 33, 36, 41, 45, 51, 57, 64, 71, 78, 85, 91, 97, 101, 107, 116, 119, 123, 125, 129} + +func constantV5(id int) rideConstructor { + if id < 0 || id > 23 { + return nil + } + return _constructors_V5[id] +} +func checkConstantV5(name string) (uint16, bool) { + for i := 0; i <= 23; i++ { + if _constants_V5[_c_index_V5[i]:_c_index_V5[i+1]] == name { + return uint16(i), true + } + } + return 0, false } -func newHalfEven(RideEnvironment) rideType { - return rideNamedType{name: "HalfEven"} +func newBuy(Environment) rideType { + return rideNamedType{name: "Buy"} } -func createHalfEven(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfEven"}, nil +func createBuy(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Buy"}, nil } -func newSha1(RideEnvironment) rideType { - return rideNamedType{name: "Sha1"} +func newCeiling(Environment) rideType { + return rideNamedType{name: "Ceiling"} } -func createSha1(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha1"}, nil +func createCeiling(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Ceiling"}, nil } -func newSha256(RideEnvironment) rideType { - return rideNamedType{name: "Sha256"} +func newDown(Environment) rideType { + return rideNamedType{name: "Down"} } -func createSha256(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha256"}, nil +func createDown(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Down"}, nil } -func newSha3256(RideEnvironment) rideType { - return rideNamedType{name: "Sha3256"} +func newFloor(Environment) rideType { + return rideNamedType{name: "Floor"} } -func createSha3256(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3256"}, nil +func createFloor(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Floor"}, nil } -func newSha3384(RideEnvironment) rideType { - return rideNamedType{name: "Sha3384"} +func newHalfDown(Environment) rideType { + return rideNamedType{name: "HalfDown"} } -func createSha3384(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3384"}, nil +func createHalfDown(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfDown"}, nil } -func newBuy(RideEnvironment) rideType { - return rideNamedType{name: "Buy"} +func newHalfEven(Environment) rideType { + return rideNamedType{name: "HalfEven"} } -func createBuy(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Buy"}, nil +func createHalfEven(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfEven"}, nil } -func newCeiling(RideEnvironment) rideType { - return rideNamedType{name: "Ceiling"} +func newHalfUp(Environment) rideType { + return rideNamedType{name: "HalfUp"} } -func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Ceiling"}, nil +func createHalfUp(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfUp"}, nil } -func newSha384(RideEnvironment) rideType { - return rideNamedType{name: "Sha384"} +func newMd5(Environment) rideType { + return rideNamedType{name: "Md5"} } -func createSha384(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha384"}, nil +func createMd5(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Md5"}, nil } -func newHalfDown(RideEnvironment) rideType { - return rideNamedType{name: "HalfDown"} +func newNoAlg(Environment) rideType { + return rideNamedType{name: "NoAlg"} } -func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfDown"}, nil +func createNoAlg(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "NoAlg"}, nil } -func newHalfUp(RideEnvironment) rideType { - return rideNamedType{name: "HalfUp"} +func newSha1(Environment) rideType { + return rideNamedType{name: "Sha1"} } -func createHalfUp(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfUp"}, nil +func createSha1(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha1"}, nil } -func newMd5(RideEnvironment) rideType { - return rideNamedType{name: "Md5"} +func newSha224(Environment) rideType { + return rideNamedType{name: "Sha224"} } -func createMd5(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Md5"}, nil +func createSha224(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha224"}, nil } -func newSha512(RideEnvironment) rideType { - return rideNamedType{name: "Sha512"} +func newSha256(Environment) rideType { + return rideNamedType{name: "Sha256"} } -func createSha512(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha512"}, nil +func createSha256(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha256"}, nil } -func newSha3512(RideEnvironment) rideType { - return rideNamedType{name: "Sha3512"} +func newSha3224(Environment) rideType { + return rideNamedType{name: "Sha3224"} } -func createSha3512(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3512"}, nil +func createSha3224(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3224"}, nil } -func newUp(RideEnvironment) rideType { - return rideNamedType{name: "Up"} +func newSha3256(Environment) rideType { + return rideNamedType{name: "Sha3256"} } -func createUp(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Up"}, nil +func createSha3256(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3256"}, nil } -func newDown(RideEnvironment) rideType { - return rideNamedType{name: "Down"} +func newSha3384(Environment) rideType { + return rideNamedType{name: "Sha3384"} } -func createDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Down"}, nil +func createSha3384(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3384"}, nil } -func newNoAlg(RideEnvironment) rideType { - return rideNamedType{name: "NoAlg"} +func newSha3512(Environment) rideType { + return rideNamedType{name: "Sha3512"} } -func createNoAlg(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "NoAlg"}, nil +func createSha3512(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3512"}, nil } -func newSha224(RideEnvironment) rideType { - return rideNamedType{name: "Sha224"} +func newSha384(Environment) rideType { + return rideNamedType{name: "Sha384"} } -func createSha224(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha224"}, nil +func createSha384(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha384"}, nil } -func newSha3224(RideEnvironment) rideType { - return rideNamedType{name: "Sha3224"} +func newSha512(Environment) rideType { + return rideNamedType{name: "Sha512"} } -func createSha3224(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3224"}, nil +func createSha512(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha512"}, nil } -func newSell(RideEnvironment) rideType { +func newSell(Environment) rideType { return rideNamedType{name: "Sell"} } -func createSell(env RideEnvironment, args ...rideType) (rideType, error) { +func createSell(env Environment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sell"}, nil } + +func newUp(Environment) rideType { + return rideNamedType{name: "Up"} +} + +func createUp(env Environment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Up"}, nil +} diff --git a/pkg/ride/constraints.go b/pkg/ride/constraints.go new file mode 100644 index 000000000..813ee9541 --- /dev/null +++ b/pkg/ride/constraints.go @@ -0,0 +1,3 @@ +package ride + +const MaxChainInvokeComplexity = 26000 diff --git a/pkg/ride/constructors.go b/pkg/ride/constructors.go index adb7e0e15..08b0fbdc5 100644 --- a/pkg/ride/constructors.go +++ b/pkg/ride/constructors.go @@ -1,13 +1,13 @@ package ride -func newHeight(env RideEnvironment) rideType { +func newHeight(env Environment) rideType { if env == nil { return rideUnit{} } return env.height() } -func newTx(env RideEnvironment) rideType { +func newTx(env Environment) rideType { if env == nil { return rideUnit{} } @@ -18,7 +18,7 @@ func newTx(env RideEnvironment) rideType { return tx } -func newLastBlock(env RideEnvironment) rideType { +func newLastBlock(env Environment) rideType { if env == nil { return rideUnit{} } @@ -29,7 +29,7 @@ func newLastBlock(env RideEnvironment) rideType { return b } -func newThis(env RideEnvironment) rideType { +func newThis(env Environment) rideType { if env == nil { return rideUnit{} } @@ -40,7 +40,7 @@ func newThis(env RideEnvironment) rideType { return this } -func newInvocation(env RideEnvironment) rideType { +func newInvocation(env Environment) rideType { if env == nil { return rideUnit{} } @@ -51,10 +51,10 @@ func newInvocation(env RideEnvironment) rideType { return inv } -func newUnit(RideEnvironment) rideType { +func newUnit(Environment) rideType { return rideUnit{} } -func newNil(RideEnvironment) rideType { +func newNil(Environment) rideType { return rideList(nil) } diff --git a/pkg/ride/converters.go b/pkg/ride/converters.go index 53f937278..68bc21769 100644 --- a/pkg/ride/converters.go +++ b/pkg/ride/converters.go @@ -933,7 +933,7 @@ func invocationToObject(v int, scheme byte, tx *proto.InvokeScriptWithProofs) (r r["caller"] = rideAddress(sender) r["callerPublicKey"] = rideBytes(common.Dup(tx.SenderPK.Bytes())) switch v { - case 4: + case 4, 5: payments := make(rideList, len(tx.Payments)) for i, p := range tx.Payments { payments[i] = attachedPaymentToObject(p) @@ -979,7 +979,7 @@ func balanceDetailsToObject(fwb *proto.FullWavesBalance) rideObject { return r } -func objectToActions(env RideEnvironment, obj rideType) ([]proto.ScriptAction, error) { +func objectToActions(env Environment, obj rideType) ([]proto.ScriptAction, error) { switch obj.instanceOf() { case "WriteSet": data, err := obj.get("data") @@ -1057,7 +1057,7 @@ func getKeyProperty(v rideType) (string, error) { return string(key), nil } -func convertToAction(env RideEnvironment, obj rideType) (proto.ScriptAction, error) { +func convertToAction(env Environment, obj rideType) (proto.ScriptAction, error) { switch obj.instanceOf() { case "Burn": id, err := digestProperty(obj, "assetId") @@ -1240,6 +1240,43 @@ func convertToAction(env RideEnvironment, obj rideType) (proto.ScriptAction, err MinFee: int64(fee), }, nil + case "Lease": + recipient, err := recipientProperty(obj, "recipient") + if err != nil { + return nil, errors.Wrap(err, "failed to convert Lease to LeaseScriptAction") + } + amount, err := intProperty(obj, "amount") + if err != nil { + return nil, errors.Wrap(err, "failed to convert Lease to LeaseScriptAction") + } + nonce, err := intProperty(obj, "nonce") + if err != nil { + return nil, errors.Wrap(err, "failed to convert Lease to LeaseScriptAction") + } + id, err := calcLeaseID(env, recipient, amount, nonce) + if err != nil { + return nil, errors.Wrap(err, "failed to convert Lease to LeaseScriptAction") + } + d, err := crypto.NewDigestFromBytes(id) + if err != nil { + return nil, errors.Wrap(err, "failed to convert Lease to LeaseScriptAction") + } + return &proto.LeaseScriptAction{ + ID: d, + Recipient: recipient, + Amount: int64(amount), + Nonce: int64(nonce), + }, nil + + case "LeaseCancel": + id, err := digestProperty(obj, "leaseId") + if err != nil { + return nil, errors.Wrap(err, "failed to convert LeaseCancel to LeaseCancelScriptAction") + } + return &proto.LeaseCancelScriptAction{ + LeaseID: id, + }, nil + default: return nil, errors.Errorf("unexpected type '%s'", obj.instanceOf()) } diff --git a/pkg/ride/diff_state.go b/pkg/ride/diff_state.go new file mode 100644 index 000000000..0d8831132 --- /dev/null +++ b/pkg/ride/diff_state.go @@ -0,0 +1,287 @@ +package ride + +import ( + "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/crypto" + "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/types" +) + +type diffDataEntries struct { + diffInteger map[string]proto.IntegerDataEntry // map[key + address.String()] + diffBool map[string]proto.BooleanDataEntry + diffString map[string]proto.StringDataEntry + diffBinary map[string]proto.BinaryDataEntry + diffDDelete map[string]proto.DeleteDataEntry +} + +type lease struct { + Recipient proto.Recipient + leasedAmount int64 + Sender proto.Recipient +} + +type diffBalance struct { + asset proto.OptionalAsset + regular int64 + leaseIn int64 + leaseOut int64 + effectiveHistory []int64 +} + +type diffSponsorship struct { + MinFee int64 +} + +type diffNewAssetInfo struct { + dAppIssuer proto.Address + name string + description string + quantity int64 + decimals int32 + reissuable bool + script []byte + nonce int64 +} + +type diffOldAssetInfo struct { + diffQuantity int64 +} + +type diffState struct { + state types.SmartState + dataEntries diffDataEntries + balances map[string]diffBalance // map[address.String() + Digest.String()] or map[address.String()] + sponsorships map[string]diffSponsorship // map[Digest.String()] + newAssetsInfo map[string]diffNewAssetInfo // map[asset.String()] + oldAssetsInfo map[string]diffOldAssetInfo // map[asset.String()] + leases map[string]lease // map[lease.String()] +} + +func (diffSt *diffState) addBalanceTo(searchAddress string, amount int64) { + oldDiffBalance := diffSt.balances[searchAddress] + oldDiffBalance.regular += amount + diffSt.balances[searchAddress] = oldDiffBalance +} + +func (diffSt *diffState) reissueNewAsset(assetID crypto.Digest, quantity int64, reissuable bool) { + asset := proto.NewOptionalAssetFromDigest(assetID) + assetInfo := diffSt.newAssetsInfo[asset.String()] + assetInfo.reissuable = reissuable + assetInfo.quantity += quantity + diffSt.newAssetsInfo[asset.String()] = assetInfo +} + +func (diffSt *diffState) burnNewAsset(assetID crypto.Digest, quantity int64) { + asset := proto.NewOptionalAssetFromDigest(assetID) + + assetInfo := diffSt.newAssetsInfo[asset.String()] + assetInfo.quantity -= quantity + diffSt.newAssetsInfo[asset.String()] = assetInfo +} + +func (diffSt *diffState) createNewWavesBalance(account proto.Recipient) (*diffBalance, string) { + wavesAsset := proto.NewOptionalAssetWaves() + balance := diffBalance{asset: wavesAsset} + diffSt.balances[account.Address.String()+wavesAsset.String()] = balance + return &balance, account.Address.String() + wavesAsset.String() +} + +func (diffSt *diffState) cancelLease(searchLease lease, senderSearchAddress, recipientSearchAddress string) { + oldDiffBalanceRecipient := diffSt.balances[recipientSearchAddress] + oldDiffBalanceRecipient.leaseIn -= searchLease.leasedAmount + diffSt.balances[recipientSearchAddress] = oldDiffBalanceRecipient + + oldDiffBalanceSender := diffSt.balances[senderSearchAddress] + oldDiffBalanceSender.leaseOut -= searchLease.leasedAmount + diffSt.balances[senderSearchAddress] = oldDiffBalanceSender +} + +func (diffSt *diffState) findMinGenerating(effectiveHistory []int64, generatingFromState int64) int64 { + min := generatingFromState + for _, value := range effectiveHistory { + if value < min { + min = value + } + } + return min +} + +func (diffSt *diffState) addEffectiveToHistory(searchAddress string, effective int64) error { + oldDiffBalance, ok := diffSt.balances[searchAddress] + if !ok { + return errors.Errorf("cannot find balance to add effective to history") + } + oldDiffBalance.effectiveHistory = append(oldDiffBalance.effectiveHistory, effective) + diffSt.balances[searchAddress] = oldDiffBalance + return nil +} + +func (diffSt *diffState) addNewLease(recipient proto.Recipient, sender proto.Recipient, leasedAmount int64, leaseID crypto.Digest) { + lease := lease{Recipient: recipient, Sender: sender, leasedAmount: leasedAmount} + diffSt.leases[leaseID.String()] = lease +} + +func (diffSt *diffState) addLeaseInTo(searchAddress string, leasedAmount int64) { + oldDiffBalance := diffSt.balances[searchAddress] + oldDiffBalance.leaseIn += leasedAmount + + diffSt.balances[searchAddress] = oldDiffBalance +} + +func (diffSt *diffState) changeLeaseIn(searchBalance *diffBalance, searchAddress string, leasedAmount int64, account proto.Recipient) error { + if searchBalance != nil { + diffSt.addLeaseInTo(searchAddress, leasedAmount) + return nil + } + address, err := diffSt.state.NewestRecipientToAddress(account) + if err != nil { + return err + } + + var balance diffBalance + balance.asset = proto.NewOptionalAssetWaves() + balance.leaseIn = leasedAmount + + diffSt.balances[address.String()+balance.asset.String()] = balance + return nil +} + +func (diffSt *diffState) addLeaseOutTo(searchAddress string, leasedAmount int64) { + oldDiffBalance := diffSt.balances[searchAddress] + oldDiffBalance.leaseOut += leasedAmount + diffSt.balances[searchAddress] = oldDiffBalance +} + +func (diffSt *diffState) changeLeaseOut(searchBalance *diffBalance, searchAddress string, leasedAmount int64, account proto.Recipient) error { + if searchBalance != nil { + diffSt.addLeaseOutTo(searchAddress, leasedAmount) + return nil + } + + address, err := diffSt.state.NewestRecipientToAddress(account) + if err != nil { + return err + } + + var balance diffBalance + balance.asset = proto.NewOptionalAssetWaves() + balance.leaseOut = leasedAmount + + diffSt.balances[address.String()+balance.asset.String()] = balance + return nil +} + +func (diffSt *diffState) changeBalance(searchBalance *diffBalance, searchAddress string, amount int64, assetID crypto.Digest, account proto.Recipient) error { + if searchBalance != nil { + diffSt.addBalanceTo(searchAddress, amount) + return nil + } + + address, err := diffSt.state.NewestRecipientToAddress(account) + if err != nil { + return err + } + + var balance diffBalance + asset := *proto.NewOptionalAssetFromDigest(assetID) + balance.asset = asset + balance.regular = amount + + diffSt.balances[address.String()+asset.String()] = balance + return nil +} + +func (diffSt *diffState) findLeaseByIDForCancel(leaseID crypto.Digest) (*lease, error) { + if lease, ok := diffSt.leases[leaseID.String()]; ok { + return &lease, nil + } + leaseFromStore, err := diffSt.state.NewestLeasingInfo(leaseID) + if err != nil { + return nil, err + } + if leaseFromStore != nil { + if !leaseFromStore.IsActive { + return nil, nil + } + lease := lease{ + Recipient: proto.NewRecipientFromAddress(leaseFromStore.Recipient), + Sender: proto.NewRecipientFromAddress(leaseFromStore.Sender), + leasedAmount: int64(leaseFromStore.LeaseAmount), + } + return &lease, nil + } + return nil, nil +} + +func (diffSt *diffState) findIntFromDataEntryByKey(key string, address string) *proto.IntegerDataEntry { + if integerEntry, ok := diffSt.dataEntries.diffInteger[key+address]; ok { + return &integerEntry + } + return nil +} + +func (diffSt *diffState) findBoolFromDataEntryByKey(key string, address string) *proto.BooleanDataEntry { + if boolEntry, ok := diffSt.dataEntries.diffBool[key+address]; ok { + return &boolEntry + } + return nil +} + +func (diffSt *diffState) findStringFromDataEntryByKey(key string, address string) *proto.StringDataEntry { + if stringEntry, ok := diffSt.dataEntries.diffString[key+address]; ok { + return &stringEntry + } + return nil +} + +func (diffSt *diffState) findBinaryFromDataEntryByKey(key string, address string) *proto.BinaryDataEntry { + if binaryEntry, ok := diffSt.dataEntries.diffBinary[key+address]; ok { + return &binaryEntry + } + return nil +} + +func (diffSt *diffState) findDeleteFromDataEntryByKey(key string, address string) *proto.DeleteDataEntry { + if deleteEntry, ok := diffSt.dataEntries.diffDDelete[key+address]; ok { + return &deleteEntry + } + return nil +} + +func (diffSt *diffState) findBalance(recipient proto.Recipient, asset proto.OptionalAsset) (*diffBalance, string, error) { + address, err := diffSt.state.NewestRecipientToAddress(recipient) + if err != nil { + return nil, "", errors.Errorf("cannot get address from recipient") + } + + if balance, ok := diffSt.balances[address.String()+asset.String()]; ok { + return &balance, address.String() + asset.String(), nil + } + + return nil, "", nil +} + +func (diffSt *diffState) findSponsorship(assetID crypto.Digest) *int64 { + asset := proto.NewOptionalAssetFromDigest(assetID) + if sponsorship, ok := diffSt.sponsorships[asset.String()]; ok { + return &sponsorship.MinFee + } + return nil +} + +func (diffSt *diffState) findNewAsset(assetID crypto.Digest) *diffNewAssetInfo { + asset := proto.NewOptionalAssetFromDigest(assetID) + if newAsset, ok := diffSt.newAssetsInfo[asset.String()]; ok { + return &newAsset + } + return nil +} + +func (diffSt *diffState) findOldAsset(assetID crypto.Digest) *diffOldAssetInfo { + asset := proto.NewOptionalAssetFromDigest(assetID) + if oldAsset, ok := diffSt.oldAssetsInfo[asset.String()]; ok { + return &oldAsset + } + return nil +} diff --git a/pkg/ride/environment.go b/pkg/ride/environment.go index f96da2847..b5b3b4759 100644 --- a/pkg/ride/environment.go +++ b/pkg/ride/environment.go @@ -1,42 +1,1153 @@ package ride import ( + "unicode/utf16" + + "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" + "github.com/wavesplatform/gowaves/pkg/errs" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" ) -type Environment struct { - sch proto.Scheme - st types.SmartState - h rideInt - tx rideObject - id rideType - th rideType - b rideObject - check func(int) bool - inv rideObject +type WrappedState struct { + diff diffState + cle rideAddress + scheme proto.Scheme + invokeCount uint64 + act []proto.ScriptAction + blackList []proto.Address + totalComplexity int +} + +func newWrappedState(env *EvaluationEnvironment) *WrappedState { + dataEntries := diffDataEntries{ + diffInteger: map[string]proto.IntegerDataEntry{}, + diffBool: map[string]proto.BooleanDataEntry{}, + diffString: map[string]proto.StringDataEntry{}, + diffBinary: map[string]proto.BinaryDataEntry{}, + diffDDelete: map[string]proto.DeleteDataEntry{}, + } + diffSt := diffState{ + state: env.st, + dataEntries: dataEntries, + balances: map[string]diffBalance{}, + sponsorships: map[string]diffSponsorship{}, + newAssetsInfo: map[string]diffNewAssetInfo{}, + oldAssetsInfo: map[string]diffOldAssetInfo{}, + leases: map[string]lease{}} + + return &WrappedState{diff: diffSt, cle: env.th.(rideAddress), scheme: env.sch} +} + +func (ws *WrappedState) appendActions(actions []proto.ScriptAction) { + ws.act = append(ws.act, actions...) +} + +func (ws *WrappedState) checkTotalComplexity() (int, bool) { + if ws.totalComplexity > MaxChainInvokeComplexity { + return ws.totalComplexity, false + } + return ws.totalComplexity, true +} + +func (ws *WrappedState) callee() proto.Address { + return proto.Address(ws.cle) +} + +func (ws *WrappedState) smartAppendActions(actions []proto.ScriptAction, env Environment) error { + modifiedActions, err := ws.ApplyToState(actions, env) + if err != nil { + return err + } + ws.appendActions(modifiedActions) + return nil +} + +func (ws *WrappedState) AddingBlockHeight() (uint64, error) { + return ws.diff.state.AddingBlockHeight() +} + +func (ws *WrappedState) NewestLeasingInfo(id crypto.Digest) (*proto.LeaseInfo, error) { + return ws.diff.state.NewestLeasingInfo(id) +} + +func (ws *WrappedState) NewestScriptPKByAddr(addr proto.Address) (crypto.PublicKey, error) { + return ws.diff.state.NewestScriptPKByAddr(addr) +} +func (ws *WrappedState) NewestTransactionByID(id []byte) (proto.Transaction, error) { + return ws.diff.state.NewestTransactionByID(id) +} +func (ws *WrappedState) NewestTransactionHeightByID(id []byte) (uint64, error) { + return ws.diff.state.NewestTransactionHeightByID(id) +} + +func (ws *WrappedState) GetByteTree(recipient proto.Recipient) (proto.Script, error) { + return ws.diff.state.GetByteTree(recipient) +} +func (ws *WrappedState) NewestRecipientToAddress(recipient proto.Recipient) (*proto.Address, error) { + return ws.diff.state.NewestRecipientToAddress(recipient) +} + +func (ws *WrappedState) NewestAddrByAlias(alias proto.Alias) (proto.Address, error) { + return ws.diff.state.NewestAddrByAlias(alias) +} + +func (ws *WrappedState) NewestAccountBalance(account proto.Recipient, assetID []byte) (uint64, error) { + balance, err := ws.diff.state.NewestAccountBalance(account, assetID) + if err != nil { + return 0, err + } + var asset *proto.OptionalAsset + + if isAssetWaves(assetID) { + waves := proto.NewOptionalAssetWaves() + asset = &waves + } else { + asset, err = proto.NewOptionalAssetFromBytes(assetID) + if err != nil { + return 0, err + } + } + + balanceDiff, _, err := ws.diff.findBalance(account, *asset) + if err != nil { + return 0, err + } + if balanceDiff != nil { + resBalance := int64(balance) + balanceDiff.regular + return uint64(resBalance), nil + + } + return balance, nil +} + +func (ws *WrappedState) NewestFullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { + balance, err := ws.diff.state.NewestFullWavesBalance(account) + if err != nil { + return nil, err + } + wavesBalanceDiff, searchAddress, err := ws.diff.findBalance(account, proto.NewOptionalAssetWaves()) + if err != nil { + return nil, err + } + if wavesBalanceDiff != nil { + resRegular := wavesBalanceDiff.regular + int64(balance.Regular) + resAvailable := (wavesBalanceDiff.regular - wavesBalanceDiff.leaseOut) + int64(balance.Available) + resEffective := (wavesBalanceDiff.regular - wavesBalanceDiff.leaseOut + wavesBalanceDiff.leaseIn) + int64(balance.Effective) + resLeaseIn := wavesBalanceDiff.leaseIn + int64(balance.LeaseIn) + resLeaseOut := wavesBalanceDiff.leaseOut + int64(balance.LeaseOut) + + err := ws.diff.addEffectiveToHistory(searchAddress, resEffective) + if err != nil { + return nil, err + } + + resGenerating := ws.diff.findMinGenerating(ws.diff.balances[searchAddress].effectiveHistory, int64(balance.Generating)) + + return &proto.FullWavesBalance{ + Regular: uint64(resRegular), + Generating: uint64(resGenerating), + Available: uint64(resAvailable), + Effective: uint64(resEffective), + LeaseIn: uint64(resLeaseIn), + LeaseOut: uint64(resLeaseOut)}, nil + + } + _, searchAddr := ws.diff.createNewWavesBalance(account) + err = ws.diff.addEffectiveToHistory(searchAddr, int64(balance.Effective)) + if err != nil { + return nil, err + } + return balance, nil +} + +func (ws *WrappedState) IsStateUntouched(account proto.Recipient) (bool, error) { + return ws.diff.state.IsStateUntouched(account) +} + +func (ws *WrappedState) RetrieveNewestIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + address, err := ws.diff.state.NewestRecipientToAddress(account) + if err != nil { + return nil, err + } + + if deletedDataEntry := ws.diff.findDeleteFromDataEntryByKey(key, address.String()); deletedDataEntry != nil { + return nil, nil + } + + if intDataEntry := ws.diff.findIntFromDataEntryByKey(key, address.String()); intDataEntry != nil { + return intDataEntry, nil + } + + return ws.diff.state.RetrieveNewestIntegerEntry(account, key) +} +func (ws *WrappedState) RetrieveNewestBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + address, err := ws.diff.state.NewestRecipientToAddress(account) + if err != nil { + return nil, err + } + + if deletedDataEntry := ws.diff.findDeleteFromDataEntryByKey(key, address.String()); deletedDataEntry != nil { + return nil, nil + } + + if boolDataEntry := ws.diff.findBoolFromDataEntryByKey(key, address.String()); boolDataEntry != nil { + return boolDataEntry, nil + } + return ws.diff.state.RetrieveNewestBooleanEntry(account, key) +} +func (ws *WrappedState) RetrieveNewestStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + address, err := ws.diff.state.NewestRecipientToAddress(account) + if err != nil { + return nil, err + } + + if deletedDataEntry := ws.diff.findDeleteFromDataEntryByKey(key, address.String()); deletedDataEntry != nil { + return nil, nil + } + + if stringDataEntry := ws.diff.findStringFromDataEntryByKey(key, address.String()); stringDataEntry != nil { + return stringDataEntry, nil + } + return ws.diff.state.RetrieveNewestStringEntry(account, key) +} +func (ws *WrappedState) RetrieveNewestBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + address, err := ws.diff.state.NewestRecipientToAddress(account) + if err != nil { + return nil, err + } + + if deletedDataEntry := ws.diff.findDeleteFromDataEntryByKey(key, address.String()); deletedDataEntry != nil { + return nil, nil + } + + if binaryDataEntry := ws.diff.findBinaryFromDataEntryByKey(key, address.String()); binaryDataEntry != nil { + return binaryDataEntry, nil + } + return ws.diff.state.RetrieveNewestBinaryEntry(account, key) +} +func (ws *WrappedState) NewestAssetIsSponsored(assetID crypto.Digest) (bool, error) { + if cost := ws.diff.findSponsorship(assetID); cost != nil { + if *cost == 0 { + return false, nil + } + return true, nil + } + return ws.diff.state.NewestAssetIsSponsored(assetID) +} +func (ws *WrappedState) NewestAssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { + searchNewAsset := ws.diff.findNewAsset(assetID) + + if searchNewAsset == nil { + + assetFromStore, err := ws.diff.state.NewestAssetInfo(assetID) + if err != nil { + return nil, errors.Wrap(err, "failed to get asset's info from store") + } + + if oldAssetFromDiff := ws.diff.findOldAsset(assetID); oldAssetFromDiff != nil { + quantity := int64(assetFromStore.Quantity) + oldAssetFromDiff.diffQuantity + + assetFromStore.Quantity = uint64(quantity) + return assetFromStore, nil + } + + return assetFromStore, nil + } + + issuerPK, err := ws.NewestScriptPKByAddr(searchNewAsset.dAppIssuer) + if err != nil { + return nil, errors.Wrap(err, "failed to get issuerPK from address in NewestAssetInfo") + } + + scripted := false + if searchNewAsset.script != nil { + scripted = true + } + + sponsored, err := ws.NewestAssetIsSponsored(assetID) + if err != nil { + return nil, errors.Wrap(err, "failed to find out sponsoring of the asset") + } + + return &proto.AssetInfo{ + ID: assetID, + Quantity: uint64(searchNewAsset.quantity), + Decimals: uint8(searchNewAsset.decimals), + Issuer: searchNewAsset.dAppIssuer, + IssuerPublicKey: issuerPK, + Reissuable: searchNewAsset.reissuable, + Scripted: scripted, + Sponsored: sponsored, + }, nil +} +func (ws *WrappedState) NewestFullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { + searchNewAsset := ws.diff.findNewAsset(assetID) + + if searchNewAsset == nil { + + assetFromStore, err := ws.diff.state.NewestFullAssetInfo(assetID) + if err != nil { + return nil, errors.Wrap(err, "failed to get asset's info from store") + } + + if oldAssetFromDiff := ws.diff.findOldAsset(assetID); oldAssetFromDiff != nil { + quantity := int64(assetFromStore.Quantity) + oldAssetFromDiff.diffQuantity + + if quantity >= 0 { + assetFromStore.Quantity = uint64(quantity) + return assetFromStore, nil + } + + return nil, errors.Errorf("quantity of the asset is negative") + } + + return assetFromStore, nil + } + + issuerPK, err := ws.NewestScriptPKByAddr(searchNewAsset.dAppIssuer) + if err != nil { + return nil, errors.Wrap(err, "failed to get issuerPK from address in NewestAssetInfo") + } + + scripted := false + if searchNewAsset.script != nil { + scripted = true + } + + sponsored, err := ws.NewestAssetIsSponsored(assetID) + if err != nil { + return nil, errors.Wrap(err, "failed to find out sponsoring of the asset") + } + + assetInfo := proto.AssetInfo{ + ID: assetID, + Quantity: uint64(searchNewAsset.quantity), + Decimals: uint8(searchNewAsset.decimals), + Issuer: searchNewAsset.dAppIssuer, + IssuerPublicKey: issuerPK, + Reissuable: searchNewAsset.reissuable, + Scripted: scripted, + Sponsored: sponsored, + } + scriptInfo := proto.ScriptInfo{ + Bytes: searchNewAsset.script, + } + + sponsorshipCost := int64(0) + if sponsorship := ws.diff.findSponsorship(assetID); sponsorship != nil { + sponsorshipCost = *sponsorship + } + + return &proto.FullAssetInfo{ + AssetInfo: assetInfo, + Name: searchNewAsset.name, + Description: searchNewAsset.description, + ScriptInfo: scriptInfo, + SponsorshipCost: uint64(sponsorshipCost), + }, nil +} + +func (ws *WrappedState) NewestHeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { + return ws.diff.state.NewestHeaderByHeight(height) +} +func (ws *WrappedState) BlockVRF(blockHeader *proto.BlockHeader, height proto.Height) ([]byte, error) { + return ws.diff.state.BlockVRF(blockHeader, height) +} + +func (ws *WrappedState) EstimatorVersion() (int, error) { + return ws.diff.state.EstimatorVersion() +} +func (ws *WrappedState) IsNotFound(err error) bool { + return ws.diff.state.IsNotFound(err) +} + +func (ws *WrappedState) NewestScriptByAsset(asset proto.OptionalAsset) (proto.Script, error) { + return ws.diff.state.NewestScriptByAsset(asset) +} + +func (ws *WrappedState) newMaxScriptComplexity(scriptVersion int) int { + maxScriptActions := proto.NewMaxScriptActions() + return maxScriptActions.GetMaxScriptsComplexityInBlock(scriptVersion) +} + +func (ws *WrappedState) validateAsset(action proto.ScriptAction, asset proto.OptionalAsset, env Environment) (bool, error) { + if !asset.Present { + return true, nil + } + + assetInfo, err := ws.NewestAssetInfo(asset.ID) + if err != nil { + return false, err + } + if !assetInfo.Scripted { + return true, nil + } + + txID, err := crypto.NewDigestFromBytes(env.txID().(rideBytes)) + if err != nil { + return false, err + } + + timestamp := env.timestamp() + + localEnv, err := NewEnvironment(env.scheme(), env.state()) + if err != nil { + return false, err + } + + switch res := action.(type) { + + case *proto.TransferScriptAction: + sender, err := proto.NewAddressFromPublicKey(localEnv.scheme(), *res.Sender) + if err != nil { + return false, err + } + + fullTr := &proto.FullScriptTransfer{ + Amount: uint64(res.Amount), + Asset: res.Asset, + Recipient: res.Recipient, + Sender: sender, + Timestamp: timestamp, + ID: &txID, + } + localEnv.SetTransactionFromScriptTransfer(fullTr) + + case *proto.ReissueScriptAction, *proto.BurnScriptAction: + err = localEnv.SetTransactionFromScriptAction(action, *action.SenderPK(), txID, timestamp) + if err != nil { + return false, err + } + + } + + script, err := ws.NewestScriptByAsset(asset) + if err != nil { + return false, err + } + + tree, err := Parse(script) + if err != nil { + return false, errors.Wrap(err, "failed to get tree by script") + } + + localEnv.ChooseSizeCheck(tree.LibVersion) + switch tree.LibVersion { + case 4, 5: + assetInfo, err := ws.NewestFullAssetInfo(asset.ID) + if err != nil { + return false, err + } + localEnv.SetThisFromFullAssetInfo(assetInfo) + default: + assetInfo, err := ws.NewestAssetInfo(asset.ID) + if err != nil { + return false, err + } + localEnv.SetThisFromAssetInfo(assetInfo) + } + + if err := localEnv.ChooseTakeString(true); err != nil { + return false, errors.Wrap(err, "failed to initialize local environment") + } + + r, err := CallVerifier(localEnv, tree) + if err != nil { + return false, errors.Wrapf(err, "failed to call script on asset '%s'", asset.String()) + } + if !r.Result() { + return false, errs.NewTransactionNotAllowedByScript(r.UserError(), asset.ID.Bytes()) + } + + return r.Result(), nil +} + +func (ws *WrappedState) validateTransferAction(otherActionsCount *int, res *proto.TransferScriptAction, restrictions proto.ActionsValidationRestrictions, sender proto.Address, env Environment) error { + *otherActionsCount++ + + assetResult, err := ws.validateAsset(res, res.Asset, env) + if err != nil { + return errors.Wrapf(err, "failed to validate asset") + } + if !assetResult { + return errors.New("action is forbidden by smart asset script") + } + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.Amount < 0 { + return errors.New("negative transfer amount") + } + if restrictions.DisableSelfTransfers { + senderAddress := restrictions.ScriptAddress + if res.SenderPK() != nil { + var err error + senderAddress, err = proto.NewAddressFromPublicKey(restrictions.Scheme, *res.SenderPK()) + if err != nil { + return errors.Wrap(err, "failed to validate TransferScriptAction") + } + } + if res.Recipient.Address.Eq(senderAddress) { + return errors.New("transfers to DApp itself are forbidden since activation of RIDE V4") + } + } + senderRcp := proto.NewRecipientFromAddress(sender) + balance, err := ws.NewestAccountBalance(senderRcp, res.Asset.ID.Bytes()) + if err != nil { + return err + } + + if balance < uint64(res.Amount) { + return errors.Errorf("not enough money in the DApp. balance of DApp with address %s is %d and it tried to transfer asset %s to %s, amount of %d", + sender.String(), balance, res.Asset.String(), res.Recipient.Address.String(), res.Amount) + } + + return nil +} + +func (ws *WrappedState) validateDataEntryAction(dataEntriesCount *int, dataEntriesSize *int, res *proto.DataEntryScriptAction, restrictions proto.ActionsValidationRestrictions) error { + *dataEntriesCount++ + if *dataEntriesCount > proto.MaxDataEntryScriptActions { + return errors.Errorf("number of data entries produced by script is more than allowed %d", proto.MaxDataEntryScriptActions) + } + switch restrictions.KeySizeValidationVersion { + case 1: + if len(utf16.Encode([]rune(res.Entry.GetKey()))) > proto.MaxKeySize { + return errs.NewTooBigArray("key is too large") + } + default: + if len([]byte(res.Entry.GetKey())) > proto.MaxPBKeySize { + return errs.NewTooBigArray("key is too large") + } + } + + *dataEntriesSize += res.Entry.BinarySize() + if *dataEntriesSize > proto.MaxDataEntryScriptActionsSizeInBytes { + return errors.Errorf("total size of data entries produced by script is more than %d bytes", proto.MaxDataEntryScriptActionsSizeInBytes) + } + return nil +} + +func (ws *WrappedState) validateIssueAction(otherActionsCount *int, res *proto.IssueScriptAction) error { + *otherActionsCount++ + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.Quantity < 0 { + return errors.New("negative quantity") + } + if res.Decimals < 0 || res.Decimals > proto.MaxDecimals { + return errors.New("invalid decimals") + } + if l := len(res.Name); l < proto.MinAssetNameLen || l > proto.MaxAssetNameLen { + return errors.New("invalid asset's name") + } + if l := len(res.Description); l > proto.MaxDescriptionLen { + return errors.New("invalid asset's description") + } + return nil } -func NewEnvironment(scheme proto.Scheme, state types.SmartState) (*Environment, error) { +func (ws *WrappedState) validateReissueAction(otherActionsCount *int, res *proto.ReissueScriptAction, env Environment) error { + *otherActionsCount++ + + asset := proto.NewOptionalAssetFromDigest(res.AssetID) + assetResult, err := ws.validateAsset(res, *asset, env) + if err != nil { + return errors.Wrapf(err, "failed to validate asset") + } + if !assetResult { + return errors.New("action is forbidden by smart asset script") + } + + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.Quantity < 0 { + return errors.New("negative quantity") + } + + assetInfo, err := ws.NewestAssetInfo(res.AssetID) + if err != nil { + return err + } + + if !assetInfo.Reissuable { + return errors.New("failed to reissue asset as it's not reissuable anymore") + } + + return nil +} + +func (ws *WrappedState) validateBurnAction(otherActionsCount *int, res *proto.BurnScriptAction, env Environment) error { + *otherActionsCount++ + + asset := proto.NewOptionalAssetFromDigest(res.AssetID) + assetResult, err := ws.validateAsset(res, *asset, env) + if err != nil { + return errors.Wrapf(err, "failed to validate asset") + } + if !assetResult { + return errors.New("action is forbidden by smart asset script") + } + + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.Quantity < 0 { + return errors.New("negative quantity") + } + assetInfo, err := ws.NewestAssetInfo(res.AssetID) + if err != nil { + return err + } + + if assetInfo.Quantity < uint64(res.Quantity) { + return errors.New("quantity of asset is less than what was tried to burn") + } + + return nil +} + +func (ws *WrappedState) validateSponsorshipAction(otherActionsCount *int, res *proto.SponsorshipScriptAction) error { + *otherActionsCount++ + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.MinFee < 0 { + return errors.New("negative minimal fee") + } + + return nil +} + +func (ws *WrappedState) validateLeaseAction(otherActionsCount *int, res *proto.LeaseScriptAction, restrictions proto.ActionsValidationRestrictions) error { + *otherActionsCount++ + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + if res.Amount < 0 { + return errors.New("negative leasing amount") + } + senderAddress := restrictions.ScriptAddress + if res.SenderPK() != nil { + var err error + senderAddress, err = proto.NewAddressFromPublicKey(restrictions.Scheme, *res.SenderPK()) + if err != nil { + return errors.Wrap(err, "failed to validate TransferScriptAction") + } + } + if res.Recipient.Address.Eq(senderAddress) { + return errors.New("leasing to DApp itself is forbidden") + } + + balance, err := ws.NewestFullWavesBalance(proto.NewRecipientFromAddress(ws.callee())) + if err != nil { + return err + } + if balance.Available < uint64(res.Amount) { + return errors.New("not enough money on the available balance of the account") + } + return nil +} + +func (ws *WrappedState) validateLeaseCancelAction(otherActionsCount *int) error { + *otherActionsCount++ + scriptVersion, err := ws.getLibVersion() + if err != nil { + return err + } + maxScriptAction := ws.newMaxScriptComplexity(scriptVersion) + + if *otherActionsCount > maxScriptAction { + return errors.Errorf("number of actions produced by script is more than allowed %d", maxScriptAction) + } + return nil +} + +func (ws *WrappedState) getLibVersion() (int, error) { + script, err := ws.GetByteTree(proto.NewRecipientFromAddress(ws.callee())) + if err != nil { + return 0, errors.Wrap(err, "failed to get script by recipient") + } + tree, err := Parse(script) + if err != nil { + return 0, errors.Wrap(err, "failed to get tree by script") + } + return tree.LibVersion, nil +} + +func (ws *WrappedState) invCount() uint64 { + return ws.invokeCount +} + +func (ws *WrappedState) incrementInvCount() { + ws.invokeCount++ +} + +func (ws *WrappedState) ApplyToState(actions []proto.ScriptAction, env Environment) ([]proto.ScriptAction, error) { + dataEntriesCount := 0 + dataEntriesSize := 0 + otherActionsCount := 0 + libVersion, err := ws.getLibVersion() + if err != nil { + return nil, err + } + + disableSelfTransfers := libVersion >= 4 + var keySizeValidationVersion byte = 1 + if libVersion >= 4 { + keySizeValidationVersion = 2 + } + restrictions := proto.ActionsValidationRestrictions{ + DisableSelfTransfers: disableSelfTransfers, + KeySizeValidationVersion: keySizeValidationVersion, + } + + for _, action := range actions { + switch res := action.(type) { + + case *proto.DataEntryScriptAction: + err := ws.validateDataEntryAction(&dataEntriesCount, &dataEntriesSize, res, restrictions) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of data entry action") + } + + switch dataEntry := res.Entry.(type) { + + case *proto.IntegerDataEntry: + addr := ws.callee() + senderPK, err := ws.diff.state.NewestScriptPKByAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + intEntry := *dataEntry + + ws.diff.dataEntries.diffInteger[dataEntry.Key+addr.String()] = intEntry + + case *proto.StringDataEntry: + addr := ws.callee() + senderPK, err := ws.diff.state.NewestScriptPKByAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + stringEntry := *dataEntry + + ws.diff.dataEntries.diffString[dataEntry.Key+addr.String()] = stringEntry + + case *proto.BooleanDataEntry: + addr := ws.callee() + senderPK, err := ws.diff.state.NewestScriptPKByAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + boolEntry := *dataEntry + + ws.diff.dataEntries.diffBool[dataEntry.Key+addr.String()] = boolEntry + + case *proto.BinaryDataEntry: + addr := ws.callee() + senderPK, err := ws.diff.state.NewestScriptPKByAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + binaryEntry := *dataEntry + + ws.diff.dataEntries.diffBinary[dataEntry.Key+addr.String()] = binaryEntry + + case *proto.DeleteDataEntry: + addr := ws.callee() + senderPK, err := ws.diff.state.NewestScriptPKByAddr(addr) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + deleteEntry := *dataEntry + + ws.diff.dataEntries.diffDDelete[dataEntry.Key+addr.String()] = deleteEntry + + default: + + } + + case *proto.TransferScriptAction: + var senderAddress proto.Address + var senderPK crypto.PublicKey + if res.Sender != nil { + senderPK = *res.Sender + var err error + senderAddress, err = proto.NewAddressFromPublicKey(ws.scheme, senderPK) + if err != nil { + return nil, errors.Wrap(err, "failed to get address by public key") + } + } else { + pk, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + senderPK = pk + senderAddress = ws.callee() + + res.Sender = &senderPK + } + + err = ws.validateTransferAction(&otherActionsCount, res, restrictions, senderAddress, env) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of transfer action or attached payments") + } + + searchBalance, searchAddr, err := ws.diff.findBalance(res.Recipient, res.Asset) + if err != nil { + return nil, err + } + err = ws.diff.changeBalance(searchBalance, searchAddr, res.Amount, res.Asset.ID, res.Recipient) + if err != nil { + return nil, err + } + + senderRecipient := proto.NewRecipientFromAddress(senderAddress) + senderSearchBalance, senderSearchAddr, err := ws.diff.findBalance(senderRecipient, res.Asset) + if err != nil { + return nil, err + } + + err = ws.diff.changeBalance(senderSearchBalance, senderSearchAddr, -res.Amount, res.Asset.ID, senderRecipient) + if err != nil { + return nil, err + } + + case *proto.SponsorshipScriptAction: + senderPK, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + err = ws.validateSponsorshipAction(&otherActionsCount, res) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + var sponsorship diffSponsorship + sponsorship.MinFee = res.MinFee + + ws.diff.sponsorships[res.AssetID.String()] = sponsorship + + case *proto.IssueScriptAction: + err := ws.validateIssueAction(&otherActionsCount, res) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + var assetInfo diffNewAssetInfo + assetInfo.dAppIssuer = ws.callee() + assetInfo.name = res.Name + assetInfo.description = res.Description + assetInfo.quantity = res.Quantity + assetInfo.decimals = res.Decimals + assetInfo.reissuable = res.Reissuable + assetInfo.script = res.Script + assetInfo.nonce = res.Nonce + + ws.diff.newAssetsInfo[res.ID.String()] = assetInfo + + senderPK, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + senderRcp := proto.NewRecipientFromAddress(ws.callee()) + asset := proto.NewOptionalAssetFromDigest(res.ID) + searchBalance, searchAddr, err := ws.diff.findBalance(senderRcp, *asset) + if err != nil { + return nil, err + } + err = ws.diff.changeBalance(searchBalance, searchAddr, res.Quantity, asset.ID, senderRcp) + if err != nil { + return nil, err + } + + case *proto.ReissueScriptAction: + senderPK, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + err = ws.validateReissueAction(&otherActionsCount, res, env) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + searchNewAsset := ws.diff.findNewAsset(res.AssetID) + if searchNewAsset == nil { + if oldAssetFromDiff := ws.diff.findOldAsset(res.AssetID); oldAssetFromDiff != nil { + oldAssetFromDiff.diffQuantity += res.Quantity + + ws.diff.oldAssetsInfo[res.AssetID.String()] = *oldAssetFromDiff + break + } + var assetInfo diffOldAssetInfo + assetInfo.diffQuantity += res.Quantity + ws.diff.oldAssetsInfo[res.AssetID.String()] = assetInfo + break + } + ws.diff.reissueNewAsset(res.AssetID, res.Quantity, res.Reissuable) + + case *proto.BurnScriptAction: + senderPK, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + res.Sender = &senderPK + + err = ws.validateBurnAction(&otherActionsCount, res, env) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + searchAsset := ws.diff.findNewAsset(res.AssetID) + if searchAsset == nil { + if oldAssetFromDiff := ws.diff.findOldAsset(res.AssetID); oldAssetFromDiff != nil { + oldAssetFromDiff.diffQuantity -= res.Quantity + + ws.diff.oldAssetsInfo[res.AssetID.String()] = *oldAssetFromDiff + break + } + var assetInfo diffOldAssetInfo + assetInfo.diffQuantity -= res.Quantity + ws.diff.oldAssetsInfo[res.AssetID.String()] = assetInfo + break + } + ws.diff.burnNewAsset(res.AssetID, res.Quantity) + + case *proto.LeaseScriptAction: + senderAddress := ws.callee() + pk, err := ws.diff.state.NewestScriptPKByAddr(senderAddress) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + + res.Sender = &pk + + err = ws.validateLeaseAction(&otherActionsCount, res, restrictions) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + recipientSearchBalance, recipientSearchAddress, err := ws.diff.findBalance(res.Recipient, proto.NewOptionalAssetWaves()) + if err != nil { + return nil, err + } + err = ws.diff.changeLeaseIn(recipientSearchBalance, recipientSearchAddress, res.Amount, res.Recipient) + if err != nil { + return nil, err + } + + senderAccount := proto.NewRecipientFromAddress(senderAddress) + senderSearchBalance, senderSearchAddr, err := ws.diff.findBalance(senderAccount, proto.NewOptionalAssetWaves()) + if err != nil { + return nil, err + } + + err = ws.diff.changeLeaseOut(senderSearchBalance, senderSearchAddr, res.Amount, senderAccount) + if err != nil { + return nil, err + } + + ws.diff.addNewLease(res.Recipient, senderAccount, res.Amount, res.ID) + + case *proto.LeaseCancelScriptAction: + pk, err := ws.diff.state.NewestScriptPKByAddr(ws.callee()) + if err != nil { + return nil, errors.Wrap(err, "failed to get public key by address") + } + + res.Sender = &pk + + err = ws.validateLeaseCancelAction(&otherActionsCount) + if err != nil { + return nil, errors.Wrapf(err, "failed to pass validation of issue action") + } + + searchLease, err := ws.diff.findLeaseByIDForCancel(res.LeaseID) + if err != nil { + return nil, errors.Errorf("failed to find lease by leaseID") + } + if searchLease == nil { + return nil, errors.Errorf("there is no lease to cancel") + } + + recipientBalance, recipientSearchAddress, err := ws.diff.findBalance(searchLease.Recipient, proto.NewOptionalAssetWaves()) + if err != nil { + return nil, err + } + if recipientBalance == nil { + _, recipientSearchAddress = ws.diff.createNewWavesBalance(searchLease.Recipient) + } + + senderBalance, senderSearchAddress, err := ws.diff.findBalance(searchLease.Sender, proto.NewOptionalAssetWaves()) + if err != nil { + return nil, err + } + if senderBalance == nil { + _, senderSearchAddress = ws.diff.createNewWavesBalance(searchLease.Sender) + } + + ws.diff.cancelLease(*searchLease, senderSearchAddress, recipientSearchAddress) + + default: + } + } + + return actions, nil +} + +type EvaluationEnvironment struct { + sch proto.Scheme + st types.SmartState + h rideInt + tx rideObject + id rideType + th rideType + time uint64 + b rideObject + check func(int) bool + takeStr func(s string, n int) rideString + inv rideObject + ver int +} + +func NewEnvironment(scheme proto.Scheme, state types.SmartState) (*EvaluationEnvironment, error) { height, err := state.AddingBlockHeight() if err != nil { return nil, err } - return &Environment{ - sch: scheme, - st: state, - h: rideInt(height), - tx: nil, - id: nil, - th: nil, - b: nil, - check: func(int) bool { return true }, - inv: nil, + + return &EvaluationEnvironment{ + sch: scheme, + st: state, + h: rideInt(height), + check: func(int) bool { return true }, // By default, for versions below 2 there was no check, always ok. + takeStr: func(s string, n int) rideString { panic("function 'takeStr' was not initialized") }, + }, nil +} + +func NewEnvironmentWithWrappedState(env *EvaluationEnvironment, payments proto.ScriptPayments, callerPK crypto.PublicKey) (*EvaluationEnvironment, error) { + caller, err := proto.NewAddressFromPublicKey(env.sch, callerPK) + if err != nil { + return nil, errors.Wrap(err, "failed to create RIDE environment with wrapped state") + } + recipient := proto.NewRecipientFromAddress(proto.Address(env.th.(rideAddress))) + + env.inv["originalCaller"] = rideAddress(caller) + env.inv["originalCallerPublicKey"] = rideBytes(callerPK.Bytes()) + //TODO add test for these fields + + st := newWrappedState(env) + + for _, payment := range payments { + senderBalance, err := st.NewestAccountBalance(proto.NewRecipientFromAddress(caller), payment.Asset.ID.Bytes()) + if err != nil { + return nil, err + } + if senderBalance < payment.Amount { + return nil, errors.New("not enough money for tx attached payments") + } + + searchBalance, searchAddr, err := st.diff.findBalance(recipient, payment.Asset) + if err != nil { + return nil, errors.Wrap(err, "failed to create RIDE environment with wrapped state") + } + err = st.diff.changeBalance(searchBalance, searchAddr, int64(payment.Amount), payment.Asset.ID, recipient) + if err != nil { + return nil, errors.Wrap(err, "failed to create RIDE environment with wrapped state") + } + + callerRcp := proto.NewRecipientFromAddress(caller) + senderSearchBalance, senderSearchAddr, err := st.diff.findBalance(callerRcp, payment.Asset) + if err != nil { + return nil, errors.Wrap(err, "failed to create RIDE environment with wrapped state") + } + + err = st.diff.changeBalance(senderSearchBalance, senderSearchAddr, -int64(payment.Amount), payment.Asset.ID, callerRcp) + if err != nil { + return nil, errors.Wrap(err, "failed to create RIDE environment with wrapped state") + } + } + + return &EvaluationEnvironment{ + sch: env.sch, + st: st, + h: env.h, + tx: env.tx, + id: env.id, + th: env.th, + b: env.b, + check: env.check, + takeStr: env.takeStr, + inv: env.inv, }, nil } -func (e *Environment) ChooseSizeCheck(v int) { +func (e *EvaluationEnvironment) ChooseTakeString(isRideV5 bool) error { + if !isRideV5 { + e.takeStr = takeRideStringWrong + return nil + } + e.takeStr = takeRideString + return nil +} + +func (e *EvaluationEnvironment) ChooseSizeCheck(v int) { + e.ver = v if v > 2 { e.check = func(l int) bool { return l <= maxMessageLength @@ -44,28 +1155,32 @@ func (e *Environment) ChooseSizeCheck(v int) { } } -func (e *Environment) SetThisFromFullAssetInfo(info *proto.FullAssetInfo) { +func (e *EvaluationEnvironment) SetThisFromFullAssetInfo(info *proto.FullAssetInfo) { e.th = fullAssetInfoToObject(info) } -func (e *Environment) SetThisFromAssetInfo(info *proto.AssetInfo) { +func (e *EvaluationEnvironment) SetTimestamp(timestamp uint64) { + e.time = timestamp +} + +func (e *EvaluationEnvironment) SetThisFromAssetInfo(info *proto.AssetInfo) { e.th = assetInfoToObject(info) } -func (e *Environment) SetThisFromAddress(addr proto.Address) { +func (e *EvaluationEnvironment) SetThisFromAddress(addr proto.Address) { e.th = rideAddress(addr) } -func (e *Environment) SetLastBlock(info *proto.BlockInfo) { +func (e *EvaluationEnvironment) SetLastBlock(info *proto.BlockInfo) { e.b = blockInfoToObject(info) } -func (e *Environment) SetTransactionFromScriptTransfer(transfer *proto.FullScriptTransfer) { +func (e *EvaluationEnvironment) SetTransactionFromScriptTransfer(transfer *proto.FullScriptTransfer) { e.id = rideBytes(transfer.ID.Bytes()) e.tx = scriptTransferToObject(transfer) } -func (e *Environment) SetTransactionWithoutProofs(tx proto.Transaction) error { +func (e *EvaluationEnvironment) SetTransactionWithoutProofs(tx proto.Transaction) error { err := e.SetTransaction(tx) if err != nil { return err @@ -74,7 +1189,7 @@ func (e *Environment) SetTransactionWithoutProofs(tx proto.Transaction) error { return nil } -func (e *Environment) SetTransactionFromScriptAction(action proto.ScriptAction, pk crypto.PublicKey, id crypto.Digest, ts uint64) error { +func (e *EvaluationEnvironment) SetTransactionFromScriptAction(action proto.ScriptAction, pk crypto.PublicKey, id crypto.Digest, ts uint64) error { obj, err := scriptActionToObject(e.sch, action, pk, id, ts) if err != nil { return err @@ -83,7 +1198,7 @@ func (e *Environment) SetTransactionFromScriptAction(action proto.ScriptAction, return nil } -func (e *Environment) SetTransaction(tx proto.Transaction) error { +func (e *EvaluationEnvironment) SetTransaction(tx proto.Transaction) error { id, err := tx.GetID(e.sch) if err != nil { return err @@ -97,7 +1212,7 @@ func (e *Environment) SetTransaction(tx proto.Transaction) error { return nil } -func (e *Environment) SetTransactionFromOrder(order proto.Order) error { +func (e *EvaluationEnvironment) SetTransactionFromOrder(order proto.Order) error { obj, err := orderToObject(e.sch, order) if err != nil { return err @@ -106,7 +1221,7 @@ func (e *Environment) SetTransactionFromOrder(order proto.Order) error { return nil } -func (e *Environment) SetInvoke(tx *proto.InvokeScriptWithProofs, v int) error { +func (e *EvaluationEnvironment) SetInvoke(tx *proto.InvokeScriptWithProofs, v int) error { obj, err := invocationToObject(v, e.sch, tx) if err != nil { return err @@ -115,38 +1230,74 @@ func (e *Environment) SetInvoke(tx *proto.InvokeScriptWithProofs, v int) error { return nil } -func (e *Environment) scheme() byte { +func (e *EvaluationEnvironment) timestamp() uint64 { + return e.time +} + +func (e *EvaluationEnvironment) scheme() byte { return e.sch } -func (e *Environment) height() rideInt { +func (e *EvaluationEnvironment) height() rideInt { return e.h } -func (e *Environment) transaction() rideObject { +func (e *EvaluationEnvironment) transaction() rideObject { return e.tx } -func (e *Environment) this() rideType { +func (e *EvaluationEnvironment) this() rideType { return e.th } -func (e *Environment) block() rideObject { +func (e *EvaluationEnvironment) block() rideObject { return e.b } -func (e *Environment) txID() rideType { +func (e *EvaluationEnvironment) txID() rideType { return e.id } -func (e *Environment) state() types.SmartState { +func (e *EvaluationEnvironment) state() types.SmartState { return e.st } -func (e *Environment) checkMessageLength(l int) bool { +func (e *EvaluationEnvironment) setNewDAppAddress(address proto.Address) { + ws, _ := e.st.(*WrappedState) + ws.cle = rideAddress(address) + + e.SetThisFromAddress(address) +} + +func (e *EvaluationEnvironment) checkMessageLength(l int) bool { return e.check(l) } -func (e *Environment) invocation() rideObject { +func (e *EvaluationEnvironment) takeString(s string, n int) rideString { + return e.takeStr(s, n) +} + +func (e *EvaluationEnvironment) invocation() rideObject { return e.inv } + +func (e *EvaluationEnvironment) setInvocation(inv rideObject) { + e.inv = inv +} + +func (e *EvaluationEnvironment) libVersion() int { + return e.ver +} + +func isAssetWaves(assetID []byte) bool { + wavesAsset := crypto.Digest{} + if len(wavesAsset) != len(assetID) { + return false + } + for i := range assetID { + if assetID[i] != wavesAsset[i] { + return false + } + } + return true +} diff --git a/pkg/ride/functions.go b/pkg/ride/functions.go index f6631efef..ffabd8d2a 100644 --- a/pkg/ride/functions.go +++ b/pkg/ride/functions.go @@ -2,10 +2,18 @@ package ride -var _functions_V2 = [...]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionByID, transactionHeightByID, assetBalanceV3, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, fraction, throw, sizeBytes, takeBytes, dropBytes, concatBytes, concatStrings, takeString, dropString, sizeString, sizeList, getList, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, toBase58, fromBase58, toBase64, fromBase64, address, alias, assetPair, dataEntry, dataTransaction, addressFromPublicKey, addressFromString, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, takeRightString, takeRightBytes, throw0, wavesBalanceV3} +var _functions_V2 [68]rideFunction + +func init() { + _functions_V2 = [68]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionByID, transactionHeightByID, assetBalanceV3, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, fraction, throw, sizeBytes, takeBytes, dropBytes, concatBytes, concatStrings, takeString, dropString, sizeString, sizeList, getList, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, toBase58, fromBase58, toBase64, fromBase64, address, alias, assetPair, dataEntry, dataTransaction, addressFromPublicKey, addressFromString, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, takeRightString, takeRightBytes, throw0, wavesBalanceV3} +} + var _catalogue_V2 = [...]int{11, 26, 9, 1, 1, 1, 100, 100, 100, 1, 1, 1, 1, 10, 10, 10, 10, 1, 100, 100, 100, 100, 1, 100, 1, 1, 1, 1, 1, 10, 10, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 100, 10, 10, 10, 10, 10, 10, 10, 1, 1, 2, 2, 9, 82, 124, 19, 19, 13, 30, 30, 30, 30, 35, 19, 19, 2, 109} + var CatalogueV2 = map[string]int{"!": 11, "!=": 26, "-": 9, "0": 1, "1": 1, "100": 1, "1000": 100, "1001": 100, "1003": 100, "101": 1, "102": 1, "103": 1, "104": 1, "1040": 10, "1041": 10, "1042": 10, "1043": 10, "105": 1, "1050": 100, "1051": 100, "1052": 100, "1053": 100, "106": 1, "1060": 100, "107": 1, "2": 1, "200": 1, "201": 1, "202": 1, "203": 10, "300": 10, "303": 1, "304": 1, "305": 1, "400": 2, "401": 2, "410": 1, "411": 1, "412": 1, "420": 1, "421": 1, "500": 100, "501": 10, "502": 10, "503": 10, "600": 10, "601": 10, "602": 10, "603": 10, "Address": 1, "Alias": 1, "AssetPair": 2, "DataEntry": 2, "DataTransaction": 9, "addressFromPublicKey": 82, "addressFromString": 124, "dropRight": 19, "dropRightBytes": 19, "extract": 13, "getBinary": 30, "getBoolean": 30, "getInteger": 30, "getString": 30, "isDefined": 35, "takeRight": 19, "takeRightBytes": 19, "throw": 2, "wavesBalance": 109} +var FreeFunctionsV2 = map[string]struct{}{"Address": {}, "Alias": {}, "AssetPair": {}, "DataEntry": {}, "DataTransaction": {}} + const _names_V2 = "!!=-011001000100110031011021031041040104110421043105105010511052105310610601072200201202203300303304305400401410411412420421500501502503600601602603AddressAliasAssetPairDataEntryDataTransactionaddressFromPublicKeyaddressFromStringdropRightdropRightBytesextractgetBinarygetBooleangetIntegergetStringisDefinedtakeRighttakeRightBytesthrowwavesBalance" var _index_V2 = [...]int{0, 1, 3, 4, 5, 6, 9, 13, 17, 21, 24, 27, 30, 33, 37, 41, 45, 49, 52, 56, 60, 64, 68, 71, 75, 78, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 155, 160, 169, 178, 193, 213, 230, 239, 253, 260, 269, 279, 289, 298, 307, 316, 330, 335, 347} @@ -16,12 +24,14 @@ func functionNameV2(i int) string { } return _names_V2[_index_V2[i]:_index_V2[i+1]] } + func functionV2(id int) rideFunction { if id < 0 || id > 67 { return nil } return _functions_V2[id] } + func checkFunctionV2(name string) (uint16, bool) { for i := 0; i <= 67; i++ { if _names_V2[_index_V2[i]:_index_V2[i+1]] == name { @@ -30,6 +40,7 @@ func checkFunctionV2(name string) (uint16, bool) { } return 0, false } + func costV2(id int) int { if id < 0 || id > 67 { return -1 @@ -37,10 +48,18 @@ func costV2(id int) int { return _catalogue_V2[id] } -var _functions_V3 = [...]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionHeightByID, assetBalanceV3, assetInfoV3, blockInfoByHeight, transferByID, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, addressToString, fraction, pow, log, createList, bytesToUTF8String, bytesToInt, bytesToIntWithOffset, indexOfSubstring, indexOfSubstringWithOffset, splitString, parseInt, lastIndexOfSubstring, lastIndexOfSubstringWithOffset, throw, sizeBytes, takeBytes, dropBytes, concatBytes, concatStrings, takeString, dropString, sizeString, sizeList, getList, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, rsaVerify, toBase58, fromBase58, toBase64, fromBase64, toBase16, fromBase16, checkMerkleProof, intValueFromArray, booleanValueFromArray, bytesValueFromArray, stringValueFromArray, intValueFromState, booleanValueFromState, bytesValueFromState, stringValueFromState, addressValueFromString, bytesValueFromArrayByIndex, booleanValueFromArrayByIndex, intValueFromArrayByIndex, stringValueFromArrayByIndex, address, alias, assetPair, createBuy, createCeiling, dataEntry, dataTransaction, createDown, createFloor, createHalfDown, createHalfEven, createHalfUp, createMd5, createNoAlg, scriptResult, scriptTransfer, createSell, createSha1, createSha224, createSha256, createSha3224, createSha3256, createSha3384, createSha3512, createSha384, createSha512, transferSet, unit, createUp, writeSet, addressFromPublicKey, addressFromString, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, parseIntValue, takeRightString, takeRightBytes, throw0, value, valueOrErrorMessage, wavesBalanceV3} +var _functions_V3 [128]rideFunction + +func init() { + _functions_V3 = [128]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionHeightByID, assetBalanceV3, assetInfoV3, blockInfoByHeight, transferByID, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, addressToString, fraction, pow, log, createList, bytesToUTF8String, bytesToInt, bytesToIntWithOffset, indexOfSubstring, indexOfSubstringWithOffset, splitString, parseInt, lastIndexOfSubstring, lastIndexOfSubstringWithOffset, throw, sizeBytes, takeBytes, dropBytes, concatBytes, concatStrings, takeString, dropString, sizeString, sizeList, getList, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, rsaVerify, toBase58, fromBase58, toBase64, fromBase64, toBase16, fromBase16, checkMerkleProof, intValueFromArray, booleanValueFromArray, bytesValueFromArray, stringValueFromArray, intValueFromState, booleanValueFromState, bytesValueFromState, stringValueFromState, addressValueFromString, bytesValueFromArrayByIndex, booleanValueFromArrayByIndex, intValueFromArrayByIndex, stringValueFromArrayByIndex, address, alias, assetPair, createBuy, createCeiling, dataEntry, dataTransaction, createDown, createFloor, createHalfDown, createHalfEven, createHalfUp, createMd5, createNoAlg, scriptResult, scriptTransfer, createSell, createSha1, createSha224, createSha256, createSha3224, createSha3256, createSha3384, createSha3512, createSha384, createSha512, transferSet, unit, createUp, writeSet, addressFromPublicKey, addressFromString, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, parseIntValue, takeRightString, takeRightBytes, throw0, value, valueOrErrorMessage, wavesBalanceV3} +} + var _catalogue_V3 = [...]int{1, 1, 1, 1, 1, 1, 100, 100, 100, 100, 100, 1, 1, 1, 1, 10, 10, 10, 10, 1, 100, 100, 100, 100, 1, 100, 10, 1, 100, 100, 2, 20, 10, 10, 20, 20, 100, 20, 20, 20, 1, 1, 1, 1, 10, 10, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 100, 10, 10, 10, 300, 10, 10, 10, 10, 10, 10, 30, 10, 10, 10, 10, 100, 100, 100, 100, 124, 10, 10, 10, 10, 1, 1, 2, 0, 0, 2, 9, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 82, 124, 19, 19, 13, 30, 30, 30, 30, 1, 20, 19, 19, 1, 13, 13, 109} + var CatalogueV3 = map[string]int{"!": 1, "!=": 1, "-": 1, "0": 1, "1": 1, "100": 1, "1001": 100, "1003": 100, "1004": 100, "1005": 100, "1006": 100, "101": 1, "102": 1, "103": 1, "104": 1, "1040": 10, "1041": 10, "1042": 10, "1043": 10, "105": 1, "1050": 100, "1051": 100, "1052": 100, "1053": 100, "106": 1, "1060": 100, "1061": 10, "107": 1, "108": 100, "109": 100, "1100": 2, "1200": 20, "1201": 10, "1202": 10, "1203": 20, "1204": 20, "1205": 100, "1206": 20, "1207": 20, "1208": 20, "2": 1, "200": 1, "201": 1, "202": 1, "203": 10, "300": 10, "303": 1, "304": 1, "305": 1, "400": 2, "401": 2, "410": 1, "411": 1, "412": 1, "420": 1, "421": 1, "500": 100, "501": 10, "502": 10, "503": 10, "504": 300, "600": 10, "601": 10, "602": 10, "603": 10, "604": 10, "605": 10, "700": 30, "@extrNative(1040)": 10, "@extrNative(1041)": 10, "@extrNative(1042)": 10, "@extrNative(1043)": 10, "@extrNative(1050)": 100, "@extrNative(1051)": 100, "@extrNative(1052)": 100, "@extrNative(1053)": 100, "@extrUser(addressFromString)": 124, "@extrUser(getBinary)": 10, "@extrUser(getBoolean)": 10, "@extrUser(getInteger)": 10, "@extrUser(getString)": 10, "Address": 1, "Alias": 1, "AssetPair": 2, "Buy": 0, "Ceiling": 0, "DataEntry": 2, "DataTransaction": 9, "Down": 0, "Floor": 0, "HalfDown": 0, "HalfEven": 0, "HalfUp": 0, "Md5": 0, "NoAlg": 0, "ScriptResult": 2, "ScriptTransfer": 3, "Sell": 0, "Sha1": 0, "Sha224": 0, "Sha256": 0, "Sha3224": 0, "Sha3256": 0, "Sha3384": 0, "Sha3512": 0, "Sha384": 0, "Sha512": 0, "TransferSet": 1, "Unit": 0, "Up": 0, "WriteSet": 1, "addressFromPublicKey": 82, "addressFromString": 124, "dropRight": 19, "dropRightBytes": 19, "extract": 13, "getBinary": 30, "getBoolean": 30, "getInteger": 30, "getString": 30, "isDefined": 1, "parseIntValue": 20, "takeRight": 19, "takeRightBytes": 19, "throw": 1, "value": 13, "valueOrErrorMessage": 13, "wavesBalance": 109} +var FreeFunctionsV3 = map[string]struct{}{"Address": {}, "Alias": {}, "AssetPair": {}, "DataEntry": {}, "DataTransaction": {}, "WriteSet": {}, "TransferSet": {}, "ScriptTransfer": {}, "ScriptResult": {}} + const _names_V3 = "!!=-0110010011003100410051006101102103104104010411042104310510501051105210531061060106110710810911001200120112021203120412051206120712082200201202203300303304305400401410411412420421500501502503504600601602603604605700@extrNative(1040)@extrNative(1041)@extrNative(1042)@extrNative(1043)@extrNative(1050)@extrNative(1051)@extrNative(1052)@extrNative(1053)@extrUser(addressFromString)@extrUser(getBinary)@extrUser(getBoolean)@extrUser(getInteger)@extrUser(getString)AddressAliasAssetPairBuyCeilingDataEntryDataTransactionDownFloorHalfDownHalfEvenHalfUpMd5NoAlgScriptResultScriptTransferSellSha1Sha224Sha256Sha3224Sha3256Sha3384Sha3512Sha384Sha512TransferSetUnitUpWriteSetaddressFromPublicKeyaddressFromStringdropRightdropRightBytesextractgetBinarygetBooleangetIntegergetStringisDefinedparseIntValuetakeRighttakeRightBytesthrowvaluevalueOrErrorMessagewavesBalance" var _index_V3 = [...]int{0, 1, 3, 4, 5, 6, 9, 13, 17, 21, 25, 29, 32, 35, 38, 41, 45, 49, 53, 57, 60, 64, 68, 72, 76, 79, 83, 87, 90, 93, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 209, 212, 215, 218, 235, 252, 269, 286, 303, 320, 337, 354, 382, 402, 423, 444, 464, 471, 476, 485, 488, 495, 504, 519, 523, 528, 536, 544, 550, 553, 558, 570, 584, 588, 592, 598, 604, 611, 618, 625, 632, 638, 644, 655, 659, 661, 669, 689, 706, 715, 729, 736, 745, 755, 765, 774, 783, 796, 805, 819, 824, 829, 848, 860} @@ -51,12 +70,14 @@ func functionNameV3(i int) string { } return _names_V3[_index_V3[i]:_index_V3[i+1]] } + func functionV3(id int) rideFunction { if id < 0 || id > 127 { return nil } return _functions_V3[id] } + func checkFunctionV3(name string) (uint16, bool) { for i := 0; i <= 127; i++ { if _names_V3[_index_V3[i]:_index_V3[i+1]] == name { @@ -65,6 +86,7 @@ func checkFunctionV3(name string) (uint16, bool) { } return 0, false } + func costV3(id int) int { if id < 0 || id > 127 { return -1 @@ -72,37 +94,94 @@ func costV3(id int) int { return _catalogue_V3[id] } -var _functions_V4 = [...]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionHeightByID, assetInfoV4, blockInfoByHeight, transferByID, wavesBalanceV4, assetBalanceV4, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, addressToString, addressFromString, fraction, transferFromProtobuf, pow, calculateAssetID, log, simplifiedIssue, fullIssue, limitedCreateList, appendToList, concatList, indexOfList, lastIndexOfList, listRemoveByIndex, bytesToUTF8String, bytesToInt, bytesToIntWithOffset, indexOfSubstring, indexOfSubstringWithOffset, splitString, parseInt, lastIndexOfSubstring, lastIndexOfSubstringWithOffset, makeString, newTuple2, newTuple3, newTuple4, newTuple5, newTuple6, newTuple7, newTuple8, newTuple9, newTuple10, newTuple11, newTuple12, newTuple13, newTuple14, newTuple15, newTuple16, newTuple17, newTuple18, newTuple19, newTuple20, newTuple21, newTuple22, throw, sizeBytes, takeBytes, dropBytes, concatBytes, bls12Groth16Verify_1, bls12Groth16Verify_2, bls12Groth16Verify_3, bls12Groth16Verify_4, bls12Groth16Verify_5, bls12Groth16Verify_6, bls12Groth16Verify_7, bls12Groth16Verify_8, bls12Groth16Verify_9, bls12Groth16Verify_10, bls12Groth16Verify_11, bls12Groth16Verify_12, bls12Groth16Verify_13, bls12Groth16Verify_14, bls12Groth16Verify_15, bn256Groth16Verify_1, bn256Groth16Verify_2, bn256Groth16Verify_3, bn256Groth16Verify_4, bn256Groth16Verify_5, bn256Groth16Verify_6, bn256Groth16Verify_7, bn256Groth16Verify_8, bn256Groth16Verify_9, bn256Groth16Verify_10, bn256Groth16Verify_11, bn256Groth16Verify_12, bn256Groth16Verify_13, bn256Groth16Verify_14, bn256Groth16Verify_15, sigVerify_8, sigVerify_16, sigVerify_32, sigVerify_64, sigVerify_128, rsaVerify_16, rsaVerify_32, rsaVerify_64, rsaVerify_128, keccak256_16, keccak256_32, keccak256_64, keccak256_128, blake2b256_16, blake2b256_32, blake2b256_64, blake2b256_128, sha256_16, sha256_32, sha256_64, sha256_128, concatStrings, takeString, dropString, sizeString, sizeList, getList, median, max, min, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, rsaVerify, toBase58, fromBase58, toBase64, fromBase64, toBase16, fromBase16, rebuildMerkleRoot, bls12Groth16Verify, bn256Groth16Verify, ecRecover, intValueFromArray, booleanValueFromArray, bytesValueFromArray, stringValueFromArray, intValueFromState, booleanValueFromState, bytesValueFromState, stringValueFromState, addressFromString, addressValueFromString, bytesValueFromArrayByIndex, booleanValueFromArrayByIndex, intValueFromArrayByIndex, stringValueFromArrayByIndex, address, alias, assetPair, checkedBytesDataEntry, checkedBooleanDataEntry, burn, createBuy, createCeiling, dataTransaction, checkedDeleteEntry, createDown, createFloor, createHalfDown, createHalfEven, createHalfUp, checkedIntDataEntry, createMd5, createNoAlg, reissue, scriptTransfer, createSell, createSha1, createSha224, createSha256, createSha3224, createSha3256, createSha3384, createSha3512, createSha384, createSha512, sponsorship, checkedStringDataEntry, unit, createUp, addressFromPublicKey, addressFromString, contains, containsElement, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, parseIntValue, takeRightString, takeRightBytes, throw0, value, valueOrElse, valueOrErrorMessage} -var _catalogue_V4 = [...]int{1, 1, 1, 1, 1, 1, 20, 15, 5, 60, 10, 10, 1, 1, 1, 1, 10, 10, 10, 10, 1, 10, 10, 10, 10, 1, 5, 10, 1, 1, 5, 100, 10, 100, 1, 1, 1, 1, 4, 5, 5, 7, 7, 1, 1, 3, 3, 75, 2, 3, 3, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 800, 850, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1550, 1600, 47, 57, 70, 102, 172, 500, 550, 625, 750, 10, 25, 50, 100, 10, 25, 50, 100, 10, 25, 50, 100, 20, 20, 20, 1, 2, 2, 20, 3, 3, 1, 8, 1, 1, 1, 200, 200, 200, 200, 1000, 3, 1, 35, 40, 10, 10, 30, 2700, 1650, 70, 10, 10, 10, 10, 10, 10, 10, 10, 1, 124, 10, 10, 10, 10, 1, 1, 2, 2, 2, 2, 0, 0, 9, 1, 0, 0, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 63, 124, 3, 5, 20, 6, 13, 30, 30, 30, 30, 1, 2, 20, 6, 1, 2, 2, 2} -var CatalogueV4 = map[string]int{"!": 1, "!=": 1, "-": 1, "0": 1, "1": 1, "100": 1, "1001": 20, "1004": 15, "1005": 5, "1006": 60, "1007": 10, "1008": 10, "101": 1, "102": 1, "103": 1, "104": 1, "1040": 10, "1041": 10, "1042": 10, "1043": 10, "105": 1, "1050": 10, "1051": 10, "1052": 10, "1053": 10, "106": 1, "1060": 5, "1061": 10, "1062": 1, "107": 1, "1070": 5, "108": 100, "1080": 10, "109": 100, "1090": 1, "1091": 1, "1100": 1, "1101": 1, "1102": 4, "1103": 5, "1104": 5, "1105": 7, "1200": 7, "1201": 1, "1202": 1, "1203": 3, "1204": 3, "1205": 75, "1206": 2, "1207": 3, "1208": 3, "1209": 30, "1300": 1, "1301": 1, "1302": 1, "1303": 1, "1304": 1, "1305": 1, "1306": 1, "1307": 1, "1308": 1, "1309": 1, "1310": 1, "1311": 1, "1312": 1, "1313": 1, "1314": 1, "1315": 1, "1316": 1, "1317": 1, "1318": 1, "1319": 1, "1320": 1, "2": 1, "200": 1, "201": 6, "202": 6, "203": 2, "2400": 1200, "2401": 1300, "2402": 1400, "2403": 1500, "2404": 1600, "2405": 1700, "2406": 1800, "2407": 1900, "2408": 2000, "2409": 2100, "2410": 2200, "2411": 2300, "2412": 2400, "2413": 2500, "2414": 2600, "2450": 800, "2451": 850, "2452": 950, "2453": 1000, "2454": 1050, "2455": 1100, "2456": 1150, "2457": 1200, "2458": 1250, "2459": 1300, "2460": 1350, "2461": 1400, "2462": 1450, "2463": 1550, "2464": 1600, "2500": 47, "2501": 57, "2502": 70, "2503": 102, "2504": 172, "2600": 500, "2601": 550, "2602": 625, "2603": 750, "2700": 10, "2701": 25, "2702": 50, "2703": 100, "2800": 10, "2801": 25, "2802": 50, "2803": 100, "2900": 10, "2901": 25, "2902": 50, "2903": 100, "300": 20, "303": 20, "304": 20, "305": 1, "400": 2, "401": 2, "405": 20, "406": 3, "407": 3, "410": 1, "411": 8, "412": 1, "420": 1, "421": 1, "500": 200, "501": 200, "502": 200, "503": 200, "504": 1000, "600": 3, "601": 1, "602": 35, "603": 40, "604": 10, "605": 10, "701": 30, "800": 2700, "801": 1650, "900": 70, "@extrNative(1040)": 10, "@extrNative(1041)": 10, "@extrNative(1042)": 10, "@extrNative(1043)": 10, "@extrNative(1050)": 10, "@extrNative(1051)": 10, "@extrNative(1052)": 10, "@extrNative(1053)": 10, "@extrNative(1062)": 1, "@extrUser(addressFromString)": 124, "@extrUser(getBinary)": 10, "@extrUser(getBoolean)": 10, "@extrUser(getInteger)": 10, "@extrUser(getString)": 10, "Address": 1, "Alias": 1, "AssetPair": 2, "BinaryEntry": 2, "BooleanEntry": 2, "Burn": 2, "Buy": 0, "Ceiling": 0, "DataTransaction": 9, "DeleteEntry": 1, "Down": 0, "Floor": 0, "HalfDown": 0, "HalfEven": 0, "HalfUp": 0, "IntegerEntry": 2, "Md5": 0, "NoAlg": 0, "Reissue": 3, "ScriptTransfer": 3, "Sell": 0, "Sha1": 0, "Sha224": 0, "Sha256": 0, "Sha3224": 0, "Sha3256": 0, "Sha3384": 0, "Sha3512": 0, "Sha384": 0, "Sha512": 0, "SponsorFee": 2, "StringEntry": 2, "Unit": 0, "Up": 0, "addressFromPublicKey": 63, "addressFromString": 124, "contains": 3, "containsElement": 5, "dropRight": 20, "dropRightBytes": 6, "extract": 13, "getBinary": 30, "getBoolean": 30, "getInteger": 30, "getString": 30, "isDefined": 1, "parseIntValue": 2, "takeRight": 20, "takeRightBytes": 6, "throw": 1, "value": 2, "valueOrElse": 2, "valueOrErrorMessage": 2} +var _functions_V4 [226]rideFunction + +func init() { + _functions_V4 = [226]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionHeightByID, assetInfoV4, blockInfoByHeight, transferByID, wavesBalanceV4, assetBalanceV4, sub, gt, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, mod, addressFromRecipient, addressToString, addressFromString, fraction, transferFromProtobuf, pow, calculateAssetID, log, simplifiedIssue, fullIssue, limitedCreateList, appendToList, concatList, indexOfList, lastIndexOfList, listRemoveByIndex, bytesToUTF8String, bytesToInt, bytesToIntWithOffset, indexOfSubstring, indexOfSubstringWithOffset, splitString, parseInt, lastIndexOfSubstring, lastIndexOfSubstringWithOffset, makeString, newTuple2, newTuple3, newTuple4, newTuple5, newTuple6, newTuple7, newTuple8, newTuple9, newTuple10, newTuple11, newTuple12, newTuple13, newTuple14, newTuple15, newTuple16, newTuple17, newTuple18, newTuple19, newTuple20, newTuple21, newTuple22, throw, sizeBytes, takeBytes, dropBytes, concatBytes, bls12Groth16Verify_1, bls12Groth16Verify_2, bls12Groth16Verify_3, bls12Groth16Verify_4, bls12Groth16Verify_5, bls12Groth16Verify_6, bls12Groth16Verify_7, bls12Groth16Verify_8, bls12Groth16Verify_9, bls12Groth16Verify_10, bls12Groth16Verify_11, bls12Groth16Verify_12, bls12Groth16Verify_13, bls12Groth16Verify_14, bls12Groth16Verify_15, bn256Groth16Verify_1, bn256Groth16Verify_2, bn256Groth16Verify_3, bn256Groth16Verify_4, bn256Groth16Verify_5, bn256Groth16Verify_6, bn256Groth16Verify_7, bn256Groth16Verify_8, bn256Groth16Verify_9, bn256Groth16Verify_10, bn256Groth16Verify_11, bn256Groth16Verify_12, bn256Groth16Verify_13, bn256Groth16Verify_14, bn256Groth16Verify_15, sigVerify_8, sigVerify_16, sigVerify_32, sigVerify_64, sigVerify_128, rsaVerify_16, rsaVerify_32, rsaVerify_64, rsaVerify_128, keccak256_16, keccak256_32, keccak256_64, keccak256_128, blake2b256_16, blake2b256_32, blake2b256_64, blake2b256_128, sha256_16, sha256_32, sha256_64, sha256_128, concatStrings, takeString, dropString, sizeString, sizeList, getList, median, max, min, intToBytes, stringToBytes, booleanToBytes, intToString, booleanToString, sigVerify, keccak256, blake2b256, sha256, rsaVerify, toBase58, fromBase58, toBase64, fromBase64, toBase16, fromBase16, rebuildMerkleRoot, bls12Groth16Verify, bn256Groth16Verify, ecRecover, intValueFromArray, booleanValueFromArray, bytesValueFromArray, stringValueFromArray, intValueFromState, booleanValueFromState, bytesValueFromState, stringValueFromState, addressFromString, addressValueFromString, bytesValueFromArrayByIndex, booleanValueFromArrayByIndex, intValueFromArrayByIndex, stringValueFromArrayByIndex, address, alias, assetPair, attachedPayment, checkedBytesDataEntry, checkedBooleanDataEntry, burn, createBuy, createCeiling, dataTransaction, checkedDeleteEntry, createDown, createFloor, createHalfDown, createHalfEven, createHalfUp, checkedIntDataEntry, createMd5, createNoAlg, reissue, scriptTransfer, createSell, createSha1, createSha224, createSha256, createSha3224, createSha3256, createSha3384, createSha3512, createSha384, createSha512, sponsorship, checkedStringDataEntry, unit, createUp, addressFromPublicKey, addressFromString, contains, containsElement, dropRightString, dropRightBytes, extract, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, parseIntValue, takeRightString, takeRightBytes, throw0, value, valueOrElse, valueOrErrorMessage} +} + +var _catalogue_V4 = [...]int{1, 1, 1, 1, 1, 1, 20, 15, 5, 60, 10, 10, 1, 1, 1, 1, 10, 10, 10, 10, 1, 10, 10, 10, 10, 1, 5, 10, 1, 1, 5, 100, 10, 100, 1, 1, 1, 1, 4, 5, 5, 7, 7, 1, 1, 3, 3, 75, 2, 3, 3, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 800, 850, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1550, 1600, 47, 57, 70, 102, 172, 500, 550, 625, 750, 10, 25, 50, 100, 10, 25, 50, 100, 10, 25, 50, 100, 20, 20, 20, 1, 2, 2, 20, 3, 3, 1, 8, 1, 1, 1, 200, 200, 200, 200, 1000, 3, 1, 35, 40, 10, 10, 30, 2700, 1650, 70, 10, 10, 10, 10, 10, 10, 10, 10, 1, 124, 10, 10, 10, 10, 1, 1, 2, 2, 2, 2, 2, 0, 0, 9, 1, 0, 0, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 63, 124, 3, 5, 20, 6, 13, 30, 30, 30, 30, 1, 2, 20, 6, 1, 2, 2, 2} -const _names_V4 = "!!=-0110010011004100510061007100810110210310410401041104210431051050105110521053106106010611062107107010810801091090109111001101110211031104110512001201120212031204120512061207120812091300130113021303130413051306130713081309131013111312131313141315131613171318131913202200201202203240024012402240324042405240624072408240924102411241224132414245024512452245324542455245624572458245924602461246224632464250025012502250325042600260126022603270027012702270328002801280228032900290129022903300303304305400401405406407410411412420421500501502503504600601602603604605701800801900@extrNative(1040)@extrNative(1041)@extrNative(1042)@extrNative(1043)@extrNative(1050)@extrNative(1051)@extrNative(1052)@extrNative(1053)@extrNative(1062)@extrUser(addressFromString)@extrUser(getBinary)@extrUser(getBoolean)@extrUser(getInteger)@extrUser(getString)AddressAliasAssetPairBinaryEntryBooleanEntryBurnBuyCeilingDataTransactionDeleteEntryDownFloorHalfDownHalfEvenHalfUpIntegerEntryMd5NoAlgReissueScriptTransferSellSha1Sha224Sha256Sha3224Sha3256Sha3384Sha3512Sha384Sha512SponsorFeeStringEntryUnitUpaddressFromPublicKeyaddressFromStringcontainscontainsElementdropRightdropRightBytesextractgetBinarygetBooleangetIntegergetStringisDefinedparseIntValuetakeRighttakeRightBytesthrowvaluevalueOrElsevalueOrErrorMessage" +var CatalogueV4 = map[string]int{"!": 1, "!=": 1, "-": 1, "0": 1, "1": 1, "100": 1, "1001": 20, "1004": 15, "1005": 5, "1006": 60, "1007": 10, "1008": 10, "101": 1, "102": 1, "103": 1, "104": 1, "1040": 10, "1041": 10, "1042": 10, "1043": 10, "105": 1, "1050": 10, "1051": 10, "1052": 10, "1053": 10, "106": 1, "1060": 5, "1061": 10, "1062": 1, "107": 1, "1070": 5, "108": 100, "1080": 10, "109": 100, "1090": 1, "1091": 1, "1100": 1, "1101": 1, "1102": 4, "1103": 5, "1104": 5, "1105": 7, "1200": 7, "1201": 1, "1202": 1, "1203": 3, "1204": 3, "1205": 75, "1206": 2, "1207": 3, "1208": 3, "1209": 30, "1300": 1, "1301": 1, "1302": 1, "1303": 1, "1304": 1, "1305": 1, "1306": 1, "1307": 1, "1308": 1, "1309": 1, "1310": 1, "1311": 1, "1312": 1, "1313": 1, "1314": 1, "1315": 1, "1316": 1, "1317": 1, "1318": 1, "1319": 1, "1320": 1, "2": 1, "200": 1, "201": 6, "202": 6, "203": 2, "2400": 1200, "2401": 1300, "2402": 1400, "2403": 1500, "2404": 1600, "2405": 1700, "2406": 1800, "2407": 1900, "2408": 2000, "2409": 2100, "2410": 2200, "2411": 2300, "2412": 2400, "2413": 2500, "2414": 2600, "2450": 800, "2451": 850, "2452": 950, "2453": 1000, "2454": 1050, "2455": 1100, "2456": 1150, "2457": 1200, "2458": 1250, "2459": 1300, "2460": 1350, "2461": 1400, "2462": 1450, "2463": 1550, "2464": 1600, "2500": 47, "2501": 57, "2502": 70, "2503": 102, "2504": 172, "2600": 500, "2601": 550, "2602": 625, "2603": 750, "2700": 10, "2701": 25, "2702": 50, "2703": 100, "2800": 10, "2801": 25, "2802": 50, "2803": 100, "2900": 10, "2901": 25, "2902": 50, "2903": 100, "300": 20, "303": 20, "304": 20, "305": 1, "400": 2, "401": 2, "405": 20, "406": 3, "407": 3, "410": 1, "411": 8, "412": 1, "420": 1, "421": 1, "500": 200, "501": 200, "502": 200, "503": 200, "504": 1000, "600": 3, "601": 1, "602": 35, "603": 40, "604": 10, "605": 10, "701": 30, "800": 2700, "801": 1650, "900": 70, "@extrNative(1040)": 10, "@extrNative(1041)": 10, "@extrNative(1042)": 10, "@extrNative(1043)": 10, "@extrNative(1050)": 10, "@extrNative(1051)": 10, "@extrNative(1052)": 10, "@extrNative(1053)": 10, "@extrNative(1062)": 1, "@extrUser(addressFromString)": 124, "@extrUser(getBinary)": 10, "@extrUser(getBoolean)": 10, "@extrUser(getInteger)": 10, "@extrUser(getString)": 10, "Address": 1, "Alias": 1, "AssetPair": 2, "AttachedPayment": 2, "BinaryEntry": 2, "BooleanEntry": 2, "Burn": 2, "Buy": 0, "Ceiling": 0, "DataTransaction": 9, "DeleteEntry": 1, "Down": 0, "Floor": 0, "HalfDown": 0, "HalfEven": 0, "HalfUp": 0, "IntegerEntry": 2, "Md5": 0, "NoAlg": 0, "Reissue": 3, "ScriptTransfer": 3, "Sell": 0, "Sha1": 0, "Sha224": 0, "Sha256": 0, "Sha3224": 0, "Sha3256": 0, "Sha3384": 0, "Sha3512": 0, "Sha384": 0, "Sha512": 0, "SponsorFee": 2, "StringEntry": 2, "Unit": 0, "Up": 0, "addressFromPublicKey": 63, "addressFromString": 124, "contains": 3, "containsElement": 5, "dropRight": 20, "dropRightBytes": 6, "extract": 13, "getBinary": 30, "getBoolean": 30, "getInteger": 30, "getString": 30, "isDefined": 1, "parseIntValue": 2, "takeRight": 20, "takeRightBytes": 6, "throw": 1, "value": 2, "valueOrElse": 2, "valueOrErrorMessage": 2} -var _index_V4 = [...]int{0, 1, 3, 4, 5, 6, 9, 13, 17, 21, 25, 29, 33, 36, 39, 42, 45, 49, 53, 57, 61, 64, 68, 72, 76, 80, 83, 87, 91, 95, 98, 102, 105, 109, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 256, 260, 264, 268, 269, 272, 275, 278, 281, 285, 289, 293, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401, 405, 409, 413, 417, 421, 425, 429, 433, 437, 441, 445, 449, 453, 457, 461, 465, 469, 473, 477, 481, 485, 488, 491, 494, 497, 500, 503, 506, 509, 512, 515, 518, 521, 524, 527, 530, 533, 536, 539, 542, 545, 548, 551, 554, 557, 560, 563, 566, 569, 572, 589, 606, 623, 640, 657, 674, 691, 708, 725, 753, 773, 794, 815, 835, 842, 847, 856, 867, 879, 883, 886, 893, 908, 919, 923, 928, 936, 944, 950, 962, 965, 970, 977, 991, 995, 999, 1005, 1011, 1018, 1025, 1032, 1039, 1045, 1051, 1061, 1072, 1076, 1078, 1098, 1115, 1123, 1138, 1147, 1161, 1168, 1177, 1187, 1197, 1206, 1215, 1228, 1237, 1251, 1256, 1261, 1272, 1291} +var FreeFunctionsV4 = map[string]struct{}{"Address": {}, "Alias": {}, "AssetPair": {}, "DataEntry": {}, "DataTransaction": {}, "WriteSet": {}, "TransferSet": {}, "ScriptTransfer": {}, "ScriptResult": {}, "IntegerEntry": {}, "BooleanEntry": {}, "BinaryEntry": {}, "StringEntry": {}, "DeleteEntry": {}, "Reissue": {}, "Burn": {}, "SponsorFee": {}, "AttachedPayment": {}} + +const _names_V4 = "!!=-0110010011004100510061007100810110210310410401041104210431051050105110521053106106010611062107107010810801091090109111001101110211031104110512001201120212031204120512061207120812091300130113021303130413051306130713081309131013111312131313141315131613171318131913202200201202203240024012402240324042405240624072408240924102411241224132414245024512452245324542455245624572458245924602461246224632464250025012502250325042600260126022603270027012702270328002801280228032900290129022903300303304305400401405406407410411412420421500501502503504600601602603604605701800801900@extrNative(1040)@extrNative(1041)@extrNative(1042)@extrNative(1043)@extrNative(1050)@extrNative(1051)@extrNative(1052)@extrNative(1053)@extrNative(1062)@extrUser(addressFromString)@extrUser(getBinary)@extrUser(getBoolean)@extrUser(getInteger)@extrUser(getString)AddressAliasAssetPairAttachedPaymentBinaryEntryBooleanEntryBurnBuyCeilingDataTransactionDeleteEntryDownFloorHalfDownHalfEvenHalfUpIntegerEntryMd5NoAlgReissueScriptTransferSellSha1Sha224Sha256Sha3224Sha3256Sha3384Sha3512Sha384Sha512SponsorFeeStringEntryUnitUpaddressFromPublicKeyaddressFromStringcontainscontainsElementdropRightdropRightBytesextractgetBinarygetBooleangetIntegergetStringisDefinedparseIntValuetakeRighttakeRightBytesthrowvaluevalueOrElsevalueOrErrorMessage" + +var _index_V4 = [...]int{0, 1, 3, 4, 5, 6, 9, 13, 17, 21, 25, 29, 33, 36, 39, 42, 45, 49, 53, 57, 61, 64, 68, 72, 76, 80, 83, 87, 91, 95, 98, 102, 105, 109, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 256, 260, 264, 268, 269, 272, 275, 278, 281, 285, 289, 293, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401, 405, 409, 413, 417, 421, 425, 429, 433, 437, 441, 445, 449, 453, 457, 461, 465, 469, 473, 477, 481, 485, 488, 491, 494, 497, 500, 503, 506, 509, 512, 515, 518, 521, 524, 527, 530, 533, 536, 539, 542, 545, 548, 551, 554, 557, 560, 563, 566, 569, 572, 589, 606, 623, 640, 657, 674, 691, 708, 725, 753, 773, 794, 815, 835, 842, 847, 856, 871, 882, 894, 898, 901, 908, 923, 934, 938, 943, 951, 959, 965, 977, 980, 985, 992, 1006, 1010, 1014, 1020, 1026, 1033, 1040, 1047, 1054, 1060, 1066, 1076, 1087, 1091, 1093, 1113, 1130, 1138, 1153, 1162, 1176, 1183, 1192, 1202, 1212, 1221, 1230, 1243, 1252, 1266, 1271, 1276, 1287, 1306} func functionNameV4(i int) string { - if i < 0 || i > 224 { + if i < 0 || i > 225 { return "" } return _names_V4[_index_V4[i]:_index_V4[i+1]] } + func functionV4(id int) rideFunction { - if id < 0 || id > 224 { + if id < 0 || id > 225 { return nil } return _functions_V4[id] } + func checkFunctionV4(name string) (uint16, bool) { - for i := 0; i <= 224; i++ { + for i := 0; i <= 225; i++ { if _names_V4[_index_V4[i]:_index_V4[i+1]] == name { return uint16(i), true } } return 0, false } + func costV4(id int) int { - if id < 0 || id > 224 { + if id < 0 || id > 225 { return -1 } return _catalogue_V4[id] } + +var _functions_V5 [266]rideFunction + +func init() { + _functions_V5 = [266]rideFunction{unaryNot, neq, unaryMinus, eq, instanceOf, sum, transactionHeightByID, assetInfoV4, blockInfoByHeight, transferByID, wavesBalanceV4, assetBalanceV4, hashScriptAtAddress, sub, gt, invoke, reentrantInvoke, ge, mul, intFromArray, booleanFromArray, bytesFromArray, stringFromArray, div, intFromState, booleanFromState, bytesFromState, stringFromState, isDataStorageUntouched, intFromSelfState, booleanFromSelfState, bytesFromSelfState, stringFromSelfState, mod, addressFromRecipient, addressToString, addressFromString, fraction, transferFromProtobuf, pow, calculateAssetID, calculateLeaseID, log, simplifiedIssue, fullIssue, simplifiedLease, fullLease, limitedCreateList, appendToList, concatList, indexOfList, lastIndexOfList, listRemoveByIndex, powBigInt, logBigInt, bytesToUTF8String, bytesToInt, bytesToIntWithOffset, indexOfSubstring, indexOfSubstringWithOffset, splitString, parseInt, lastIndexOfSubstring, lastIndexOfSubstringWithOffset, makeString, newTuple2, newTuple3, newTuple4, newTuple5, newTuple6, newTuple7, newTuple8, newTuple9, newTuple10, newTuple11, newTuple12, newTuple13, newTuple14, newTuple15, newTuple16, newTuple17, newTuple18, newTuple19, newTuple20, newTuple21, newTuple22, throw, sizeBytes, takeBytes, dropBytes, concatBytes, bls12Groth16Verify_1, bls12Groth16Verify_2, bls12Groth16Verify_3, bls12Groth16Verify_4, bls12Groth16Verify_5, bls12Groth16Verify_6, bls12Groth16Verify_7, bls12Groth16Verify_8, bls12Groth16Verify_9, bls12Groth16Verify_10, bls12Groth16Verify_11, bls12Groth16Verify_12, bls12Groth16Verify_13, bls12Groth16Verify_14, bls12Groth16Verify_15, bn256Groth16Verify_1, bn256Groth16Verify_2, bn256Groth16Verify_3, bn256Groth16Verify_4, bn256Groth16Verify_5, bn256Groth16Verify_6, bn256Groth16Verify_7, bn256Groth16Verify_8, bn256Groth16Verify_9, bn256Groth16Verify_10, bn256Groth16Verify_11, bn256Groth16Verify_12, bn256Groth16Verify_13, bn256Groth16Verify_14, bn256Groth16Verify_15, sigVerify_8, sigVerify_16, sigVerify_32, sigVerify_64, sigVerify_128, rsaVerify_16, rsaVerify_32, rsaVerify_64, rsaVerify_128, keccak256_16, keccak256_32, keccak256_64, keccak256_128, blake2b256_16, blake2b256_32, blake2b256_64, blake2b256_128, sha256_16, sha256_32, sha256_64, sha256_128, concatStrings, takeString, dropString, sizeString, toBigInt, sumBigInt, subtractBigInt, multiplyBigInt, divideBigInt, moduloBigInt, fractionBigInt, fractionBigIntRounds, unaryMinusBigInt, gtBigInt, geBigInt, sizeList, getList, median, max, min, maxListBigInt, minListBigInt, intToBytes, stringToBytes, booleanToBytes, bigIntToBytes, bytesToBigInt, bytesToBigIntLim, bigIntToInt, intToString, booleanToString, bigIntToString, stringToBigInt, stringToBigIntOpt, medianListBigInt, sigVerify, keccak256, blake2b256, sha256, rsaVerify, toBase58, fromBase58, toBase64, fromBase64, toBase16, fromBase16, rebuildMerkleRoot, bls12Groth16Verify, bn256Groth16Verify, ecRecover, intValueFromArray, booleanValueFromArray, bytesValueFromArray, stringValueFromArray, intValueFromState, booleanValueFromState, bytesValueFromState, stringValueFromState, intValueFromSelfState, booleanValueFromSelfState, bytesValueFromSelfState, stringValueFromSelfState, addressFromString, addressValueFromString, bytesValueFromArrayByIndex, booleanValueFromArrayByIndex, intValueFromArrayByIndex, stringValueFromArrayByIndex, address, alias, assetPair, attachedPayment, checkedBytesDataEntry, checkedBooleanDataEntry, burn, createBuy, createCeiling, dataTransaction, checkedDeleteEntry, createDown, createFloor, createHalfDown, createHalfEven, createHalfUp, checkedIntDataEntry, leaseCancel, createMd5, createNoAlg, reissue, scriptTransfer, createSell, createSha1, createSha224, createSha256, createSha3224, createSha3256, createSha3384, createSha3512, createSha384, createSha512, sponsorship, checkedStringDataEntry, unit, createUp, addressFromPublicKey, addressFromString, contains, containsElement, dropRightString, dropRightBytes, extract, fractionIntRounds, bytesFromArrayByIndex, booleanFromArrayByIndex, intFromArrayByIndex, stringFromArrayByIndex, isDefined, parseIntValue, takeRightString, takeRightBytes, throw0, value, valueOrElse, valueOrErrorMessage} +} + +var _catalogue_V5 = [...]int{1, 1, 1, 1, 1, 1, 20, 15, 5, 60, 10, 10, 200, 1, 1, 75, 75, 1, 1, 10, 10, 10, 10, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1, 5, 10, 1, 14, 5, 100, 10, 1, 100, 1, 1, 1, 1, 1, 1, 4, 5, 5, 7, 200, 200, 7, 1, 1, 3, 3, 75, 2, 3, 3, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 800, 850, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1550, 1600, 47, 57, 70, 102, 172, 500, 550, 625, 750, 10, 25, 50, 100, 10, 25, 50, 100, 10, 25, 50, 100, 20, 20, 20, 1, 1, 8, 8, 64, 64, 64, 128, 128, 8, 8, 8, 2, 2, 20, 3, 3, 192, 192, 1, 8, 1, 65, 65, 65, 1, 1, 1, 65, 65, 65, 160, 200, 200, 200, 200, 1000, 3, 1, 35, 40, 10, 10, 30, 2700, 1650, 70, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1, 124, 10, 10, 10, 10, 1, 1, 2, 2, 2, 2, 2, 0, 0, 9, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 63, 124, 3, 5, 20, 6, 13, 17, 30, 30, 30, 30, 1, 2, 20, 6, 1, 2, 2, 2} + +var CatalogueV5 = map[string]int{"!": 1, "!=": 1, "-": 1, "0": 1, "1": 1, "100": 1, "1001": 20, "1004": 15, "1005": 5, "1006": 60, "1007": 10, "1008": 10, "1009": 200, "101": 1, "102": 1, "1020": 75, "1021": 75, "103": 1, "104": 1, "1040": 10, "1041": 10, "1042": 10, "1043": 10, "105": 1, "1050": 10, "1051": 10, "1052": 10, "1053": 10, "1054": 10, "1055": 10, "1056": 10, "1057": 10, "1058": 10, "106": 1, "1060": 5, "1061": 10, "1062": 1, "107": 14, "1070": 5, "108": 100, "1080": 10, "1081": 1, "109": 100, "1090": 1, "1091": 1, "1092": 1, "1093": 1, "1100": 1, "1101": 1, "1102": 4, "1103": 5, "1104": 5, "1105": 7, "118": 200, "119": 200, "1200": 7, "1201": 1, "1202": 1, "1203": 3, "1204": 3, "1205": 75, "1206": 2, "1207": 3, "1208": 3, "1209": 30, "1300": 1, "1301": 1, "1302": 1, "1303": 1, "1304": 1, "1305": 1, "1306": 1, "1307": 1, "1308": 1, "1309": 1, "1310": 1, "1311": 1, "1312": 1, "1313": 1, "1314": 1, "1315": 1, "1316": 1, "1317": 1, "1318": 1, "1319": 1, "1320": 1, "2": 1, "200": 1, "201": 6, "202": 6, "203": 2, "2400": 1200, "2401": 1300, "2402": 1400, "2403": 1500, "2404": 1600, "2405": 1700, "2406": 1800, "2407": 1900, "2408": 2000, "2409": 2100, "2410": 2200, "2411": 2300, "2412": 2400, "2413": 2500, "2414": 2600, "2450": 800, "2451": 850, "2452": 950, "2453": 1000, "2454": 1050, "2455": 1100, "2456": 1150, "2457": 1200, "2458": 1250, "2459": 1300, "2460": 1350, "2461": 1400, "2462": 1450, "2463": 1550, "2464": 1600, "2500": 47, "2501": 57, "2502": 70, "2503": 102, "2504": 172, "2600": 500, "2601": 550, "2602": 625, "2603": 750, "2700": 10, "2701": 25, "2702": 50, "2703": 100, "2800": 10, "2801": 25, "2802": 50, "2803": 100, "2900": 10, "2901": 25, "2902": 50, "2903": 100, "300": 20, "303": 20, "304": 20, "305": 1, "310": 1, "311": 8, "312": 8, "313": 64, "314": 64, "315": 64, "316": 128, "317": 128, "318": 8, "319": 8, "320": 8, "400": 2, "401": 2, "405": 20, "406": 3, "407": 3, "408": 192, "409": 192, "410": 1, "411": 8, "412": 1, "413": 65, "414": 65, "415": 65, "416": 1, "420": 1, "421": 1, "422": 65, "423": 65, "424": 65, "425": 160, "500": 200, "501": 200, "502": 200, "503": 200, "504": 1000, "600": 3, "601": 1, "602": 35, "603": 40, "604": 10, "605": 10, "701": 30, "800": 2700, "801": 1650, "900": 70, "@extrNative(1040)": 10, "@extrNative(1041)": 10, "@extrNative(1042)": 10, "@extrNative(1043)": 10, "@extrNative(1050)": 10, "@extrNative(1051)": 10, "@extrNative(1052)": 10, "@extrNative(1053)": 10, "@extrNative(1055)": 10, "@extrNative(1056)": 10, "@extrNative(1057)": 10, "@extrNative(1058)": 10, "@extrNative(1062)": 1, "@extrUser(addressFromString)": 124, "@extrUser(getBinary)": 10, "@extrUser(getBoolean)": 10, "@extrUser(getInteger)": 10, "@extrUser(getString)": 10, "Address": 1, "Alias": 1, "AssetPair": 2, "AttachedPayment": 2, "BinaryEntry": 2, "BooleanEntry": 2, "Burn": 2, "Buy": 0, "Ceiling": 0, "DataTransaction": 9, "DeleteEntry": 1, "Down": 0, "Floor": 0, "HalfDown": 0, "HalfEven": 0, "HalfUp": 0, "IntegerEntry": 2, "LeaseCancel": 1, "Md5": 0, "NoAlg": 0, "Reissue": 3, "ScriptTransfer": 3, "Sell": 0, "Sha1": 0, "Sha224": 0, "Sha256": 0, "Sha3224": 0, "Sha3256": 0, "Sha3384": 0, "Sha3512": 0, "Sha384": 0, "Sha512": 0, "SponsorFee": 2, "StringEntry": 2, "Unit": 0, "Up": 0, "addressFromPublicKey": 63, "addressFromString": 124, "contains": 3, "containsElement": 5, "dropRight": 20, "dropRightBytes": 6, "extract": 13, "fraction": 17, "getBinary": 30, "getBoolean": 30, "getInteger": 30, "getString": 30, "isDefined": 1, "parseIntValue": 2, "takeRight": 20, "takeRightBytes": 6, "throw": 1, "value": 2, "valueOrElse": 2, "valueOrErrorMessage": 2} + +var FreeFunctionsV5 = map[string]struct{}{"Address": {}, "Alias": {}, "AssetPair": {}, "DataEntry": {}, "DataTransaction": {}, "WriteSet": {}, "TransferSet": {}, "ScriptTransfer": {}, "ScriptResult": {}, "IntegerEntry": {}, "BooleanEntry": {}, "BinaryEntry": {}, "StringEntry": {}, "DeleteEntry": {}, "Reissue": {}, "Burn": {}, "SponsorFee": {}, "AttachedPayment": {}, "LeaseCancel": {}} + +const _names_V5 = "!!=-011001001100410051006100710081009101102102010211031041040104110421043105105010511052105310541055105610571058106106010611062107107010810801081109109010911092109311001101110211031104110511811912001201120212031204120512061207120812091300130113021303130413051306130713081309131013111312131313141315131613171318131913202200201202203240024012402240324042405240624072408240924102411241224132414245024512452245324542455245624572458245924602461246224632464250025012502250325042600260126022603270027012702270328002801280228032900290129022903300303304305310311312313314315316317318319320400401405406407408409410411412413414415416420421422423424425500501502503504600601602603604605701800801900@extrNative(1040)@extrNative(1041)@extrNative(1042)@extrNative(1043)@extrNative(1050)@extrNative(1051)@extrNative(1052)@extrNative(1053)@extrNative(1055)@extrNative(1056)@extrNative(1057)@extrNative(1058)@extrNative(1062)@extrUser(addressFromString)@extrUser(getBinary)@extrUser(getBoolean)@extrUser(getInteger)@extrUser(getString)AddressAliasAssetPairAttachedPaymentBinaryEntryBooleanEntryBurnBuyCeilingDataTransactionDeleteEntryDownFloorHalfDownHalfEvenHalfUpIntegerEntryLeaseCancelMd5NoAlgReissueScriptTransferSellSha1Sha224Sha256Sha3224Sha3256Sha3384Sha3512Sha384Sha512SponsorFeeStringEntryUnitUpaddressFromPublicKeyaddressFromStringcontainscontainsElementdropRightdropRightBytesextractfractiongetBinarygetBooleangetIntegergetStringisDefinedparseIntValuetakeRighttakeRightBytesthrowvaluevalueOrElsevalueOrErrorMessage" + +var _index_V5 = [...]int{0, 1, 3, 4, 5, 6, 9, 13, 17, 21, 25, 29, 33, 37, 40, 43, 47, 51, 54, 57, 61, 65, 69, 73, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 115, 119, 123, 127, 130, 134, 137, 141, 145, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 191, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 254, 258, 262, 266, 270, 274, 278, 282, 286, 290, 294, 298, 302, 306, 310, 314, 318, 319, 322, 325, 328, 331, 335, 339, 343, 347, 351, 355, 359, 363, 367, 371, 375, 379, 383, 387, 391, 395, 399, 403, 407, 411, 415, 419, 423, 427, 431, 435, 439, 443, 447, 451, 455, 459, 463, 467, 471, 475, 479, 483, 487, 491, 495, 499, 503, 507, 511, 515, 519, 523, 527, 531, 535, 538, 541, 544, 547, 550, 553, 556, 559, 562, 565, 568, 571, 574, 577, 580, 583, 586, 589, 592, 595, 598, 601, 604, 607, 610, 613, 616, 619, 622, 625, 628, 631, 634, 637, 640, 643, 646, 649, 652, 655, 658, 661, 664, 667, 670, 673, 676, 679, 682, 685, 702, 719, 736, 753, 770, 787, 804, 821, 838, 855, 872, 889, 906, 934, 954, 975, 996, 1016, 1023, 1028, 1037, 1052, 1063, 1075, 1079, 1082, 1089, 1104, 1115, 1119, 1124, 1132, 1140, 1146, 1158, 1169, 1172, 1177, 1184, 1198, 1202, 1206, 1212, 1218, 1225, 1232, 1239, 1246, 1252, 1258, 1268, 1279, 1283, 1285, 1305, 1322, 1330, 1345, 1354, 1368, 1375, 1383, 1392, 1402, 1412, 1421, 1430, 1443, 1452, 1466, 1471, 1476, 1487, 1506} + +func functionNameV5(i int) string { + if i < 0 || i > 265 { + return "" + } + return _names_V5[_index_V5[i]:_index_V5[i+1]] +} + +func functionV5(id int) rideFunction { + if id < 0 || id > 265 { + return nil + } + return _functions_V5[id] +} + +func checkFunctionV5(name string) (uint16, bool) { + for i := 0; i <= 265; i++ { + if _names_V5[_index_V5[i]:_index_V5[i+1]] == name { + return uint16(i), true + } + } + return 0, false +} + +func costV5(id int) int { + if id < 0 || id > 265 { + return -1 + } + return _catalogue_V5[id] +} diff --git a/pkg/ride/functions_bigint.go b/pkg/ride/functions_bigint.go new file mode 100644 index 000000000..46ed0add6 --- /dev/null +++ b/pkg/ride/functions_bigint.go @@ -0,0 +1,663 @@ +package ride + +import ( + "math/big" + "sort" + + "github.com/ericlagergren/decimal" + "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/ride/math" +) + +var ( + minBigInt, maxBigInt = initBoundaries() + zeroBigInt = big.NewInt(0) + oneBigInt = big.NewInt(1) +) + +func initBoundaries() (*big.Int, *big.Int) { + max := big.NewInt(0) + max = max.Exp(big.NewInt(2), big.NewInt(511), nil) + max = max.Sub(max, oneBigInt) + + min := big.NewInt(0) + min = min.Neg(max) + min = min.Sub(min, oneBigInt) + return min, max +} + +func bigIntArg(args []rideType) (rideBigInt, error) { + if len(args) != 1 { + return rideBigInt{}, errors.Errorf("%d is invalid number of arguments, expected 1", len(args)) + } + if args[0] == nil { + return rideBigInt{}, errors.Errorf("argument 1 is empty") + } + l, ok := args[0].(rideBigInt) + if !ok { + return rideBigInt{}, errors.Errorf("argument 1 is not of type 'BigInt' but '%s'", args[0].instanceOf()) + } + return l, nil +} + +func twoBigIntArgs(args []rideType) (rideBigInt, rideBigInt, error) { + if len(args) != 2 { + return rideBigInt{}, rideBigInt{}, errors.Errorf("%d is invalid number of arguments, expected 2", len(args)) + } + if args[0] == nil { + return rideBigInt{}, rideBigInt{}, errors.Errorf("argument 1 is empty") + } + if args[1] == nil { + return rideBigInt{}, rideBigInt{}, errors.Errorf("argument 2 is empty") + } + v1, ok := args[0].(rideBigInt) + if !ok { + return rideBigInt{}, rideBigInt{}, errors.Errorf("argument 1 is not of type 'BigInt' but '%s'", args[0].instanceOf()) + } + v2, ok := args[1].(rideBigInt) + if !ok { + return rideBigInt{}, rideBigInt{}, errors.Errorf("argument 2 is not of type 'BigInt' but '%s'", args[1].instanceOf()) + } + return v1, v2, nil +} + +func threeBigIntArgs(args []rideType) (rideBigInt, rideBigInt, rideBigInt, error) { + if len(args) != 3 { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("%d is invalid number of arguments, expected 3", len(args)) + } + if args[0] == nil { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 1 is empty") + } + if args[1] == nil { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 2 is empty") + } + if args[2] == nil { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 3 is empty") + } + v1, ok := args[0].(rideBigInt) + if !ok { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 1 is not of type 'BigInt' but '%s'", args[0].instanceOf()) + } + v2, ok := args[1].(rideBigInt) + if !ok { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 2 is not of type 'BigInt' but '%s'", args[1].instanceOf()) + } + v3, ok := args[2].(rideBigInt) + if !ok { + return rideBigInt{}, rideBigInt{}, rideBigInt{}, errors.Errorf("argument 3 is not of type 'BigInt' but '%s'", args[2].instanceOf()) + } + return v1, v2, v3, nil +} + +func powBigInt(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 6); err != nil { + return nil, errors.Wrap(err, "powBigInt") + } + base, ok := args[0].(rideBigInt) + if !ok { + return nil, errors.Errorf("powBigInt: unexpected argument type '%s'", args[0].instanceOf()) + } + bp, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("powBigInt: unexpected argument type '%s'", args[1].instanceOf()) + } + exponent, ok := args[2].(rideBigInt) + if !ok { + return nil, errors.Errorf("powBigInt: unexpected argument type '%s'", args[2].instanceOf()) + } + ep, ok := args[3].(rideInt) + if !ok { + return nil, errors.Errorf("powBigInt: unexpected argument type '%s'", args[3].instanceOf()) + } + rp, ok := args[4].(rideInt) + if !ok { + return nil, errors.Errorf("powBigInt: unexpected argument type '%s'", args[4].instanceOf()) + } + round, err := roundingMode(args[5]) + if err != nil { + return nil, errors.Wrap(err, "powBigInt") + } + b := big.NewInt(0).Set(base.v) + e := big.NewInt(0).Set(exponent.v) + r, err := math.PowBigInt(b, e, int(bp), int(ep), int(rp), round) + if err != nil { + return nil, errors.Wrap(err, "powBigInt") + } + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.New("powBigInt: result is out of range") + } + return rideBigInt{v: r}, nil +} + +func logBigInt(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 6); err != nil { + return nil, errors.Wrap(err, "logBigInt") + } + base, ok := args[0].(rideBigInt) + if !ok { + return nil, errors.Errorf("logBigInt: unexpected argument type '%s'", args[0].instanceOf()) + } + bp, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("logBigInt: unexpected argument type '%s'", args[1].instanceOf()) + } + exponent, ok := args[2].(rideBigInt) + if !ok { + return nil, errors.Errorf("logBigInt: unexpected argument type '%s'", args[2].instanceOf()) + } + ep, ok := args[3].(rideInt) + if !ok { + return nil, errors.Errorf("logBigInt: unexpected argument type '%s'", args[3].instanceOf()) + } + rp, ok := args[4].(rideInt) + if !ok { + return nil, errors.Errorf("logBigInt: unexpected argument type '%s'", args[4].instanceOf()) + } + round, err := roundingMode(args[5]) + if err != nil { + return nil, errors.Wrap(err, "logBigInt") + } + b := big.NewInt(0).Set(base.v) + e := big.NewInt(0).Set(exponent.v) + r, err := math.LogBigInt(b, e, int(bp), int(ep), int(rp), round) + if err != nil { + return nil, errors.Wrap(err, "logBigInt") + } + return rideBigInt{v: r}, nil +} + +func toBigInt(_ Environment, args ...rideType) (rideType, error) { + i, err := intArg(args) + if err != nil { + return nil, errors.Wrap(err, "toBigInt") + } + v := big.NewInt(int64(i)) + return rideBigInt{v: v}, nil +} + +func sumBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "sumBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + r := i1.Add(i1, i2) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("sumBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func subtractBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "subtractBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + r := i1.Sub(i1, i2) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("subtractBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func multiplyBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "multiplyBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + r := i1.Mul(i1, i2) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("multiplyBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func divideBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "divideBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + if i2.Cmp(zeroBigInt) == 0 { + return nil, errors.New("divideBigInt: division by zero") + } + r := i1.Div(i1, i2) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("divideBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func moduloBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "moduloBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + if i2.Cmp(zeroBigInt) == 0 { + return nil, errors.New("moduloBigInt: division by zero") + } + //(a % b + b) % b + r0 := i1.Rem(i1, i2) + r1 := r0.Add(r0, i2) + r := r1.Rem(r1, i2) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("moduloBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func fractionBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, c, err := threeBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "fractionBigInt") + } + v := big.NewInt(0).Set(a.v) + n := big.NewInt(0).Set(b.v) + d := big.NewInt(0).Set(c.v) + if d.Cmp(zeroBigInt) == 0 { + return nil, errors.New("fractionBigInt: division by zero") + } + r := v.Mul(v, n) + r = r.Quo(r, d) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("fractionBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func fractionBigIntRounds(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 4); err != nil { + return nil, errors.Wrap(err, "fractionBigIntRounds") + } + v1, ok := args[0].(rideBigInt) + if !ok { + return nil, errors.Errorf("fractionBigIntRounds: unexpected argument type '%s'", args[0].instanceOf()) + } + v := big.NewInt(0).Set(v1.v) + v2, ok := args[1].(rideBigInt) + if !ok { + return nil, errors.Errorf("fractionBigIntRounds: unexpected argument type '%s'", args[1].instanceOf()) + } + n := big.NewInt(0).Set(v2.v) + v3, ok := args[2].(rideBigInt) + if !ok { + return nil, errors.Errorf("fractionBigIntRounds: unexpected argument type '%s'", args[2].instanceOf()) + } + d := big.NewInt(0).Set(v3.v) + round, err := roundingMode(args[3]) + if err != nil { + return nil, errors.Wrap(err, "fractionBigIntRounds") + } + r, err := fractionBigIntLikeInScala(v, n, d, round) + if err != nil { + return nil, errors.Wrap(err, "fractionBigIntRounds") + } + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("fractionBigIntRounds: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +// fractionBigIntLikeInScala the algo is fully taken from Scala implementation. +func fractionBigIntLikeInScala(v, n, d *big.Int, roundingMode decimal.RoundingMode) (*big.Int, error) { + if d.Cmp(zeroBigInt) == 0 { + return nil, errors.New("division by zero") + } + p := v.Mul(v, n) + s := big.NewInt(int64(p.Sign() * d.Sign())) + pa := p.Abs(p) + da := d.Abs(d) + r, m := pa.QuoRem(pa, da, big.NewInt(0)) + ms := big.NewInt(int64(m.Sign())) + switch roundingMode { + case decimal.ToZero: // Down + r = r.Mul(r, s) + case decimal.AwayFromZero: // Up + r = r.Add(r, ms) + r = r.Mul(r, s) + case decimal.ToNearestAway: // HalfUp + x := d.Abs(d) + y := m.Mul(m, big.NewInt(2)) + x = x.Sub(x, y) + switch x.Cmp(zeroBigInt) { + case -1: + r = r.Add(r, big.NewInt(1)) + r = r.Mul(r, s) + case 0: + r = r.Add(r, big.NewInt(1)) + r = r.Mul(r, s) + case 1: + r = r.Mul(r, s) + } + case decimal.ToNearestTowardZero: // RoundHalfDown + x := d.Abs(d) + y := m.Mul(m, big.NewInt(2)) + x = x.Sub(x, y) + if x.Cmp(zeroBigInt) < 0 { + r = r.Add(r, big.NewInt(1)) + r = r.Mul(r, s) + } else { + r = r.Mul(r, s) + } + case decimal.ToPositiveInf: // Ceiling + if s.Cmp(zeroBigInt) > 0 { + r = r.Add(r, ms) + } + r = r.Mul(r, s) + case decimal.ToNegativeInf: // Floor + if s.Cmp(zeroBigInt) < 0 { + r = r.Add(r, ms) + } + r = r.Mul(r, s) + case decimal.ToNearestEven: // HalfEven + x := d.Abs(d) + y := m.Mul(m, big.NewInt(2)) + x = x.Sub(x, y) + switch x.Cmp(zeroBigInt) { + case -1: + r = r.Add(r, big.NewInt(1)) + r = r.Mul(r, s) + case 1: + r = r.Mul(r, s) + case 0: + r2 := big.NewInt(2) + r2 = r2.Mod(r, r2) + r = r.Add(r, r2) + r = r.Mul(r, s) + } + default: + return nil, errors.New("unsupported rounding mode") + } + return r, nil +} + +func unaryMinusBigInt(_ Environment, args ...rideType) (rideType, error) { + v, err := bigIntArg(args) + if err != nil { + return nil, errors.Wrap(err, "unaryMinusBigInt") + } + i := big.NewInt(0).Set(v.v) + if i.Cmp(minBigInt) == 0 { + return nil, errors.New("unaryMinusBigInt: positive BigInt overflow") + } + r := i.Neg(i) + return rideBigInt{v: r}, nil +} + +func gtBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "gtBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + r := i1.Cmp(i2) + return rideBoolean(r > 0), nil +} + +func geBigInt(_ Environment, args ...rideType) (rideType, error) { + a, b, err := twoBigIntArgs(args) + if err != nil { + return nil, errors.Wrap(err, "geBigInt") + } + i1 := big.NewInt(0).Set(a.v) + i2 := big.NewInt(0).Set(b.v) + r := i1.Cmp(i2) + return rideBoolean(r >= 0), nil +} + +func maxListBigInt(_ Environment, args ...rideType) (rideType, error) { + list, err := listArg(args) + if err != nil { + return nil, errors.Wrap(err, "maxListBigInt") + } + size := len(list) + if size > maxListSize || size == 0 { + return nil, errors.Errorf("maxListBigInt: invalid list size %d", size) + } + items, err := toBigIntSlice(list) + if err != nil { + return nil, errors.Wrap(err, "maxListBigInt") + } + _, max := minMaxBigInt(items) + return rideBigInt{v: max}, nil +} + +func minListBigInt(_ Environment, args ...rideType) (rideType, error) { + list, err := listArg(args) + if err != nil { + return nil, errors.Wrap(err, "minListBigInt") + } + size := len(list) + if size > maxListSize || size == 0 { + return nil, errors.Errorf("minListBigInt: invalid list size %d", size) + } + items, err := toBigIntSlice(list) + if err != nil { + return nil, errors.Wrap(err, "minListBigInt") + } + min, _ := minMaxBigInt(items) + return rideBigInt{v: min}, nil +} + +func bigIntToBytes(_ Environment, args ...rideType) (rideType, error) { + v, err := bigIntArg(args) + if err != nil { + return nil, errors.Wrap(err, "bigIntToBytes") + } + i := big.NewInt(0).Set(v.v) + return rideBytes(encode2CBigInt(i)), nil +} + +func bytesToBigInt(_ Environment, args ...rideType) (rideType, error) { + bts, err := bytesArg(args) + if err != nil { + return nil, errors.Wrap(err, "bytesToBigInt") + } + if l := len(bts); l > 64 { // No more then 64 bytes can be converted to BigInt, max size of BigInt value is 512 bit. + return nil, errors.Errorf("bytesToBigInt: bytes array is too long (%d) for a BigInt", l) + } + r := decode2CBigInt(bts) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("bytesToBigInt: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func bytesToBigIntLim(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 3); err != nil { + return nil, errors.Wrap(err, "bytesToBigIntLim") + } + bts, ok := args[0].(rideBytes) + if !ok { + return nil, errors.Errorf("bytesToBigIntLim: argument 1 is not of type 'ByteVector' but '%s'", args[0].instanceOf()) + } + l := len(bts) + offset, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("bytesToBigIntLim: argument 2 is not of type 'Int' but '%s'", args[1].instanceOf()) + } + if offset < 0 || int(offset) >= l { + return nil, errors.Errorf("bytesToBigIntLim: offset %d is out of range [0; %d]", offset, len(bts)-1) + } + size, ok := args[2].(rideInt) + if !ok { + return nil, errors.Errorf("bytesToBigIntLim: argument 3 is not of type 'Int' but '%s'", args[2].instanceOf()) + } + if size <= 0 || size > 64 { // No more then 64 bytes can be converted to BigInt, max size of BigInt value is 512 bit. + return nil, errors.Errorf("bytesToBigIntLim: size %d is out of ranger [1; 64]", size) + } + end := int(offset + size) + if end > l { + end = l + } + r := decode2CBigInt(bts[offset:end]) + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.Errorf("bytesToBigIntLim: %s result is out of range", r.String()) + } + return rideBigInt{v: r}, nil +} + +func bigIntToInt(_ Environment, args ...rideType) (rideType, error) { + v, err := bigIntArg(args) + if err != nil { + return nil, errors.Wrap(err, "bigIntToInt") + } + i := big.NewInt(0).Set(v.v) + if !i.IsInt64() { + return nil, errors.Errorf("bigIntToInt: value (%s) is too big for an Int", i.String()) + } + return rideInt(i.Int64()), nil +} + +func bigIntToString(_ Environment, args ...rideType) (rideType, error) { + v, err := bigIntArg(args) + if err != nil { + return nil, errors.Wrap(err, "bigIntToString") + } + i := big.NewInt(0).Set(v.v) + return rideString(i.String()), nil +} + +func stringToBigInt(_ Environment, args ...rideType) (rideType, error) { + s, err := stringArg(args) + if err != nil { + return nil, errors.Wrap(err, "stringToBigInt") + } + if l := len(s); l > 155 { // 155 symbols is the length of minBigInt value is string representation + return nil, errors.Errorf("stringToBigInt: string is too long (%d symbols) for a BigInt", l) + } + r, ok := big.NewInt(0).SetString(string(s), 10) + if !ok { + return nil, errors.Errorf("stringToBigInt: failed to convert string '%s' to BigInt", s) + } + if r.Cmp(minBigInt) < 0 || r.Cmp(maxBigInt) > 0 { + return nil, errors.New("stringToBigInt: value too big for a BigInt") + } + return rideBigInt{v: r}, nil +} + +func stringToBigIntOpt(env Environment, args ...rideType) (rideType, error) { + v, err := stringToBigInt(env, args...) + if err != nil { + return newUnit(env), nil + } + return v, nil +} + +func medianListBigInt(_ Environment, args ...rideType) (rideType, error) { + list, err := listArg(args) + if err != nil { + return nil, errors.Wrap(err, "medianListBigInt") + } + size := len(list) + if size > maxListSize || size < 2 { + return nil, errors.Errorf("medianListBigInt: invalid list size %d", size) + } + items, err := toBigIntSlice(list) + if err != nil { + return nil, errors.Wrap(err, "medianListBigInt") + } + sort.Sort(items) + half := size / 2 + if size%2 == 1 { + return rideBigInt{v: items[half]}, nil + } + x := items[half-1] + y := items[half] + r := math.FloorDivBigInt(x.Add(x, y), big.NewInt(2)) + return rideBigInt{v: r}, nil +} + +func minMaxBigInt(items []*big.Int) (*big.Int, *big.Int) { + if len(items) == 0 { + panic("empty slice") + } + max, min := items[0], items[0] + for _, i := range items { + if i.Cmp(max) > 0 { + max = i + } + if i.Cmp(min) < 0 { + min = i + } + } + return min, max +} + +type bigIntSlice []*big.Int + +func (x bigIntSlice) Len() int { return len(x) } +func (x bigIntSlice) Less(i, j int) bool { return x[i].Cmp(x[j]) < 0 } +func (x bigIntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func toBigIntSlice(list rideList) (bigIntSlice, error) { + items := make([]*big.Int, len(list)) + for i, el := range list { + item, ok := el.(rideBigInt) + if !ok { + return nil, errors.Errorf("unexpected type of list element '%s'", el.instanceOf()) + } + items[i] = big.NewInt(0).Set(item.v) + } + return items, nil +} + +// decode2CBigInt decodes two's complement representation of BigInt from bytes slice +func decode2CBigInt(bytes []byte) *big.Int { + r := new(big.Int) + if len(bytes) > 0 && bytes[0]&0x80 == 0x80 { // Decode a negative number + notBytes := make([]byte, len(bytes)) + for i := range notBytes { + notBytes[i] = ^bytes[i] + } + r.SetBytes(notBytes) + r.Add(r, oneBigInt) + r.Neg(r) + return r + } + r.SetBytes(bytes) + return r +} + +// encode2CBigInt encodes BigInt into a two's compliment representation +func encode2CBigInt(n *big.Int) []byte { + if n.Sign() < 0 { + // Convert negative number into two's complement form + // Subtract 1 and invert + // If the most-significant-bit isn't set then we'll need to pad the beginning with 0xff in order to keep the number negative + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, oneBigInt) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if l := len(bytes); l == 0 || bytes[0]&0x80 == 0 { + return padBytes(0xff, bytes) + } + return bytes + } else if n.Sign() == 0 { // Zero is written as a single 0 zero rather than no bytes + return []byte{0x00} + } else { + bytes := n.Bytes() + if len(bytes) > 0 && bytes[0]&0x80 != 0 { // We'll have to pad this with 0x00 in order to stop it looking like a negative number + return padBytes(0x00, bytes) + } + return bytes + } +} + +func padBytes(p byte, bytes []byte) []byte { + r := make([]byte, len(bytes)+1) + r[0] = p + copy(r[1:], bytes) + return r +} diff --git a/pkg/ride/functions_bigint_test.go b/pkg/ride/functions_bigint_test.go new file mode 100644 index 000000000..42867c1a6 --- /dev/null +++ b/pkg/ride/functions_bigint_test.go @@ -0,0 +1,728 @@ +package ride + +import ( + "encoding/hex" + "fmt" + "math" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPowBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(12), rideInt(1), toRideBigInt(3456), rideInt(3), rideInt(2), newDown(nil)}, false, toRideBigInt(187)}, + {[]rideType{toRideBigInt(12), rideInt(1), toRideBigInt(3456), rideInt(3), rideInt(2), newUp(nil)}, false, toRideBigInt(188)}, + {[]rideType{toRideBigInt(0), rideInt(1), toRideBigInt(3456), rideInt(3), rideInt(2), newUp(nil)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(0), rideInt(1), toRideBigInt(3456), rideInt(3), rideInt(2), newDown(nil)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(20), rideInt(1), toRideBigInt(-1), rideInt(0), rideInt(4), newDown(nil)}, false, toRideBigInt(5000)}, + {[]rideType{toRideBigInt(-20), rideInt(1), toRideBigInt(-1), rideInt(0), rideInt(4), newDown(nil)}, false, toRideBigInt(-5000)}, + {[]rideType{toRideBigInt(0), rideInt(1), toRideBigInt(-1), rideInt(0), rideInt(4), newDown(nil)}, true, nil}, + {[]rideType{toRideBigInt(2), rideInt(0), toRideBigInt(512), rideInt(0), rideInt(0), newDown(nil)}, true, nil}, + {[]rideType{toRideBigInt(12), rideInt(1), toRideBigInt(3456), rideInt(3), rideInt(2), newUp(nil), newDown(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(10), rideInt(0), rideInt(0), newUp(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(1), rideInt(0), rideInt(0), newNoAlg(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(1), rideString("0"), rideInt(0), newUp(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(1), rideInt(0), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(1), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(1)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := powBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestLogBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(16), rideInt(0), toRideBigInt(2), rideInt(0), rideInt(0), newCeiling(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(1), rideInt(4), toRideBigInt(1), rideInt(1), rideInt(0), newHalfEven(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(16), rideInt(0), toRideBigInt(-2), rideInt(0), rideInt(0), newCeiling(nil)}, true, nil}, + {[]rideType{toRideBigInt(-16), rideInt(0), toRideBigInt(2), rideInt(0), rideInt(0), newCeiling(nil)}, true, nil}, + {[]rideType{toRideBigInt(1), rideInt(16), toRideBigInt(10), rideInt(0), rideInt(0), newCeiling(nil)}, false, toRideBigInt(-16)}, + {[]rideType{toRideBigInt(100), rideInt(0), toRideBigInt(10), rideInt(0), rideInt(0), newUp(nil)}, false, toRideBigInt(2)}, + {[]rideType{toRideBigInt(100), rideInt(0), toRideBigInt(10), rideInt(0), rideInt(0), newUp(nil), newDown(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(100), rideInt(0), rideInt(0), newNoAlg(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(100), rideString("0"), rideInt(0), newUp(nil)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(100), rideInt(0), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(100), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0), toRideBigInt(100)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64), rideInt(0)}, true, nil}, + {[]rideType{toRideBigInt(math.MaxInt64)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := logBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestToBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideInt(0)}, false, toRideBigInt(0)}, + {[]rideType{rideInt(-1)}, false, toRideBigInt(-1)}, + {[]rideType{rideInt(1)}, false, toRideBigInt(1)}, + {[]rideType{rideInt(-1234567890)}, false, toRideBigInt(-1234567890)}, + {[]rideType{rideInt(1234567890)}, false, toRideBigInt(1234567890)}, + {[]rideType{rideInt(math.MaxInt64)}, false, toRideBigInt(math.MaxInt64)}, + {[]rideType{rideInt(math.MinInt64)}, false, toRideBigInt(math.MinInt64)}, + {[]rideType{}, true, nil}, + {[]rideType{rideString("12345")}, true, nil}, + {[]rideType{toRideBigInt(12345)}, true, nil}, + {[]rideType{rideInt(12345), rideInt(67890)}, true, nil}, + } { + r, err := toBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestSumBigInt(t *testing.T) { + doubleMaxInt64 := big.NewInt(math.MaxInt64) + doubleMaxInt64 = doubleMaxInt64.Add(doubleMaxInt64, doubleMaxInt64) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(5), toRideBigInt(5)}, false, toRideBigInt(10)}, + {[]rideType{toRideBigInt(-5), toRideBigInt(5)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(0), toRideBigInt(0)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(math.MinInt64)}, false, toRideBigInt(-1)}, + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(math.MaxInt64)}, false, rideBigInt{v: doubleMaxInt64}}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(1)}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(1), toRideBigInt(1)}, true, nil}, + {[]rideType{toRideBigInt(1), rideInt(1)}, true, nil}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := sumBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestSubtractBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(5), toRideBigInt(4)}, false, toRideBigInt(1)}, + {[]rideType{toRideBigInt(5), toRideBigInt(5)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(-5), toRideBigInt(5)}, false, toRideBigInt(-10)}, + {[]rideType{toRideBigInt(0), toRideBigInt(0)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(math.MaxInt64)}, false, toRideBigInt(0)}, + {[]rideType{rideBigInt{v: minBigInt}, toRideBigInt(1)}, true, nil}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := subtractBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestMultiplyBigInt(t *testing.T) { + n := big.NewInt(math.MaxInt64) + n = n.Mul(n, n) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(5), toRideBigInt(4)}, false, toRideBigInt(20)}, + {[]rideType{toRideBigInt(5), toRideBigInt(5)}, false, toRideBigInt(25)}, + {[]rideType{toRideBigInt(-5), toRideBigInt(5)}, false, toRideBigInt(-25)}, + {[]rideType{toRideBigInt(0), toRideBigInt(0)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(math.MaxInt64)}, false, rideBigInt{v: n}}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(2)}, true, nil}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := multiplyBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestDivideBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(10), toRideBigInt(2)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(25), toRideBigInt(5)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(-25), toRideBigInt(5)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(math.MaxInt64)}, false, toRideBigInt(1)}, + {[]rideType{rideBigInt{v: maxBigInt}, rideBigInt{v: maxBigInt}}, false, toRideBigInt(1)}, + {[]rideType{rideBigInt{v: minBigInt}, rideBigInt{v: minBigInt}}, false, toRideBigInt(1)}, + {[]rideType{rideBigInt{v: maxBigInt}, rideBigInt{v: minBigInt}}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(10), toRideBigInt(0)}, true, nil}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := divideBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestModuloBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(10), toRideBigInt(6)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(-10), toRideBigInt(6)}, false, toRideBigInt(2)}, + {[]rideType{toRideBigInt(10), toRideBigInt(-6)}, false, toRideBigInt(-2)}, + {[]rideType{toRideBigInt(-10), toRideBigInt(-6)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(2), toRideBigInt(2)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(10), toRideBigInt(0)}, true, nil}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := moduloBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestFractionBigInt(t *testing.T) { + r1 := big.NewInt(0).Set(maxBigInt) + r1 = r1.Mul(r1, big.NewInt(2)) + r1 = r1.Div(r1, big.NewInt(3)) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(4), toRideBigInt(6)}, false, toRideBigInt(6148914691236517204)}, + {[]rideType{toRideBigInt(8), toRideBigInt(4), toRideBigInt(2)}, false, toRideBigInt(16)}, + {[]rideType{toRideBigInt(8), toRideBigInt(-2), toRideBigInt(-3)}, false, toRideBigInt(5)}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(-2), toRideBigInt(-3)}, false, rideBigInt{v: r1}}, + {[]rideType{rideBigInt{v: maxBigInt}, rideBigInt{v: maxBigInt}, rideBigInt{v: maxBigInt}}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{rideBigInt{v: minBigInt}, rideBigInt{v: minBigInt}, rideBigInt{v: minBigInt}}, false, rideBigInt{v: minBigInt}}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(4), toRideBigInt(1)}, true, nil}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(4), toRideBigInt(0)}, true, nil}, + {[]rideType{toRideBigInt(2), toRideBigInt(2)}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := fractionBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestFractionBigIntRounds(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(math.MaxInt64), toRideBigInt(4), toRideBigInt(6), newFloor(nil)}, false, toRideBigInt(6148914691236517204)}, + {[]rideType{toRideBigInt(8), toRideBigInt(4), toRideBigInt(2), newFloor(nil)}, false, toRideBigInt(16)}, + {[]rideType{toRideBigInt(8), toRideBigInt(-2), toRideBigInt(-3), newFloor(nil)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(2), newDown(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(2), newDown(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(-2), newDown(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(-2), newDown(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(2), newCeiling(nil)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(2), newCeiling(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(-2), newCeiling(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(-2), newCeiling(nil)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(2), newFloor(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(2), newFloor(nil)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(-2), newFloor(nil)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(-2), newFloor(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(2), newHalfUp(nil)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(2), newHalfUp(nil)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(-2), newHalfUp(nil)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(-2), newHalfUp(nil)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(2), newHalfEven(nil)}, false, toRideBigInt(4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(2), newHalfEven(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(9), toRideBigInt(1), toRideBigInt(-2), newHalfEven(nil)}, false, toRideBigInt(-4)}, + {[]rideType{toRideBigInt(-9), toRideBigInt(1), toRideBigInt(-2), newHalfEven(nil)}, false, toRideBigInt(4)}, + {[]rideType{rideBigInt{v: maxBigInt}, rideBigInt{v: maxBigInt}, rideBigInt{v: maxBigInt}, newCeiling(nil)}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{rideBigInt{v: minBigInt}, rideBigInt{v: minBigInt}, rideBigInt{v: minBigInt}, newCeiling(nil)}, false, rideBigInt{v: minBigInt}}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(4), toRideBigInt(1), newFloor(nil)}, true, nil}, + {[]rideType{rideBigInt{v: maxBigInt}, toRideBigInt(4), toRideBigInt(0), newFloor(nil)}, true, nil}, + {[]rideType{toRideBigInt(2), toRideBigInt(2), toRideBigInt(3)}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := fractionBigIntRounds(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestUnaryMinusBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(math.MaxInt64)}, false, toRideBigInt(-math.MaxInt64)}, + {[]rideType{toRideBigInt(5)}, false, toRideBigInt(-5)}, + {[]rideType{toRideBigInt(0)}, false, toRideBigInt(0)}, + {[]rideType{toRideBigInt(-5)}, false, toRideBigInt(5)}, + {[]rideType{toRideBigInt(math.MinInt64)}, false, rideBigInt{v: big.NewInt(0).Neg(big.NewInt(math.MinInt64))}}, + {[]rideType{rideBigInt{v: minBigInt}}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(5)}, true, nil}, + {[]rideType{rideUnit{}}, true, nil}, + {[]rideType{}, true, nil}, + {[]rideType{rideString("x")}, true, nil}, + } { + r, err := unaryMinusBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestGTBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(5), toRideBigInt(4)}, false, rideBoolean(true)}, + {[]rideType{toRideBigInt(16), toRideBigInt(2)}, false, rideBoolean(true)}, + {[]rideType{toRideBigInt(5), toRideBigInt(5)}, false, rideBoolean(false)}, + {[]rideType{toRideBigInt(1), toRideBigInt(5)}, false, rideBoolean(false)}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), toRideBigInt(3)}, true, nil}, + {[]rideType{toRideBigInt(1), rideInt(2)}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := gtBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestGEBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(15), toRideBigInt(5)}, false, rideBoolean(true)}, + {[]rideType{toRideBigInt(5), toRideBigInt(5)}, false, rideBoolean(true)}, + {[]rideType{toRideBigInt(1), toRideBigInt(5)}, false, rideBoolean(false)}, + {[]rideType{toRideBigInt(1), rideUnit{}}, true, nil}, + {[]rideType{toRideBigInt(1), toRideBigInt(2), toRideBigInt(3)}, true, nil}, + {[]rideType{toRideBigInt(1), rideInt(2)}, true, nil}, + {[]rideType{toRideBigInt(1), rideString("x")}, true, nil}, + {[]rideType{toRideBigInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := geBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestMaxListBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideList(toRideBigInt(1), toRideBigInt(2), toRideBigInt(3))}, false, toRideBigInt(3)}, + {[]rideType{toRideList(toRideBigInt(-1), toRideBigInt(-2), toRideBigInt(-3))}, false, toRideBigInt(-1)}, + {[]rideType{toRideList(toRideBigInt(0), toRideBigInt(0), toRideBigInt(0))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(toRideBigInt(0))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(rideBigInt{v: maxBigInt}, rideBigInt{v: minBigInt}, toRideBigInt(0), toRideBigInt(-10), toRideBigInt(10))}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{toRideList(toRideBigInt(0)), rideInt(1)}, true, nil}, + {[]rideType{toRideList()}, true, nil}, + {[]rideType{toRideBigInt(0)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := maxListBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestMinListBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideList(toRideBigInt(1), toRideBigInt(2), toRideBigInt(3))}, false, toRideBigInt(1)}, + {[]rideType{toRideList(toRideBigInt(-1), toRideBigInt(-2), toRideBigInt(-3))}, false, toRideBigInt(-3)}, + {[]rideType{toRideList(toRideBigInt(0), toRideBigInt(0), toRideBigInt(0))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(toRideBigInt(0))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(rideBigInt{v: maxBigInt}, rideBigInt{v: minBigInt}, toRideBigInt(0), toRideBigInt(-10), toRideBigInt(10))}, false, rideBigInt{v: minBigInt}}, + {[]rideType{toRideList(toRideBigInt(0)), rideInt(1)}, true, nil}, + {[]rideType{toRideList()}, true, nil}, + {[]rideType{toRideBigInt(0)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := minListBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestBigIntToBytes(t *testing.T) { + v, ok := big.NewInt(0).SetString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480", 10) + require.True(t, ok) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(-1)}, false, toRideBytes("ff")}, + {[]rideType{toRideBigInt(0)}, false, toRideBytes("00")}, + {[]rideType{toRideBigInt(1)}, false, toRideBytes("01")}, + {[]rideType{toRideBigInt(1234567890)}, false, toRideBytes("499602d2")}, + {[]rideType{toRideBigInt(-1234567890)}, false, toRideBytes("b669fd2e")}, + {[]rideType{rideBigInt{v: maxBigInt}}, false, toRideBytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, + {[]rideType{rideBigInt{v: minBigInt}}, false, toRideBytes("80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}, + {[]rideType{toRideBigInt(math.MaxInt64)}, false, toRideBytes("7fffffffffffffff")}, + {[]rideType{toRideBigInt(math.MinInt64)}, false, toRideBytes("8000000000000000")}, + {[]rideType{rideBigInt{v: v}}, false, toRideBytes("0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40")}, + {[]rideType{toRideBigInt(0), rideInt(4)}, true, nil}, + {[]rideType{rideString("0")}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := bigIntToBytes(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBytesToBigInt(t *testing.T) { + v, ok := big.NewInt(0).SetString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480", 10) + require.True(t, ok) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBytes("ff")}, false, toRideBigInt(-1)}, + {[]rideType{toRideBytes("00")}, false, toRideBigInt(0)}, + {[]rideType{toRideBytes("01")}, false, toRideBigInt(1)}, + {[]rideType{toRideBytes("499602d2")}, false, toRideBigInt(1234567890)}, + {[]rideType{toRideBytes("b669fd2e")}, false, toRideBigInt(-1234567890)}, + {[]rideType{toRideBytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{toRideBytes("80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}, false, rideBigInt{v: minBigInt}}, + {[]rideType{toRideBytes("7fffffffffffffff")}, false, toRideBigInt(math.MaxInt64)}, + {[]rideType{toRideBytes("8000000000000000")}, false, toRideBigInt(math.MinInt64)}, + {[]rideType{toRideBytes("0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40")}, false, rideBigInt{v: v}}, + {[]rideType{toRideBytes("ff"), rideInt(4)}, true, nil}, + {[]rideType{rideString("0")}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := bytesToBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestBytesToBigIntLim(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBytes("cafebebeff"), rideInt(4), rideInt(1)}, false, toRideBigInt(-1)}, + {[]rideType{toRideBytes("cafebebeff"), rideInt(4), rideInt(4)}, false, toRideBigInt(-1)}, + {[]rideType{toRideBytes("00deadbeef"), rideInt(0), rideInt(1)}, false, toRideBigInt(0)}, + {[]rideType{toRideBytes("cafe01bebe"), rideInt(2), rideInt(1)}, false, toRideBigInt(1)}, + {[]rideType{toRideBytes("deadbeef499602d2"), rideInt(4), rideInt(4)}, false, toRideBigInt(1234567890)}, + {[]rideType{toRideBytes("deadbeefb669fd2e"), rideInt(4), rideInt(4)}, false, toRideBigInt(-1234567890)}, + {[]rideType{toRideBytes("cafebebe7fffffffffffffff"), rideInt(4), rideInt(8)}, false, toRideBigInt(math.MaxInt64)}, + {[]rideType{toRideBytes("8000000000000000cafebebe"), rideInt(0), rideInt(8)}, false, toRideBigInt(math.MinInt64)}, + {[]rideType{toRideBytes("deadbeef00"), rideInt(5), rideInt(1)}, true, nil}, + {[]rideType{toRideBytes("deadbeef00"), rideInt(4), rideInt(65)}, true, nil}, + {[]rideType{toRideBytes("deadbeef00"), rideInt(-1), rideInt(5)}, true, nil}, + {[]rideType{toRideBytes("deadbeef00"), rideInt(4), rideInt(0)}, true, nil}, + {[]rideType{toRideBytes("deadbeef00"), rideInt(4), rideInt(-1)}, true, nil}, + {[]rideType{toRideBytes("ff"), rideInt(4)}, true, nil}, + {[]rideType{rideString("0")}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := bytesToBigIntLim(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestBigIntToInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(-1)}, false, rideInt(-1)}, + {[]rideType{toRideBigInt(0)}, false, rideInt(0)}, + {[]rideType{toRideBigInt(1)}, false, rideInt(1)}, + {[]rideType{toRideBigInt(1234567890)}, false, rideInt(1234567890)}, + {[]rideType{toRideBigInt(-1234567890)}, false, rideInt(-1234567890)}, + {[]rideType{toRideBigInt(math.MaxInt64)}, false, rideInt(math.MaxInt64)}, + {[]rideType{toRideBigInt(math.MinInt64)}, false, rideInt(math.MinInt64)}, + {[]rideType{rideBigInt{v: maxBigInt}}, true, nil}, + {[]rideType{rideBigInt{v: minBigInt}}, true, nil}, + {[]rideType{toRideBigInt(0), rideInt(4)}, true, nil}, + {[]rideType{rideString("0")}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := bigIntToInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBigIntToString(t *testing.T) { + v, ok := big.NewInt(0).SetString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480", 10) + require.True(t, ok) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideBigInt(-1)}, false, rideString("-1")}, + {[]rideType{toRideBigInt(0)}, false, rideString("0")}, + {[]rideType{toRideBigInt(1)}, false, rideString("1")}, + {[]rideType{toRideBigInt(1234567890)}, false, rideString("1234567890")}, + {[]rideType{toRideBigInt(-1234567890)}, false, rideString("-1234567890")}, + {[]rideType{rideBigInt{v: maxBigInt}}, false, rideString("6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042047")}, + {[]rideType{rideBigInt{v: minBigInt}}, false, rideString("-6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048")}, + {[]rideType{toRideBigInt(math.MaxInt64)}, false, rideString("9223372036854775807")}, + {[]rideType{toRideBigInt(math.MinInt64)}, false, rideString("-9223372036854775808")}, + {[]rideType{rideBigInt{v: v}}, false, rideString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480")}, + {[]rideType{toRideBigInt(0), rideInt(4)}, true, nil}, + {[]rideType{rideString("0")}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := bigIntToString(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestStringToBigInt(t *testing.T) { + v, ok := big.NewInt(0).SetString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480", 10) + require.True(t, ok) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("-1")}, false, toRideBigInt(-1)}, + {[]rideType{rideString("0")}, false, toRideBigInt(0)}, + {[]rideType{rideString("1")}, false, toRideBigInt(1)}, + {[]rideType{rideString("1234567890")}, false, toRideBigInt(1234567890)}, + {[]rideType{rideString("-1234567890")}, false, toRideBigInt(-1234567890)}, + {[]rideType{rideString("6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042047")}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{rideString("-6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048")}, false, rideBigInt{v: minBigInt}}, + {[]rideType{rideString("9223372036854775807")}, false, toRideBigInt(math.MaxInt64)}, + {[]rideType{rideString("-9223372036854775808")}, false, toRideBigInt(math.MinInt64)}, + {[]rideType{rideString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480")}, false, rideBigInt{v: v}}, + {[]rideType{rideString("0"), rideInt(4)}, true, nil}, + {[]rideType{rideInt(0)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := stringToBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestStringToBigIntOpt(t *testing.T) { + v, ok := big.NewInt(0).SetString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480", 10) + require.True(t, ok) + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("-1")}, false, toRideBigInt(-1)}, + {[]rideType{rideString("0")}, false, toRideBigInt(0)}, + {[]rideType{rideString("1")}, false, toRideBigInt(1)}, + {[]rideType{rideString("1234567890")}, false, toRideBigInt(1234567890)}, + {[]rideType{rideString("-1234567890")}, false, toRideBigInt(-1234567890)}, + {[]rideType{rideString("6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042047")}, false, rideBigInt{v: maxBigInt}}, + {[]rideType{rideString("-6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048")}, false, rideBigInt{v: minBigInt}}, + {[]rideType{rideString("9223372036854775807")}, false, toRideBigInt(math.MaxInt64)}, + {[]rideType{rideString("-9223372036854775808")}, false, toRideBigInt(math.MinInt64)}, + {[]rideType{rideString("52785833603464895924505196455835395749861094195642486808108138863402869537852026544579466671752822414281401856143643660416162921950916138504990605852480")}, false, rideBigInt{v: v}}, + {[]rideType{rideString("0"), rideInt(4)}, false, newUnit(nil)}, + {[]rideType{rideInt(0)}, false, newUnit(nil)}, + {[]rideType{}, false, newUnit(nil)}, + } { + r, err := stringToBigIntOpt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func TestMedianListBigInt(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{toRideList(toRideBigInt(1), toRideBigInt(2), toRideBigInt(3), toRideBigInt(4))}, false, toRideBigInt(3)}, + {[]rideType{toRideList(toRideBigInt(1), toRideBigInt(2), toRideBigInt(3), toRideBigInt(4), toRideBigInt(5))}, false, toRideBigInt(3)}, + {[]rideType{toRideList(toRideBigInt(-1), toRideBigInt(-2), toRideBigInt(-3))}, false, toRideBigInt(-2)}, + {[]rideType{toRideList(toRideBigInt(0), toRideBigInt(0), toRideBigInt(0))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(toRideBigInt(0), toRideBigInt(1), toRideBigInt(1), toRideBigInt(1), toRideBigInt(1), toRideBigInt(2), toRideBigInt(3))}, false, toRideBigInt(1)}, + {[]rideType{toRideList(rideBigInt{v: maxBigInt}, rideBigInt{v: minBigInt}, toRideBigInt(0), toRideBigInt(-10), toRideBigInt(10))}, false, toRideBigInt(0)}, + {[]rideType{toRideList(toRideBigInt(0))}, true, nil}, + {[]rideType{toRideList(toRideBigInt(0)), rideInt(1)}, true, nil}, + {[]rideType{toRideList()}, true, nil}, + {[]rideType{toRideBigInt(0)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := medianListBigInt(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, test.r.eq(r), fmt.Sprintf("%s != %s", test.r, r)) + } + } +} + +func toRideBigInt(i int) rideBigInt { + v := big.NewInt(int64(i)) + return rideBigInt{v: v} +} + +func toRideBytes(s string) rideBytes { + r, _ := hex.DecodeString(s) + return r +} + +func toRideList(args ...rideType) rideList { + return args +} diff --git a/pkg/ride/functions_boolean.go b/pkg/ride/functions_boolean.go index 283e33e17..e603fa019 100644 --- a/pkg/ride/functions_boolean.go +++ b/pkg/ride/functions_boolean.go @@ -16,7 +16,7 @@ func booleanArg(args []rideType) (rideBoolean, error) { return b, nil } -func booleanToBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func booleanToBytes(_ Environment, args ...rideType) (rideType, error) { b, err := booleanArg(args) if err != nil { return nil, errors.Wrap(err, "booleanToBytes") @@ -28,7 +28,7 @@ func booleanToBytes(_ RideEnvironment, args ...rideType) (rideType, error) { } } -func booleanToString(_ RideEnvironment, args ...rideType) (rideType, error) { +func booleanToString(_ Environment, args ...rideType) (rideType, error) { b, err := booleanArg(args) if err != nil { return nil, errors.Wrap(err, "booleanToString") @@ -40,7 +40,7 @@ func booleanToString(_ RideEnvironment, args ...rideType) (rideType, error) { } } -func unaryNot(_ RideEnvironment, args ...rideType) (rideType, error) { +func unaryNot(_ Environment, args ...rideType) (rideType, error) { b, err := booleanArg(args) if err != nil { return nil, errors.Wrap(err, "unaryNot") diff --git a/pkg/ride/functions_bytes.go b/pkg/ride/functions_bytes.go index 4b89bc134..e6e086853 100644 --- a/pkg/ride/functions_bytes.go +++ b/pkg/ride/functions_bytes.go @@ -86,7 +86,7 @@ func bytesOrUnitArgAsBytes(args ...rideType) ([]byte, error) { } } -func sizeBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func sizeBytes(_ Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "sizeBytes") @@ -94,7 +94,7 @@ func sizeBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(len(b)), nil } -func takeBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func takeBytes(_ Environment, args ...rideType) (rideType, error) { b, n, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "takeBytes") @@ -102,7 +102,7 @@ func takeBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return takeRideBytes(b, n), nil } -func dropBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func dropBytes(_ Environment, args ...rideType) (rideType, error) { b, n, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "dropBytes") @@ -110,7 +110,7 @@ func dropBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return dropRideBytes(b, n), nil } -func concatBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func concatBytes(_ Environment, args ...rideType) (rideType, error) { b1, b2, err := bytesArgs2(args) if err != nil { return nil, errors.Wrap(err, "concatBytes") @@ -125,7 +125,7 @@ func concatBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(out), nil } -func toBase58(_ RideEnvironment, args ...rideType) (rideType, error) { +func toBase58(_ Environment, args ...rideType) (rideType, error) { b, err := bytesOrUnitArgAsBytes(args...) if err != nil { return nil, errors.Wrap(err, "toBase58") @@ -133,7 +133,7 @@ func toBase58(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(base58.Encode(b)), nil } -func fromBase58(_ RideEnvironment, args ...rideType) (rideType, error) { +func fromBase58(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "fromBase58") @@ -149,7 +149,7 @@ func fromBase58(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(r), nil } -func toBase64(_ RideEnvironment, args ...rideType) (rideType, error) { +func toBase64(_ Environment, args ...rideType) (rideType, error) { b, err := bytesOrUnitArgAsBytes(args...) if err != nil { return nil, errors.Wrap(err, "toBase64") @@ -157,7 +157,7 @@ func toBase64(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(base64.StdEncoding.EncodeToString(b)), nil } -func fromBase64(_ RideEnvironment, args ...rideType) (rideType, error) { +func fromBase64(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "fromBase64") @@ -174,7 +174,7 @@ func fromBase64(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(decoded), nil } -func toBase16(_ RideEnvironment, args ...rideType) (rideType, error) { +func toBase16(_ Environment, args ...rideType) (rideType, error) { b, err := bytesOrUnitArgAsBytes(args...) if err != nil { return nil, errors.Wrap(err, "toBase16") @@ -182,7 +182,7 @@ func toBase16(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(hex.EncodeToString(b)), nil } -func fromBase16(_ RideEnvironment, args ...rideType) (rideType, error) { +func fromBase16(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "fromBase16") @@ -195,7 +195,7 @@ func fromBase16(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(decoded), nil } -func dropRightBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func dropRightBytes(_ Environment, args ...rideType) (rideType, error) { b, n, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "dropRightBytes") @@ -203,7 +203,7 @@ func dropRightBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return takeRideBytes(b, len(b)-n), nil } -func takeRightBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func takeRightBytes(_ Environment, args ...rideType) (rideType, error) { b, n, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "takeRightBytes") @@ -211,7 +211,7 @@ func takeRightBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return dropRideBytes(b, len(b)-n), nil } -func bytesToUTF8String(_ RideEnvironment, args ...rideType) (rideType, error) { +func bytesToUTF8String(_ Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "bytesToUTF8String") @@ -222,7 +222,7 @@ func bytesToUTF8String(_ RideEnvironment, args ...rideType) (rideType, error) { return nil, errors.Errorf("invalid UTF-8 sequence") } -func bytesToInt(_ RideEnvironment, args ...rideType) (rideType, error) { +func bytesToInt(_ Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "bytesToInt") @@ -233,7 +233,7 @@ func bytesToInt(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(binary.BigEndian.Uint64(b)), nil } -func bytesToIntWithOffset(_ RideEnvironment, args ...rideType) (rideType, error) { +func bytesToIntWithOffset(_ Environment, args ...rideType) (rideType, error) { b, n, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "bytesToLongWithOffset") diff --git a/pkg/ride/functions_common.go b/pkg/ride/functions_common.go index d570169c0..a7765de47 100644 --- a/pkg/ride/functions_common.go +++ b/pkg/ride/functions_common.go @@ -20,21 +20,21 @@ func checkArgs(args []rideType, count int) error { return nil } -func eq(_ RideEnvironment, args ...rideType) (rideType, error) { +func eq(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "eq") } return rideBoolean(args[0].eq(args[1])), nil } -func neq(_ RideEnvironment, args ...rideType) (rideType, error) { +func neq(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "neq") } return rideBoolean(!args[0].eq(args[1])), nil } -func instanceOf(_ RideEnvironment, args ...rideType) (rideType, error) { +func instanceOf(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "instanceOf") } @@ -45,7 +45,7 @@ func instanceOf(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(args[0].instanceOf() == string(t)), nil } -func extract(_ RideEnvironment, args ...rideType) (rideType, error) { +func extract(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "extract") } @@ -55,7 +55,7 @@ func extract(_ RideEnvironment, args ...rideType) (rideType, error) { return args[0], nil } -func isDefined(_ RideEnvironment, args ...rideType) (rideType, error) { +func isDefined(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "isDefined") } @@ -65,7 +65,7 @@ func isDefined(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(true), nil } -func throw(_ RideEnvironment, args ...rideType) (rideType, error) { +func throw(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "throw") @@ -73,11 +73,11 @@ func throw(_ RideEnvironment, args ...rideType) (rideType, error) { return rideThrow(s), nil } -func throw0(_ RideEnvironment, _ ...rideType) (rideType, error) { +func throw0(_ Environment, _ ...rideType) (rideType, error) { return rideThrow(defaultThrowMessage), nil } -func value(_ RideEnvironment, args ...rideType) (rideType, error) { +func value(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "value") } @@ -87,7 +87,7 @@ func value(_ RideEnvironment, args ...rideType) (rideType, error) { return args[0], nil } -func valueOrErrorMessage(_ RideEnvironment, args ...rideType) (rideType, error) { +func valueOrErrorMessage(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "valueOrErrorMessage") } @@ -101,7 +101,7 @@ func valueOrErrorMessage(_ RideEnvironment, args ...rideType) (rideType, error) return args[0], nil } -func valueOrElse(_ RideEnvironment, args ...rideType) (rideType, error) { +func valueOrElse(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "valueOrErrorMessage") } diff --git a/pkg/ride/functions_generated.go b/pkg/ride/functions_generated.go index 3178158f9..f02cb201a 100644 --- a/pkg/ride/functions_generated.go +++ b/pkg/ride/functions_generated.go @@ -11,7 +11,7 @@ import ( c2 "github.com/wavesplatform/gowaves/pkg/ride/crypto" ) -func bls12Groth16Verify_1(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_1(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_1") } @@ -32,12 +32,12 @@ func bls12Groth16Verify_1(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_1") } return rideBoolean(ok), nil } -func bls12Groth16Verify_2(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_2(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_2") } @@ -58,12 +58,12 @@ func bls12Groth16Verify_2(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_2") } return rideBoolean(ok), nil } -func bls12Groth16Verify_3(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_3(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_3") } @@ -84,12 +84,12 @@ func bls12Groth16Verify_3(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_3") } return rideBoolean(ok), nil } -func bls12Groth16Verify_4(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_4(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_4") } @@ -110,12 +110,12 @@ func bls12Groth16Verify_4(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_4") } return rideBoolean(ok), nil } -func bls12Groth16Verify_5(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_5(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_5") } @@ -136,12 +136,12 @@ func bls12Groth16Verify_5(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_5") } return rideBoolean(ok), nil } -func bls12Groth16Verify_6(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_6(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_6") } @@ -162,12 +162,12 @@ func bls12Groth16Verify_6(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_6") } return rideBoolean(ok), nil } -func bls12Groth16Verify_7(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_7(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_7") } @@ -188,12 +188,12 @@ func bls12Groth16Verify_7(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_7") } return rideBoolean(ok), nil } -func bls12Groth16Verify_8(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_8(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_8") } @@ -214,12 +214,12 @@ func bls12Groth16Verify_8(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_8") } return rideBoolean(ok), nil } -func bls12Groth16Verify_9(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_9(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_9") } @@ -240,12 +240,12 @@ func bls12Groth16Verify_9(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_9") } return rideBoolean(ok), nil } -func bls12Groth16Verify_10(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_10(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_10") } @@ -266,12 +266,12 @@ func bls12Groth16Verify_10(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_10") } return rideBoolean(ok), nil } -func bls12Groth16Verify_11(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_11(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_11") } @@ -292,12 +292,12 @@ func bls12Groth16Verify_11(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_11") } return rideBoolean(ok), nil } -func bls12Groth16Verify_12(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_12(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_12") } @@ -318,12 +318,12 @@ func bls12Groth16Verify_12(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_12") } return rideBoolean(ok), nil } -func bls12Groth16Verify_13(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_13(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_13") } @@ -344,12 +344,12 @@ func bls12Groth16Verify_13(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_13") } return rideBoolean(ok), nil } -func bls12Groth16Verify_14(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_14(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_14") } @@ -370,12 +370,12 @@ func bls12Groth16Verify_14(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_14") } return rideBoolean(ok), nil } -func bls12Groth16Verify_15(env RideEnvironment, args ...rideType) (rideType, error) { +func bls12Groth16Verify_15(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bls12Groth16Verify_15") } @@ -396,12 +396,12 @@ func bls12Groth16Verify_15(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bls12Groth16Verify_15") } return rideBoolean(ok), nil } -func bn256Groth16Verify_1(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_1(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_1") } @@ -422,12 +422,12 @@ func bn256Groth16Verify_1(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_1") } return rideBoolean(ok), nil } -func bn256Groth16Verify_2(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_2(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_2") } @@ -448,12 +448,12 @@ func bn256Groth16Verify_2(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_2") } return rideBoolean(ok), nil } -func bn256Groth16Verify_3(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_3(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_3") } @@ -474,12 +474,12 @@ func bn256Groth16Verify_3(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_3") } return rideBoolean(ok), nil } -func bn256Groth16Verify_4(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_4(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_4") } @@ -500,12 +500,12 @@ func bn256Groth16Verify_4(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_4") } return rideBoolean(ok), nil } -func bn256Groth16Verify_5(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_5(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_5") } @@ -526,12 +526,12 @@ func bn256Groth16Verify_5(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_5") } return rideBoolean(ok), nil } -func bn256Groth16Verify_6(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_6(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_6") } @@ -552,12 +552,12 @@ func bn256Groth16Verify_6(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_6") } return rideBoolean(ok), nil } -func bn256Groth16Verify_7(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_7(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_7") } @@ -578,12 +578,12 @@ func bn256Groth16Verify_7(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_7") } return rideBoolean(ok), nil } -func bn256Groth16Verify_8(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_8(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_8") } @@ -604,12 +604,12 @@ func bn256Groth16Verify_8(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_8") } return rideBoolean(ok), nil } -func bn256Groth16Verify_9(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_9(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_9") } @@ -630,12 +630,12 @@ func bn256Groth16Verify_9(env RideEnvironment, args ...rideType) (rideType, erro } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_9") } return rideBoolean(ok), nil } -func bn256Groth16Verify_10(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_10(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_10") } @@ -656,12 +656,12 @@ func bn256Groth16Verify_10(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_10") } return rideBoolean(ok), nil } -func bn256Groth16Verify_11(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_11(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_11") } @@ -682,12 +682,12 @@ func bn256Groth16Verify_11(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_11") } return rideBoolean(ok), nil } -func bn256Groth16Verify_12(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_12(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_12") } @@ -708,12 +708,12 @@ func bn256Groth16Verify_12(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_12") } return rideBoolean(ok), nil } -func bn256Groth16Verify_13(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_13(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_13") } @@ -734,12 +734,12 @@ func bn256Groth16Verify_13(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_13") } return rideBoolean(ok), nil } -func bn256Groth16Verify_14(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_14(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_14") } @@ -760,12 +760,12 @@ func bn256Groth16Verify_14(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_14") } return rideBoolean(ok), nil } -func bn256Groth16Verify_15(env RideEnvironment, args ...rideType) (rideType, error) { +func bn256Groth16Verify_15(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "bn256Groth16Verify_15") } @@ -786,12 +786,12 @@ func bn256Groth16Verify_15(env RideEnvironment, args ...rideType) (rideType, err } ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) if err != nil { - return rideUnit{}, err + return nil, errors.Wrap(err, "bn256Groth16Verify_15") } return rideBoolean(ok), nil } -func sigVerify_8(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify_8(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify_8") } @@ -822,7 +822,7 @@ func sigVerify_8(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func sigVerify_16(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify_16(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify_16") } @@ -853,7 +853,7 @@ func sigVerify_16(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func sigVerify_32(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify_32(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify_32") } @@ -884,7 +884,7 @@ func sigVerify_32(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func sigVerify_64(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify_64(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify_64") } @@ -915,7 +915,7 @@ func sigVerify_64(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func sigVerify_128(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify_128(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify_128") } @@ -946,7 +946,7 @@ func sigVerify_128(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func rsaVerify_16(_ RideEnvironment, args ...rideType) (rideType, error) { +func rsaVerify_16(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 4); err != nil { return nil, errors.Wrap(err, "rsaVerify_16") } @@ -990,7 +990,7 @@ func rsaVerify_16(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func rsaVerify_32(_ RideEnvironment, args ...rideType) (rideType, error) { +func rsaVerify_32(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 4); err != nil { return nil, errors.Wrap(err, "rsaVerify_32") } @@ -1034,7 +1034,7 @@ func rsaVerify_32(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func rsaVerify_64(_ RideEnvironment, args ...rideType) (rideType, error) { +func rsaVerify_64(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 4); err != nil { return nil, errors.Wrap(err, "rsaVerify_64") } @@ -1078,7 +1078,7 @@ func rsaVerify_64(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func rsaVerify_128(_ RideEnvironment, args ...rideType) (rideType, error) { +func rsaVerify_128(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 4); err != nil { return nil, errors.Wrap(err, "rsaVerify_128") } @@ -1122,7 +1122,7 @@ func rsaVerify_128(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func keccak256_16(env RideEnvironment, args ...rideType) (rideType, error) { +func keccak256_16(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "keccak256_16") @@ -1137,7 +1137,7 @@ func keccak256_16(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func keccak256_32(env RideEnvironment, args ...rideType) (rideType, error) { +func keccak256_32(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "keccak256_32") @@ -1152,7 +1152,7 @@ func keccak256_32(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func keccak256_64(env RideEnvironment, args ...rideType) (rideType, error) { +func keccak256_64(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "keccak256_64") @@ -1167,7 +1167,7 @@ func keccak256_64(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func keccak256_128(env RideEnvironment, args ...rideType) (rideType, error) { +func keccak256_128(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "keccak256_128") @@ -1182,7 +1182,7 @@ func keccak256_128(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func blake2b256_16(_ RideEnvironment, args ...rideType) (rideType, error) { +func blake2b256_16(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "blake2b256_16") @@ -1197,7 +1197,7 @@ func blake2b256_16(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func blake2b256_32(_ RideEnvironment, args ...rideType) (rideType, error) { +func blake2b256_32(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "blake2b256_32") @@ -1212,7 +1212,7 @@ func blake2b256_32(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func blake2b256_64(_ RideEnvironment, args ...rideType) (rideType, error) { +func blake2b256_64(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "blake2b256_64") @@ -1227,7 +1227,7 @@ func blake2b256_64(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func blake2b256_128(_ RideEnvironment, args ...rideType) (rideType, error) { +func blake2b256_128(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "blake2b256_128") @@ -1242,7 +1242,7 @@ func blake2b256_128(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func sha256_16(_ RideEnvironment, args ...rideType) (rideType, error) { +func sha256_16(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "sha256_16") @@ -1258,7 +1258,7 @@ func sha256_16(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d), nil } -func sha256_32(_ RideEnvironment, args ...rideType) (rideType, error) { +func sha256_32(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "sha256_32") @@ -1274,7 +1274,7 @@ func sha256_32(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d), nil } -func sha256_64(_ RideEnvironment, args ...rideType) (rideType, error) { +func sha256_64(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "sha256_64") @@ -1290,7 +1290,7 @@ func sha256_64(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d), nil } -func sha256_128(_ RideEnvironment, args ...rideType) (rideType, error) { +func sha256_128(_ Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "sha256_128") diff --git a/pkg/ride/functions_int.go b/pkg/ride/functions_int.go index 77e5ad921..c7e887207 100644 --- a/pkg/ride/functions_int.go +++ b/pkg/ride/functions_int.go @@ -2,6 +2,7 @@ package ride import ( "encoding/binary" + "math/big" "strconv" "github.com/ericlagergren/decimal" @@ -62,7 +63,7 @@ func intArgs(args []rideType, count int) ([]rideInt, error) { return r, nil } -func ge(_ RideEnvironment, args ...rideType) (rideType, error) { +func ge(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "ge") @@ -70,7 +71,7 @@ func ge(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(l1 >= l2), nil } -func gt(_ RideEnvironment, args ...rideType) (rideType, error) { +func gt(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "gt") @@ -78,7 +79,7 @@ func gt(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(l1 > l2), nil } -func intToString(_ RideEnvironment, args ...rideType) (rideType, error) { +func intToString(_ Environment, args ...rideType) (rideType, error) { l, err := intArg(args) if err != nil { return nil, errors.Wrap(err, "intToString") @@ -86,7 +87,7 @@ func intToString(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(strconv.Itoa(int(l))), nil } -func unaryMinus(_ RideEnvironment, args ...rideType) (rideType, error) { +func unaryMinus(_ Environment, args ...rideType) (rideType, error) { l, err := intArg(args) if err != nil { return nil, errors.Wrap(err, "unaryMinus") @@ -94,7 +95,7 @@ func unaryMinus(_ RideEnvironment, args ...rideType) (rideType, error) { return -l, nil } -func sum(_ RideEnvironment, args ...rideType) (rideType, error) { +func sum(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "sum") @@ -102,7 +103,7 @@ func sum(_ RideEnvironment, args ...rideType) (rideType, error) { return l1 + l2, nil } -func sub(_ RideEnvironment, args ...rideType) (rideType, error) { +func sub(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "sub") @@ -110,7 +111,7 @@ func sub(_ RideEnvironment, args ...rideType) (rideType, error) { return l1 - l2, nil } -func mul(_ RideEnvironment, args ...rideType) (rideType, error) { +func mul(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "mul") @@ -118,7 +119,7 @@ func mul(_ RideEnvironment, args ...rideType) (rideType, error) { return l1 * l2, nil } -func div(_ RideEnvironment, args ...rideType) (rideType, error) { +func div(_ Environment, args ...rideType) (rideType, error) { l1, l2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "div") @@ -129,7 +130,7 @@ func div(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(math.FloorDiv(int64(l1), int64(l2))), nil } -func mod(_ RideEnvironment, args ...rideType) (rideType, error) { +func mod(_ Environment, args ...rideType) (rideType, error) { i1, i2, err := twoIntArgs(args) if err != nil { return nil, errors.Wrap(err, "mod") @@ -140,7 +141,7 @@ func mod(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(math.ModDivision(int64(i1), int64(i2))), nil } -func fraction(_ RideEnvironment, args ...rideType) (rideType, error) { +func fraction(_ Environment, args ...rideType) (rideType, error) { values, err := intArgs(args, 3) if err != nil { return nil, errors.Wrap(err, "fraction") @@ -152,17 +153,51 @@ func fraction(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(res), nil } -func intToBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func fractionIntRounds(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 4); err != nil { + return nil, errors.Wrap(err, "fraction") + } + value, ok := args[0].(rideInt) + if !ok { + return nil, errors.Errorf("fraction: unexpected argument type '%s'", args[0].instanceOf()) + } + v := big.NewInt(int64(value)) + numerator, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("fraction: unexpected argument type '%s'", args[1].instanceOf()) + } + n := big.NewInt(int64(numerator)) + denominator, ok := args[2].(rideInt) + if !ok { + return nil, errors.Errorf("fraction: unexpected argument type '%s'", args[2].instanceOf()) + } + d := big.NewInt(int64(denominator)) + round, err := roundingMode(args[3]) + if err != nil { + return nil, errors.Wrap(err, "fraction") + } + r, err := fractionBigIntLikeInScala(v, n, d, round) + if err != nil { + return nil, errors.Wrap(err, "fraction") + } + if !r.IsInt64() { + return nil, errors.New("fraction: result is out of int64 range") + } + return rideInt(r.Int64()), nil +} + +func intToBytes(_ Environment, args ...rideType) (rideType, error) { i, err := intArg(args) if err != nil { return nil, errors.Wrap(err, "intToBytes") } + out := make([]byte, 8) binary.BigEndian.PutUint64(out, uint64(i)) return rideBytes(out), nil } -func pow(_ RideEnvironment, args ...rideType) (rideType, error) { +func pow(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 6); err != nil { return nil, errors.Wrap(err, "pow") } @@ -197,7 +232,7 @@ func pow(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(r), nil } -func log(_ RideEnvironment, args ...rideType) (rideType, error) { +func log(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 6); err != nil { return nil, errors.Wrap(err, "log") } @@ -242,11 +277,11 @@ func roundingMode(v rideType) (decimal.RoundingMode, error) { return decimal.ToNearestEven, nil case "Down": return decimal.ToZero, nil - case "Up": + case "Up": // round-up v2-v4 return decimal.AwayFromZero, nil case "HalfUp": return decimal.ToNearestAway, nil - case "HalfDown": + case "HalfDown": // round-half-down v2-v4 return decimal.ToNearestTowardZero, nil default: return 0, errors.Errorf("unable to get rounding mode from '%s'", v.instanceOf()) diff --git a/pkg/ride/functions_int_test.go b/pkg/ride/functions_int_test.go index 7770f6385..27c350f78 100644 --- a/pkg/ride/functions_int_test.go +++ b/pkg/ride/functions_int_test.go @@ -248,8 +248,14 @@ func TestFraction(t *testing.T) { }{ {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(6)}, false, rideInt(6148914691236517204)}, {[]rideType{rideInt(8), rideInt(4), rideInt(2)}, false, rideInt(16)}, + {[]rideType{rideInt(math.MaxInt64), rideInt(math.MinInt64), rideInt(math.MinInt64)}, false, rideInt(math.MaxInt64)}, + {[]rideType{rideInt(1), rideInt(math.MinInt64), rideInt(1)}, false, rideInt(math.MinInt64)}, + {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(1)}, true, nil}, {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(0)}, true, nil}, + {[]rideType{rideInt(1), rideInt(-1), rideInt(0)}, true, nil}, + {[]rideType{rideInt(math.MaxInt64), rideInt(math.MinInt64), rideInt(1)}, true, nil}, + {[]rideType{rideInt(2), rideInt(2)}, true, nil}, {[]rideType{rideInt(1), rideInt(2), rideUnit{}}, true, nil}, {[]rideType{rideInt(1), rideInt(2), rideString("x")}, true, nil}, @@ -266,6 +272,57 @@ func TestFraction(t *testing.T) { } } +func TestFractionIntRounds(t *testing.T) { + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(6), newDown(nil)}, false, rideInt(6148914691236517204)}, + {[]rideType{rideInt(8), rideInt(4), rideInt(2), newDown(nil)}, false, rideInt(16)}, + {[]rideType{rideInt(math.MaxInt64), rideInt(math.MinInt64), rideInt(math.MinInt64), newHalfEven(nil)}, false, rideInt(math.MaxInt64)}, + {[]rideType{rideInt(1), rideInt(math.MinInt64), rideInt(1), newHalfEven(nil)}, false, rideInt(math.MinInt64)}, + {[]rideType{rideInt(5), rideInt(1), rideInt(2), newDown(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(5), rideInt(1), rideInt(2), newHalfUp(nil)}, false, rideInt(3)}, + {[]rideType{rideInt(5), rideInt(1), rideInt(2), newHalfEven(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(5), rideInt(1), rideInt(2), newCeiling(nil)}, false, rideInt(3)}, + {[]rideType{rideInt(5), rideInt(1), rideInt(2), newFloor(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(2), rideInt(4), rideInt(5), newDown(nil)}, false, rideInt(1)}, + {[]rideType{rideInt(2), rideInt(4), rideInt(5), newHalfUp(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(2), rideInt(4), rideInt(5), newHalfEven(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(2), rideInt(4), rideInt(5), newCeiling(nil)}, false, rideInt(2)}, + {[]rideType{rideInt(2), rideInt(4), rideInt(5), newFloor(nil)}, false, rideInt(1)}, + {[]rideType{rideInt(-2), rideInt(4), rideInt(5), newDown(nil)}, false, rideInt(-1)}, + {[]rideType{rideInt(-2), rideInt(4), rideInt(5), newHalfUp(nil)}, false, rideInt(-2)}, + {[]rideType{rideInt(-2), rideInt(4), rideInt(5), newHalfEven(nil)}, false, rideInt(-2)}, + {[]rideType{rideInt(-2), rideInt(4), rideInt(5), newCeiling(nil)}, false, rideInt(-1)}, + {[]rideType{rideInt(-2), rideInt(4), rideInt(5), newFloor(nil)}, false, rideInt(-2)}, + {[]rideType{rideInt(-5), rideInt(11), rideInt(10), newDown(nil)}, false, rideInt(-5)}, + {[]rideType{rideInt(-5), rideInt(11), rideInt(10), newHalfUp(nil)}, false, rideInt(-6)}, + {[]rideType{rideInt(-5), rideInt(11), rideInt(10), newHalfEven(nil)}, false, rideInt(-6)}, + {[]rideType{rideInt(-5), rideInt(11), rideInt(10), newCeiling(nil)}, false, rideInt(-5)}, + {[]rideType{rideInt(-5), rideInt(11), rideInt(10), newFloor(nil)}, false, rideInt(-6)}, + {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(1), newDown(nil)}, true, nil}, + {[]rideType{rideInt(math.MaxInt64), rideInt(4), rideInt(0), newDown(nil)}, true, nil}, + {[]rideType{rideInt(math.MaxInt64), rideInt(math.MinInt64), rideInt(1), newHalfEven(nil)}, true, nil}, + {[]rideType{rideInt(1), rideInt(-1), rideInt(0), newHalfEven(nil)}, true, nil}, + {[]rideType{rideInt(2), rideInt(2), newDown(nil)}, true, nil}, + {[]rideType{rideInt(1), rideInt(2), rideUnit{}, newDown(nil)}, true, nil}, + {[]rideType{rideInt(1), rideInt(2), rideInt(4)}, true, nil}, + {[]rideType{rideInt(1), rideInt(2), rideString("x")}, true, nil}, + {[]rideType{rideInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + } { + r, err := fractionIntRounds(nil, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + func TestIntToBytes(t *testing.T) { for _, test := range []struct { args []rideType diff --git a/pkg/ride/functions_list.go b/pkg/ride/functions_list.go index 3dd5ded6f..8ae3097cd 100644 --- a/pkg/ride/functions_list.go +++ b/pkg/ride/functions_list.go @@ -86,7 +86,7 @@ func listAndElementArgs(args []rideType) (rideList, rideType, error) { return l, args[1], nil } -func intFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { +func intFromArray(_ Environment, args ...rideType) (rideType, error) { list, key, err := listAndStringArgs(args) if err != nil { return nil, errors.Wrap(err, "intFromArray") @@ -98,7 +98,7 @@ func intFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { return item, nil } -func booleanFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { +func booleanFromArray(_ Environment, args ...rideType) (rideType, error) { list, key, err := listAndStringArgs(args) if err != nil { return nil, errors.Wrap(err, "booleanFromArray") @@ -110,7 +110,7 @@ func booleanFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { return item, nil } -func bytesFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { +func bytesFromArray(_ Environment, args ...rideType) (rideType, error) { list, key, err := listAndStringArgs(args) if err != nil { return nil, errors.Wrap(err, "bytesFromArray") @@ -122,7 +122,7 @@ func bytesFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { return item, nil } -func stringFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { +func stringFromArray(_ Environment, args ...rideType) (rideType, error) { list, key, err := listAndStringArgs(args) if err != nil { return nil, errors.Wrap(err, "stringFromArray") @@ -134,7 +134,7 @@ func stringFromArray(_ RideEnvironment, args ...rideType) (rideType, error) { return item, nil } -func intFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error) { +func intFromArrayByIndex(_ Environment, args ...rideType) (rideType, error) { list, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "intFromArrayByIndex") @@ -154,7 +154,7 @@ func intFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error) } } -func booleanFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error) { +func booleanFromArrayByIndex(_ Environment, args ...rideType) (rideType, error) { list, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "booleanFromArrayByIndex") @@ -174,7 +174,7 @@ func booleanFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, err } } -func bytesFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error) { +func bytesFromArrayByIndex(_ Environment, args ...rideType) (rideType, error) { list, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "bytesFromArrayByIndex") @@ -194,7 +194,7 @@ func bytesFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error } } -func stringFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, error) { +func stringFromArrayByIndex(_ Environment, args ...rideType) (rideType, error) { list, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "stringFromArrayByIndex") @@ -214,7 +214,7 @@ func stringFromArrayByIndex(_ RideEnvironment, args ...rideType) (rideType, erro } } -func sizeList(_ RideEnvironment, args ...rideType) (rideType, error) { +func sizeList(_ Environment, args ...rideType) (rideType, error) { l, err := listArg(args) if err != nil { return nil, errors.Wrap(err, "sizeList") @@ -222,7 +222,7 @@ func sizeList(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(len(l)), nil } -func getList(_ RideEnvironment, args ...rideType) (rideType, error) { +func getList(_ Environment, args ...rideType) (rideType, error) { l, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "getList") @@ -230,7 +230,7 @@ func getList(_ RideEnvironment, args ...rideType) (rideType, error) { return l[i], nil } -func createList(_ RideEnvironment, args ...rideType) (rideType, error) { +func createList(_ Environment, args ...rideType) (rideType, error) { if len(args) != 2 { return nil, errors.Errorf("createList: %d is invalid number of arguments, expected %d", len(args), 2) } @@ -250,7 +250,7 @@ func createList(_ RideEnvironment, args ...rideType) (rideType, error) { return append(rideList{args[0]}, tail...), nil } -func intValueFromArray(env RideEnvironment, args ...rideType) (rideType, error) { +func intValueFromArray(env Environment, args ...rideType) (rideType, error) { v, err := intFromArray(env, args...) if err != nil { return nil, err @@ -258,7 +258,7 @@ func intValueFromArray(env RideEnvironment, args ...rideType) (rideType, error) return extractValue(v) } -func booleanValueFromArray(env RideEnvironment, args ...rideType) (rideType, error) { +func booleanValueFromArray(env Environment, args ...rideType) (rideType, error) { v, err := booleanFromArray(env, args...) if err != nil { return nil, err @@ -266,7 +266,7 @@ func booleanValueFromArray(env RideEnvironment, args ...rideType) (rideType, err return extractValue(v) } -func bytesValueFromArray(env RideEnvironment, args ...rideType) (rideType, error) { +func bytesValueFromArray(env Environment, args ...rideType) (rideType, error) { v, err := bytesFromArray(env, args...) if err != nil { return nil, err @@ -274,7 +274,7 @@ func bytesValueFromArray(env RideEnvironment, args ...rideType) (rideType, error return extractValue(v) } -func stringValueFromArray(env RideEnvironment, args ...rideType) (rideType, error) { +func stringValueFromArray(env Environment, args ...rideType) (rideType, error) { v, err := stringFromArray(env, args...) if err != nil { return nil, err @@ -282,7 +282,7 @@ func stringValueFromArray(env RideEnvironment, args ...rideType) (rideType, erro return extractValue(v) } -func intValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType, error) { +func intValueFromArrayByIndex(env Environment, args ...rideType) (rideType, error) { v, err := intFromArrayByIndex(env, args...) if err != nil { return nil, err @@ -290,7 +290,7 @@ func intValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType, return extractValue(v) } -func booleanValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType, error) { +func booleanValueFromArrayByIndex(env Environment, args ...rideType) (rideType, error) { v, err := booleanFromArrayByIndex(env, args...) if err != nil { return nil, err @@ -298,7 +298,7 @@ func booleanValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideTy return extractValue(v) } -func bytesValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType, error) { +func bytesValueFromArrayByIndex(env Environment, args ...rideType) (rideType, error) { v, err := bytesFromArrayByIndex(env, args...) if err != nil { return nil, err @@ -306,7 +306,7 @@ func bytesValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType return extractValue(v) } -func stringValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideType, error) { +func stringValueFromArrayByIndex(env Environment, args ...rideType) (rideType, error) { v, err := stringFromArrayByIndex(env, args...) if err != nil { return nil, err @@ -314,7 +314,7 @@ func stringValueFromArrayByIndex(env RideEnvironment, args ...rideType) (rideTyp return extractValue(v) } -func limitedCreateList(_ RideEnvironment, args ...rideType) (rideType, error) { +func limitedCreateList(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "limitedCreateList") } @@ -331,7 +331,7 @@ func limitedCreateList(_ RideEnvironment, args ...rideType) (rideType, error) { return append(rideList{args[0]}, tail...), nil } -func appendToList(_ RideEnvironment, args ...rideType) (rideType, error) { +func appendToList(_ Environment, args ...rideType) (rideType, error) { list, e, err := listAndElementArgs(args) if err != nil { return nil, errors.Wrap(err, "appendToList") @@ -345,7 +345,7 @@ func appendToList(_ RideEnvironment, args ...rideType) (rideType, error) { return append(list, e), nil } -func concatList(_ RideEnvironment, args ...rideType) (rideType, error) { +func concatList(_ Environment, args ...rideType) (rideType, error) { list1, e, err := listAndElementArgs(args) if err != nil { return nil, errors.Wrap(err, "concatList") @@ -365,7 +365,7 @@ func concatList(_ RideEnvironment, args ...rideType) (rideType, error) { return r, nil } -func indexOfList(_ RideEnvironment, args ...rideType) (rideType, error) { +func indexOfList(_ Environment, args ...rideType) (rideType, error) { list, e, err := listAndElementArgs(args) if err != nil { return nil, errors.Wrap(err, "indexOfList") @@ -381,7 +381,7 @@ func indexOfList(_ RideEnvironment, args ...rideType) (rideType, error) { return rideUnit{}, nil // not found returns Unit } -func lastIndexOfList(_ RideEnvironment, args ...rideType) (rideType, error) { +func lastIndexOfList(_ Environment, args ...rideType) (rideType, error) { list, e, err := listAndElementArgs(args) if err != nil { return nil, errors.Wrap(err, "lastIndexOfList") @@ -397,7 +397,7 @@ func lastIndexOfList(_ RideEnvironment, args ...rideType) (rideType, error) { return rideUnit{}, nil // not found returns Unit } -func median(_ RideEnvironment, args ...rideType) (rideType, error) { +func median(_ Environment, args ...rideType) (rideType, error) { list, err := listArg(args) if err != nil { return nil, errors.Wrap(err, "median") @@ -419,7 +419,7 @@ func median(_ RideEnvironment, args ...rideType) (rideType, error) { } } -func max(_ RideEnvironment, args ...rideType) (rideType, error) { +func max(_ Environment, args ...rideType) (rideType, error) { list, err := listArg(args) if err != nil { return nil, errors.Wrap(err, "max") @@ -436,7 +436,7 @@ func max(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(max), nil } -func min(_ RideEnvironment, args ...rideType) (rideType, error) { +func min(_ Environment, args ...rideType) (rideType, error) { list, err := listArg(args) if err != nil { return nil, errors.Wrap(err, "min") @@ -453,7 +453,7 @@ func min(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(min), nil } -func containsElement(_ RideEnvironment, args ...rideType) (rideType, error) { +func containsElement(_ Environment, args ...rideType) (rideType, error) { list, e, err := listAndElementArgs(args) if err != nil { return nil, errors.Wrap(err, "containsElement") @@ -466,7 +466,7 @@ func containsElement(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(false), nil } -func listRemoveByIndex(_ RideEnvironment, args ...rideType) (rideType, error) { +func listRemoveByIndex(_ Environment, args ...rideType) (rideType, error) { list, i, err := listAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "listRemoveByIndex") diff --git a/pkg/ride/functions_proto.go b/pkg/ride/functions_proto.go index afe11de5a..e5a87448f 100644 --- a/pkg/ride/functions_proto.go +++ b/pkg/ride/functions_proto.go @@ -7,6 +7,8 @@ import ( sh256 "crypto/sha256" "crypto/x509" + "github.com/wavesplatform/gowaves/pkg/util/common" + "github.com/mr-tron/base58" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" @@ -14,7 +16,380 @@ import ( c2 "github.com/wavesplatform/gowaves/pkg/ride/crypto" ) -func addressFromString(env RideEnvironment, args ...rideType) (rideType, error) { +func isAddressInBL(dAppAddress proto.Address, blackList []proto.Address) bool { + for _, v := range blackList { + if v == dAppAddress { + return true + } + } + return false +} + +func reentrantInvoke(env Environment, args ...rideType) (rideType, error) { + ws, ok := env.state().(*WrappedState) + if !ok { + return nil, errors.Wrapf(errors.New("wrong state"), "invoke") + } + ws.incrementInvCount() + if ws.invCount() > 100 { + return rideUnit{}, nil + } + + callerAddress, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, errors.Errorf("invoke: this has an unexpected type '%s'", env.this().instanceOf()) + } + + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[0].instanceOf()) + } + + if recipient.Address == nil { + if recipient.Alias == nil { + return nil, errors.New("invoke: address and alias are nil") + } + addressFromAlias, err := env.state().NewestAddrByAlias(*recipient.Alias) + if err != nil { + return nil, errors.Errorf("invoke: failed to get address by alias, %v", err) + } + recipient = proto.NewRecipientFromAddress(addressFromAlias) + } + + var fnName rideString + switch fnN := args[1].(type) { + case rideUnit: + fnName = "default" + case rideString: + if fnN == "" { + fnName = "default" + break + } + fnName = fnN + default: + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[1].instanceOf()) + } + + listArg, ok := args[2].(rideList) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[2].instanceOf()) + } + + var attachedPayments proto.ScriptPayments + payments := args[3].(rideList) + + oldInvocationParam := env.invocation() + + invocationParam := make(rideObject) + for key, value := range oldInvocationParam { + invocationParam[key] = value + } + + invocationParam["caller"] = callerAddress + callerPublicKey, err := env.state().NewestScriptPKByAddr(proto.Address(callerAddress)) + if err != nil { + return nil, errors.Wrapf(err, "failed to get caller public key by address") + } + invocationParam["callerPublicKey"] = rideBytes(common.Dup(callerPublicKey.Bytes())) + invocationParam["payments"] = payments + env.setInvocation(invocationParam) + + for _, value := range payments { + payment, ok := value.(rideObject) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", payment.instanceOf()) + } + + assetID, err := payment.get("assetId") + if err != nil { + return nil, errors.Wrap(err, "invoke") + } + amount, err := payment.get("amount") + if err != nil { + return nil, errors.Wrap(err, "invoke") + } + + intAmount, ok := amount.(rideInt) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", amount.instanceOf()) + } + var asset *proto.OptionalAsset + + switch asID := assetID.(type) { + case rideBytes: + asset, err = proto.NewOptionalAssetFromBytes(asID) + if err != nil { + return nil, errors.Errorf("invoke: failed to get optional asset from ride bytes") + } + case rideUnit: + waves := proto.NewOptionalAssetWaves() + asset = &waves + default: + return nil, errors.Errorf("attachedPayment: unexpected argument type '%s'", args[0].instanceOf()) + } + + attachedPayments = append(attachedPayments, proto.ScriptPayment{Asset: *asset, Amount: uint64(intAmount)}) + } + // since RideV5 the limit of attached payments is 10 + if len(attachedPayments) > 10 { + return nil, errors.New("invoke: no more than ten payments is allowed since RideV5 activation") + } + + var paymentActions []proto.ScriptAction + for _, payment := range attachedPayments { + action := &proto.TransferScriptAction{Sender: &callerPublicKey, Recipient: recipient, Amount: int64(payment.Amount), Asset: payment.Asset} + paymentActions = append(paymentActions, action) + } + + address, err := env.state().NewestRecipientToAddress(recipient) + if err != nil { + return nil, errors.Errorf("failed to get address from dApp, invokeFunctionFromDApp") + } + env.setNewDAppAddress(*address) + err = ws.smartAppendActions(paymentActions, env) + if err != nil { + return nil, errors.Wrapf(err, "failed to apply attachedPayments") + } + + if ws.invCount() > 1 { + if isAddressInBL(*recipient.Address, ws.blackList) && proto.Address(callerAddress) != *recipient.Address { + return rideUnit{}, errors.Errorf("function call of %s with dApp address %s is forbiden because it had already been called once by 'invoke'", fnName, recipient.Address) + } + } + + res, err := invokeFunctionFromDApp(env, recipient, fnName, listArg) + + if err != nil { + return nil, errors.Wrapf(err, "failed to get Result from invokeFunctionFromDApp") + } + + if res.Result() { + if res.UserError() != "" { + return nil, errors.Errorf(res.UserError()) + } + + err = ws.smartAppendActions(res.ScriptActions(), env) + if err != nil { + return nil, err + } + + env.setNewDAppAddress(proto.Address(callerAddress)) + env.setInvocation(oldInvocationParam) + + ws.totalComplexity += res.Complexity() + + if res.userResult() == nil { + return rideUnit{}, nil + } + return res.userResult(), nil + } + + return rideThrow("result of reentrantInvoke function is false"), nil +} + +func invoke(env Environment, args ...rideType) (rideType, error) { + ws, ok := env.state().(*WrappedState) + if !ok { + return nil, errors.Wrapf(errors.New("wrong state"), "invoke") + } + ws.incrementInvCount() + if ws.invCount() > 100 { + return rideUnit{}, nil + } + + callerAddress, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, errors.Errorf("invoke: this has an unexpected type '%s'", env.this().instanceOf()) + } + + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[0].instanceOf()) + } + + if recipient.Address == nil { + if recipient.Alias == nil { + return nil, errors.New("invoke: address and alias are nil") + } + addressFromAlias, err := env.state().NewestAddrByAlias(*recipient.Alias) + if err != nil { + return nil, errors.Errorf("invoke: failed to get address by alias, %v", err) + } + recipient = proto.NewRecipientFromAddress(addressFromAlias) + } + + var fnName rideString + switch fnN := args[1].(type) { + case rideUnit: + fnName = "default" + case rideString: + if fnN == "" { + fnName = "default" + break + } + fnName = fnN + default: + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[1].instanceOf()) + } + + listArg, ok := args[2].(rideList) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", args[2].instanceOf()) + } + + var attachedPayments proto.ScriptPayments + payments := args[3].(rideList) + + oldInvocationParam := env.invocation() + + invocationParam := make(rideObject) + for key, value := range oldInvocationParam { + invocationParam[key] = value + } + + invocationParam["caller"] = callerAddress + callerPublicKey, err := env.state().NewestScriptPKByAddr(proto.Address(callerAddress)) + if err != nil { + return nil, errors.Wrapf(err, "failed to get caller public key by address") + } + invocationParam["callerPublicKey"] = rideBytes(common.Dup(callerPublicKey.Bytes())) + invocationParam["payments"] = payments + env.setInvocation(invocationParam) + + for _, value := range payments { + payment, ok := value.(rideObject) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", payment.instanceOf()) + } + + assetID, err := payment.get("assetId") + if err != nil { + return nil, errors.Wrap(err, "invoke") + } + amount, err := payment.get("amount") + if err != nil { + return nil, errors.Wrap(err, "invoke") + } + + intAmount, ok := amount.(rideInt) + if !ok { + return nil, errors.Errorf("invoke: unexpected argument type '%s'", amount.instanceOf()) + } + var asset *proto.OptionalAsset + + switch asID := assetID.(type) { + case rideBytes: + asset, err = proto.NewOptionalAssetFromBytes(asID) + if err != nil { + return nil, errors.Errorf("invoke: failed to get optional asset from ride bytes") + } + case rideUnit: + waves := proto.NewOptionalAssetWaves() + asset = &waves + default: + return nil, errors.Errorf("attachedPayment: unexpected argument type '%s'", args[0].instanceOf()) + } + + attachedPayments = append(attachedPayments, proto.ScriptPayment{Asset: *asset, Amount: uint64(intAmount)}) + } + + // since RideV5 the limit of attached payments is 10 + if len(attachedPayments) > 10 { + return nil, errors.New("invoke: no more than ten payments is allowed since RideV5 activation") + } + + var paymentActions []proto.ScriptAction + for _, payment := range attachedPayments { + action := &proto.TransferScriptAction{Sender: &callerPublicKey, Recipient: recipient, Amount: int64(payment.Amount), Asset: payment.Asset} + paymentActions = append(paymentActions, action) + } + + address, err := env.state().NewestRecipientToAddress(recipient) + if err != nil { + return nil, errors.Errorf("failed get address from dApp, invokeFunctionFromDApp") + } + env.setNewDAppAddress(*address) + err = ws.smartAppendActions(paymentActions, env) + if err != nil { + return nil, errors.Wrapf(err, "failed to apply attachedPayments") + } + + // append a call to the stack to protect a user from the reentrancy attack + ws.blackList = append(ws.blackList, proto.Address(callerAddress)) // push + + if ws.invCount() > 1 { + if isAddressInBL(*recipient.Address, ws.blackList) && proto.Address(callerAddress) != *recipient.Address { + return rideUnit{}, errors.Errorf("function call of %s with dApp address %s is forbiden because it had already been called once by 'invoke'", fnName, recipient.Address) + } + } + + res, err := invokeFunctionFromDApp(env, recipient, fnName, listArg) + + ws.blackList = ws.blackList[:len(ws.blackList)-1] // pop + + if err != nil { + return nil, errors.Wrapf(err, "failed to get Result from invokeFunctionFromDApp") + } + + if res.Result() { + if res.UserError() != "" { + return nil, errors.Errorf(res.UserError()) + } + + err = ws.smartAppendActions(res.ScriptActions(), env) + if err != nil { + return nil, err + } + + env.setNewDAppAddress(proto.Address(callerAddress)) + env.setInvocation(oldInvocationParam) + + ws.totalComplexity += res.Complexity() + + if res.userResult() == nil { + return rideUnit{}, nil + } + return res.userResult(), nil + } + + return rideThrow("result of invoke function is false"), nil +} + +func hashScriptAtAddress(env Environment, args ...rideType) (rideType, error) { + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Errorf("hashScriptAtAddress: unexpected argument type '%s'", args[0].instanceOf()) + } + + script, err := env.state().GetByteTree(recipient) + if err != nil { + return nil, errors.Errorf("hashScriptAtAddress: failed to get script by recipient, %v", err) + } + + if len(script) != 0 { + hash, err := crypto.FastHash(script) + if err != nil { + return nil, errors.Errorf("hashScriptAtAddress: failed to get hash of script, %v", err) + } + return rideBytes(hash.Bytes()), nil + } + + return rideUnit{}, nil +} + +func isDataStorageUntouched(env Environment, args ...rideType) (rideType, error) { + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Errorf("isDataStorageUntouched: unexpected argument type '%s'", args[0].instanceOf()) + } + isUntouched, err := env.state().IsStateUntouched(recipient) + if err != nil { + return nil, errors.Wrapf(err, "isDataStorageUntouched") + } + return rideBoolean(isUntouched), nil +} + +func addressFromString(env Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "addressFromString") @@ -29,7 +404,7 @@ func addressFromString(env RideEnvironment, args ...rideType) (rideType, error) return rideAddress(a), nil } -func addressValueFromString(env RideEnvironment, args ...rideType) (rideType, error) { +func addressValueFromString(env Environment, args ...rideType) (rideType, error) { r, err := addressFromString(env, args...) if err != nil { return nil, errors.Wrap(err, "addressValueFromString") @@ -40,7 +415,7 @@ func addressValueFromString(env RideEnvironment, args ...rideType) (rideType, er return r, nil } -func transactionByID(env RideEnvironment, args ...rideType) (rideType, error) { +func transactionByID(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "transactionByID") @@ -59,7 +434,7 @@ func transactionByID(env RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func transactionHeightByID(env RideEnvironment, args ...rideType) (rideType, error) { +func transactionHeightByID(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "transactionHeightByID") @@ -74,7 +449,7 @@ func transactionHeightByID(env RideEnvironment, args ...rideType) (rideType, err return rideInt(h), nil } -func assetBalanceV3(env RideEnvironment, args ...rideType) (rideType, error) { +func assetBalanceV3(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "assetBalanceV3") } @@ -93,7 +468,7 @@ func assetBalanceV3(env RideEnvironment, args ...rideType) (rideType, error) { return rideInt(balance), nil } -func assetBalanceV4(env RideEnvironment, args ...rideType) (rideType, error) { +func assetBalanceV4(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "assetBalanceV4") } @@ -115,7 +490,7 @@ func assetBalanceV4(env RideEnvironment, args ...rideType) (rideType, error) { return rideInt(balance), nil } -func intFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func intFromState(env Environment, args ...rideType) (rideType, error) { r, k, err := extractRecipientAndKey(args) if err != nil { return rideUnit{}, nil @@ -127,7 +502,24 @@ func intFromState(env RideEnvironment, args ...rideType) (rideType, error) { return rideInt(entry.Value), nil } -func bytesFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func intFromSelfState(env Environment, args ...rideType) (rideType, error) { + k, err := extractKey(args) + if err != nil { + return rideUnit{}, nil + } + a, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, nil + } + r := proto.NewRecipientFromAddress(proto.Address(a)) + entry, err := env.state().RetrieveNewestIntegerEntry(r, k) + if err != nil { + return rideUnit{}, nil + } + return rideInt(entry.Value), nil +} + +func bytesFromState(env Environment, args ...rideType) (rideType, error) { r, k, err := extractRecipientAndKey(args) if err != nil { return rideUnit{}, nil @@ -139,7 +531,24 @@ func bytesFromState(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(entry.Value), nil } -func stringFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func bytesFromSelfState(env Environment, args ...rideType) (rideType, error) { + k, err := extractKey(args) + if err != nil { + return rideUnit{}, nil + } + a, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, nil + } + r := proto.NewRecipientFromAddress(proto.Address(a)) + entry, err := env.state().RetrieveNewestBinaryEntry(r, k) + if err != nil { + return rideUnit{}, nil + } + return rideBytes(entry.Value), nil +} + +func stringFromState(env Environment, args ...rideType) (rideType, error) { r, k, err := extractRecipientAndKey(args) if err != nil { return rideUnit{}, nil @@ -151,7 +560,24 @@ func stringFromState(env RideEnvironment, args ...rideType) (rideType, error) { return rideString(entry.Value), nil } -func booleanFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func stringFromSelfState(env Environment, args ...rideType) (rideType, error) { + k, err := extractKey(args) + if err != nil { + return rideUnit{}, nil + } + a, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, nil + } + r := proto.NewRecipientFromAddress(proto.Address(a)) + entry, err := env.state().RetrieveNewestStringEntry(r, k) + if err != nil { + return rideUnit{}, nil + } + return rideString(entry.Value), nil +} + +func booleanFromState(env Environment, args ...rideType) (rideType, error) { r, k, err := extractRecipientAndKey(args) if err != nil { return rideUnit{}, nil @@ -163,7 +589,24 @@ func booleanFromState(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(entry.Value), nil } -func addressFromRecipient(env RideEnvironment, args ...rideType) (rideType, error) { +func booleanFromSelfState(env Environment, args ...rideType) (rideType, error) { + k, err := extractKey(args) + if err != nil { + return rideUnit{}, nil + } + a, ok := env.this().(rideAddress) + if !ok { + return rideUnit{}, nil + } + r := proto.NewRecipientFromAddress(proto.Address(a)) + entry, err := env.state().RetrieveNewestBooleanEntry(r, k) + if err != nil { + return rideUnit{}, nil + } + return rideBoolean(entry.Value), nil +} + +func addressFromRecipient(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "addressFromRecipient") } @@ -187,7 +630,7 @@ func addressFromRecipient(env RideEnvironment, args ...rideType) (rideType, erro } } -func sigVerify(env RideEnvironment, args ...rideType) (rideType, error) { +func sigVerify(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "sigVerify") } @@ -195,7 +638,7 @@ func sigVerify(env RideEnvironment, args ...rideType) (rideType, error) { if !ok { return nil, errors.Errorf("sigVerify: unexpected argument type '%s'", args[0].instanceOf()) } - if l := len(message); env != nil && !env.checkMessageLength(l) { + if l := len(message); env != nil && env.libVersion() == 3 && !env.checkMessageLength(l) { return nil, errors.Errorf("sigVerify: invalid message size %d", l) } signature, ok := args[1].(rideBytes) @@ -218,7 +661,7 @@ func sigVerify(env RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func keccak256(env RideEnvironment, args ...rideType) (rideType, error) { +func keccak256(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "keccak256") @@ -233,7 +676,7 @@ func keccak256(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func blake2b256(env RideEnvironment, args ...rideType) (rideType, error) { +func blake2b256(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "blake2b256") @@ -248,7 +691,7 @@ func blake2b256(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d.Bytes()), nil } -func sha256(env RideEnvironment, args ...rideType) (rideType, error) { +func sha256(env Environment, args ...rideType) (rideType, error) { data, err := bytesOrStringArg(args) if err != nil { return nil, errors.Wrap(err, "sha256") @@ -264,7 +707,7 @@ func sha256(env RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(d), nil } -func addressFromPublicKey(env RideEnvironment, args ...rideType) (rideType, error) { +func addressFromPublicKey(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "addressFromPublicKey") @@ -276,7 +719,7 @@ func addressFromPublicKey(env RideEnvironment, args ...rideType) (rideType, erro return rideAddress(addr), nil } -func wavesBalanceV3(env RideEnvironment, args ...rideType) (rideType, error) { +func wavesBalanceV3(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "wavesBalanceV3") } @@ -291,7 +734,7 @@ func wavesBalanceV3(env RideEnvironment, args ...rideType) (rideType, error) { return rideInt(balance), nil } -func wavesBalanceV4(env RideEnvironment, args ...rideType) (rideType, error) { +func wavesBalanceV4(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "wavesBalanceV4") } @@ -306,7 +749,7 @@ func wavesBalanceV4(env RideEnvironment, args ...rideType) (rideType, error) { return balanceDetailsToObject(balance), nil } -func assetInfoV3(env RideEnvironment, args ...rideType) (rideType, error) { +func assetInfoV3(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "assetInfoV3") @@ -322,7 +765,7 @@ func assetInfoV3(env RideEnvironment, args ...rideType) (rideType, error) { return assetInfoToObject(info), nil } -func assetInfoV4(env RideEnvironment, args ...rideType) (rideType, error) { +func assetInfoV4(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "assetInfoV4") @@ -338,7 +781,7 @@ func assetInfoV4(env RideEnvironment, args ...rideType) (rideType, error) { return fullAssetInfoToObject(info), nil } -func blockInfoByHeight(env RideEnvironment, args ...rideType) (rideType, error) { +func blockInfoByHeight(env Environment, args ...rideType) (rideType, error) { i, err := intArg(args) if err != nil { return nil, errors.Wrap(err, "blockInfoByHeight") @@ -359,7 +802,7 @@ func blockInfoByHeight(env RideEnvironment, args ...rideType) (rideType, error) return obj, nil } -func transferByID(env RideEnvironment, args ...rideType) (rideType, error) { +func transferByID(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "transferByID") @@ -378,7 +821,7 @@ func transferByID(env RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func addressToString(_ RideEnvironment, args ...rideType) (rideType, error) { +func addressToString(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "addressToString") } @@ -397,7 +840,7 @@ func addressToString(_ RideEnvironment, args ...rideType) (rideType, error) { } } -func rsaVerify(_ RideEnvironment, args ...rideType) (rideType, error) { +func rsaVerify(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 4); err != nil { return nil, errors.Wrap(err, "rsaVerify") } @@ -409,6 +852,9 @@ func rsaVerify(_ RideEnvironment, args ...rideType) (rideType, error) { if !ok { return nil, errors.Errorf("rsaVerify: unexpected argument type '%s'", args[1].instanceOf()) } + if l := len(message); env != nil && env.libVersion() == 3 && !env.checkMessageLength(l) { + return nil, errors.Errorf("sigVerify: invalid message size %d", l) + } sig, ok := args[2].(rideBytes) if !ok { return nil, errors.Errorf("rsaVerify: unexpected argument type '%s'", args[2].instanceOf()) @@ -438,7 +884,7 @@ func rsaVerify(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(ok), nil } -func checkMerkleProof(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkMerkleProof(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "checkMerkleProof") } @@ -461,7 +907,7 @@ func checkMerkleProof(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBoolean(bytes.Equal(root, r)), nil } -func intValueFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func intValueFromState(env Environment, args ...rideType) (rideType, error) { v, err := intFromState(env, args...) if err != nil { return nil, err @@ -469,7 +915,15 @@ func intValueFromState(env RideEnvironment, args ...rideType) (rideType, error) return extractValue(v) } -func booleanValueFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func intValueFromSelfState(env Environment, args ...rideType) (rideType, error) { + v, err := intFromSelfState(env, args...) + if err != nil { + return nil, err + } + return extractValue(v) +} + +func booleanValueFromState(env Environment, args ...rideType) (rideType, error) { v, err := booleanFromState(env, args...) if err != nil { return nil, err @@ -477,7 +931,15 @@ func booleanValueFromState(env RideEnvironment, args ...rideType) (rideType, err return extractValue(v) } -func bytesValueFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func booleanValueFromSelfState(env Environment, args ...rideType) (rideType, error) { + v, err := booleanFromSelfState(env, args...) + if err != nil { + return nil, err + } + return extractValue(v) +} + +func bytesValueFromState(env Environment, args ...rideType) (rideType, error) { v, err := bytesFromState(env, args...) if err != nil { return nil, err @@ -485,7 +947,15 @@ func bytesValueFromState(env RideEnvironment, args ...rideType) (rideType, error return extractValue(v) } -func stringValueFromState(env RideEnvironment, args ...rideType) (rideType, error) { +func bytesValueFromSelfState(env Environment, args ...rideType) (rideType, error) { + v, err := bytesFromSelfState(env, args...) + if err != nil { + return nil, err + } + return extractValue(v) +} + +func stringValueFromState(env Environment, args ...rideType) (rideType, error) { v, err := stringFromState(env, args...) if err != nil { return nil, err @@ -493,7 +963,15 @@ func stringValueFromState(env RideEnvironment, args ...rideType) (rideType, erro return extractValue(v) } -func transferFromProtobuf(env RideEnvironment, args ...rideType) (rideType, error) { +func stringValueFromSelfState(env Environment, args ...rideType) (rideType, error) { + v, err := stringFromSelfState(env, args...) + if err != nil { + return nil, err + } + return extractValue(v) +} + +func transferFromProtobuf(env Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "transferFromProtobuf") @@ -515,7 +993,7 @@ func transferFromProtobuf(env RideEnvironment, args ...rideType) (rideType, erro return obj, nil } -func calcAssetID(env RideEnvironment, name, description rideString, decimals, quantity rideInt, reissuable rideBoolean, nonce rideInt) (rideBytes, error) { +func calcAssetID(env Environment, name, description rideString, decimals, quantity rideInt, reissuable rideBoolean, nonce rideInt) (rideBytes, error) { pid, ok := env.txID().(rideBytes) if !ok { return nil, errors.New("calculateAssetID: no parent transaction ID found") @@ -528,7 +1006,7 @@ func calcAssetID(env RideEnvironment, name, description rideString, decimals, qu return id.Bytes(), nil } -func calculateAssetID(env RideEnvironment, args ...rideType) (rideType, error) { +func calculateAssetID(env Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "calculateAssetID") } @@ -566,56 +1044,56 @@ func calculateAssetID(env RideEnvironment, args ...rideType) (rideType, error) { return calcAssetID(env, name, description, decimals, quantity, reissuable, nonce) } -func simplifiedIssue(_ RideEnvironment, args ...rideType) (rideType, error) { +func simplifiedIssue(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 5); err != nil { return nil, errors.Wrap(err, "simplifiedIssue") } name, ok := args[0].(rideString) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[0].instanceOf()) + return nil, errors.Errorf("simplifiedIssue: unexpected argument type '%s'", args[0].instanceOf()) } description, ok := args[1].(rideString) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[1].instanceOf()) + return nil, errors.Errorf("simplifiedIssue: unexpected argument type '%s'", args[1].instanceOf()) } quantity, ok := args[2].(rideInt) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[2].instanceOf()) + return nil, errors.Errorf("simplifiedIssue: unexpected argument type '%s'", args[2].instanceOf()) } decimals, ok := args[3].(rideInt) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[3].instanceOf()) + return nil, errors.Errorf("simplifiedIssue: unexpected argument type '%s'", args[3].instanceOf()) } reissuable, ok := args[4].(rideBoolean) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[4].instanceOf()) + return nil, errors.Errorf("simplifiedIssue: unexpected argument type '%s'", args[4].instanceOf()) } return newIssue(name, description, quantity, decimals, reissuable, rideUnit{}, 0), nil } -func fullIssue(_ RideEnvironment, args ...rideType) (rideType, error) { +func fullIssue(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 7); err != nil { - return nil, errors.Wrap(err, "simplifiedIssue") + return nil, errors.Wrap(err, "fullIssue") } name, ok := args[0].(rideString) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[0].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[0].instanceOf()) } description, ok := args[1].(rideString) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[1].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[1].instanceOf()) } quantity, ok := args[2].(rideInt) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[2].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[2].instanceOf()) } decimals, ok := args[3].(rideInt) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[3].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[3].instanceOf()) } reissuable, ok := args[4].(rideBoolean) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[4].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[4].instanceOf()) } var script rideType switch s := args[5].(type) { @@ -624,16 +1102,16 @@ func fullIssue(_ RideEnvironment, args ...rideType) (rideType, error) { case rideUnit: script = s default: - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[5].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[5].instanceOf()) } nonce, ok := args[6].(rideInt) if !ok { - return nil, errors.Errorf("calculateAssetID: unexpected argument type '%s'", args[6].instanceOf()) + return nil, errors.Errorf("fullIssue: unexpected argument type '%s'", args[6].instanceOf()) } return newIssue(name, description, quantity, decimals, reissuable, script, nonce), nil } -func rebuildMerkleRoot(_ RideEnvironment, args ...rideType) (rideType, error) { +func rebuildMerkleRoot(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "rebuildMerkleRoot") } @@ -677,17 +1155,53 @@ func rebuildMerkleRoot(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(root[:]), nil } -func bls12Groth16Verify(_ RideEnvironment, _ ...rideType) (rideType, error) { - //TODO: implement - return rideBoolean(true), nil +func bls12Groth16Verify(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 3); err != nil { + return nil, errors.Wrap(err, "bls12Groth16Verify") + } + key, ok := args[0].(rideBytes) + if !ok { + return nil, errors.Errorf("bls12Groth16Verify: unexpected argument type '%s'", args[0].instanceOf()) + } + proof, ok := args[1].(rideBytes) + if !ok { + return nil, errors.Errorf("bls12Groth16Verify: unexpected argument type '%s'", args[1].instanceOf()) + } + inputs, ok := args[2].(rideBytes) + if !ok { + return nil, errors.Errorf("bls12Groth16Verify: unexpected argument type '%s'", args[2].instanceOf()) + } + ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs) + if err != nil { + return nil, errors.Wrap(err, "bls12Groth16Verify") + } + return rideBoolean(ok), nil } -func bn256Groth16Verify(_ RideEnvironment, _ ...rideType) (rideType, error) { - //TODO: implement - return rideBoolean(true), nil +func bn256Groth16Verify(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 3); err != nil { + return nil, errors.Wrap(err, "bn256Groth16Verify") + } + key, ok := args[0].(rideBytes) + if !ok { + return nil, errors.Errorf("bn256Groth16Verify: unexpected argument type '%s'", args[0].instanceOf()) + } + proof, ok := args[1].(rideBytes) + if !ok { + return nil, errors.Errorf("bn256Groth16Verify: unexpected argument type '%s'", args[1].instanceOf()) + } + inputs, ok := args[2].(rideBytes) + if !ok { + return nil, errors.Errorf("bn256Groth16Verify: unexpected argument type '%s'", args[2].instanceOf()) + } + ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs) + if err != nil { + return nil, errors.Wrap(err, "bn256Groth16Verify") + } + return rideBoolean(ok), nil } -func ecRecover(_ RideEnvironment, args ...rideType) (rideType, error) { +func ecRecover(_ Environment, args ...rideType) (rideType, error) { digest, signature, err := bytesArgs2(args) if err != nil { return nil, errors.Wrap(err, "ecRecover") @@ -707,7 +1221,7 @@ func ecRecover(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(pkb[1:]), nil } -func checkedBytesDataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkedBytesDataEntry(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "checkedBytesDataEntry") } @@ -722,7 +1236,7 @@ func checkedBytesDataEntry(_ RideEnvironment, args ...rideType) (rideType, error return newDataEntry("BinaryEntry", key, value), nil } -func checkedBooleanDataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkedBooleanDataEntry(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "checkedBooleanDataEntry") } @@ -737,7 +1251,7 @@ func checkedBooleanDataEntry(_ RideEnvironment, args ...rideType) (rideType, err return newDataEntry("BooleanEntry", key, value), nil } -func checkedDeleteEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkedDeleteEntry(_ Environment, args ...rideType) (rideType, error) { key, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "checkedDeleteEntry") @@ -745,7 +1259,7 @@ func checkedDeleteEntry(_ RideEnvironment, args ...rideType) (rideType, error) { return newDataEntry("DeleteEntry", key, rideUnit{}), nil } -func checkedIntDataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkedIntDataEntry(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "checkedIntDataEntry") } @@ -760,7 +1274,7 @@ func checkedIntDataEntry(_ RideEnvironment, args ...rideType) (rideType, error) return newDataEntry("IntegerEntry", key, value), nil } -func checkedStringDataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func checkedStringDataEntry(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "checkedStringDataEntry") } @@ -777,7 +1291,7 @@ func checkedStringDataEntry(_ RideEnvironment, args ...rideType) (rideType, erro // Constructors -func address(_ RideEnvironment, args ...rideType) (rideType, error) { +func address(_ Environment, args ...rideType) (rideType, error) { b, err := bytesArg(args) if err != nil { return nil, errors.Wrap(err, "address") @@ -789,7 +1303,7 @@ func address(_ RideEnvironment, args ...rideType) (rideType, error) { return rideAddress(addr), nil } -func alias(env RideEnvironment, args ...rideType) (rideType, error) { +func alias(env Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "alias") @@ -798,7 +1312,7 @@ func alias(env RideEnvironment, args ...rideType) (rideType, error) { return rideAlias(*alias), nil } -func assetPair(_ RideEnvironment, args ...rideType) (rideType, error) { +func assetPair(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "assetPair") } @@ -817,7 +1331,7 @@ func assetPair(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func burn(_ RideEnvironment, args ...rideType) (rideType, error) { +func burn(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "burn") } @@ -836,7 +1350,7 @@ func burn(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func dataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { +func dataEntry(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "dataEntry") } @@ -854,7 +1368,7 @@ func dataEntry(_ RideEnvironment, args ...rideType) (rideType, error) { return newDataEntry("DataEntry", key, value), nil } -func dataTransaction(_ RideEnvironment, args ...rideType) (rideType, error) { +func dataTransaction(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 9); err != nil { return nil, errors.Wrap(err, "dataTransaction") } @@ -908,7 +1422,7 @@ func dataTransaction(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func scriptResult(_ RideEnvironment, args ...rideType) (rideType, error) { +func scriptResult(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "scriptResult") } @@ -925,7 +1439,7 @@ func scriptResult(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func writeSet(_ RideEnvironment, args ...rideType) (rideType, error) { +func writeSet(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "writeSet") } @@ -947,7 +1461,7 @@ func writeSet(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func scriptTransfer(_ RideEnvironment, args ...rideType) (rideType, error) { +func scriptTransfer(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "scriptTransfer") } @@ -974,7 +1488,7 @@ func scriptTransfer(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func transferSet(_ RideEnvironment, args ...rideType) (rideType, error) { +func transferSet(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 1); err != nil { return nil, errors.Wrap(err, "transferSet") } @@ -996,11 +1510,11 @@ func transferSet(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func unit(_ RideEnvironment, _ ...rideType) (rideType, error) { +func unit(_ Environment, _ ...rideType) (rideType, error) { return rideUnit{}, nil } -func reissue(_ RideEnvironment, args ...rideType) (rideType, error) { +func reissue(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 3); err != nil { return nil, errors.Wrap(err, "reissue") } @@ -1024,7 +1538,7 @@ func reissue(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } -func sponsorship(_ RideEnvironment, args ...rideType) (rideType, error) { +func sponsorship(_ Environment, args ...rideType) (rideType, error) { asset, fee, err := bytesAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "sponsorship") @@ -1036,6 +1550,31 @@ func sponsorship(_ RideEnvironment, args ...rideType) (rideType, error) { return obj, nil } +func attachedPayment(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 2); err != nil { + return nil, errors.Wrap(err, "attachedPayment") + } + + r := make(rideObject) + r[instanceFieldName] = rideString("AttachedPayment") + + var assetID rideType + switch assID := args[0].(type) { + case rideBytes, rideUnit: + assetID = assID + default: + return nil, errors.Errorf("attachedPayment: unexpected argument type '%s'", args[0].instanceOf()) + } + r["assetId"] = assetID + + amount, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("attachedPayment: unexpected argument type '%s'", args[1].instanceOf()) + } + r["amount"] = amount + return r, nil +} + func extractRecipient(v rideType) (proto.Recipient, error) { var r proto.Recipient switch a := v.(type) { @@ -1077,6 +1616,17 @@ func extractRecipientAndKey(args []rideType) (proto.Recipient, string, error) { return r, string(key), nil } +func extractKey(args []rideType) (string, error) { + if err := checkArgs(args, 1); err != nil { + return "", err + } + key, ok := args[0].(rideString) + if !ok { + return "", errors.Errorf("unexpected argument '%s'", args[0].instanceOf()) + } + return string(key), nil +} + func bytesOrStringArg(args []rideType) (rideBytes, error) { if len(args) != 1 { return nil, errors.Errorf("%d is invalid number of arguments, expected 1", len(args)) @@ -1152,3 +1702,102 @@ func checkAsset(v rideType) (rideType, bool) { return nil, false } } + +func calcLeaseID(env Environment, recipient proto.Recipient, amount, nonce rideInt) (rideBytes, error) { + pid, ok := env.txID().(rideBytes) + if !ok { + return nil, errors.New("calcLeaseID: no parent transaction ID found") + } + d, err := crypto.NewDigestFromBytes(pid) + if err != nil { + return nil, errors.Wrap(err, "calcLeaseID") + } + id := proto.GenerateLeaseScriptActionID(recipient, int64(amount), int64(nonce), d) + return id.Bytes(), nil +} + +func calculateLeaseID(env Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 1); err != nil { + return nil, errors.Wrap(err, "calculateLeaseID") + } + if t := args[0].instanceOf(); t != "Lease" { + return nil, errors.Errorf("calculateLeaseID: unexpected argument type '%s'", t) + } + lease, ok := args[0].(rideObject) + if !ok { + return nil, errors.New("calculateLeaseID: not an object") + } + if lease.instanceOf() != "Lease" { + return nil, errors.Errorf("calculateLeaseID: unexpected object type '%s'", lease.instanceOf()) + } + recipient, err := recipientProperty(lease, "recipient") + if err != nil { + return nil, errors.Wrap(err, "calculateLeaseID") + } + amount, err := intProperty(lease, "amount") + if err != nil { + return nil, errors.Wrap(err, "calculateLeaseID") + } + nonce, err := intProperty(lease, "nonce") + if err != nil { + return nil, errors.Wrap(err, "calculateLeaseID") + } + return calcLeaseID(env, recipient, amount, nonce) +} + +func newLease(recipient rideRecipient, amount, nonce rideInt) rideObject { + r := make(rideObject) + r[instanceFieldName] = rideString("Lease") + r["recipient"] = recipient + r["amount"] = amount + r["nonce"] = nonce + return r +} + +func simplifiedLease(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 2); err != nil { + return nil, errors.Wrap(err, "simplifiedLease") + } + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Wrap(err, "simplifiedLease") + } + amount, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("simplifiedLease: unexpected argument type '%s'", args[1].instanceOf()) + } + return newLease(rideRecipient(recipient), amount, 0), nil +} + +func fullLease(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 3); err != nil { + return nil, errors.Wrap(err, "fullLease") + } + recipient, err := extractRecipient(args[0]) + if err != nil { + return nil, errors.Wrap(err, "simplifiedLease") + } + amount, ok := args[1].(rideInt) + if !ok { + return nil, errors.Errorf("fullLease: unexpected argument type '%s'", args[1].instanceOf()) + } + nonce, ok := args[2].(rideInt) + if !ok { + return nil, errors.Errorf("fullLease: unexpected argument type '%s'", args[6].instanceOf()) + } + return newLease(rideRecipient(recipient), amount, nonce), nil +} + +func leaseCancel(_ Environment, args ...rideType) (rideType, error) { + if err := checkArgs(args, 1); err != nil { + return nil, errors.Wrap(err, "leaseCancel") + } + id, ok := args[0].(rideBytes) + if !ok { + return nil, errors.Errorf("leaseCancel: unexpected argument type '%s'", args[0].instanceOf()) + } + obj := make(rideObject) + obj[instanceFieldName] = rideString("LeaseCancel") + obj["leaseId"] = id + return obj, nil +} diff --git a/pkg/ride/functions_proto_test.go b/pkg/ride/functions_proto_test.go index 9c452cdc4..50f607ca1 100644 --- a/pkg/ride/functions_proto_test.go +++ b/pkg/ride/functions_proto_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/base64" "encoding/hex" + "errors" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/types" ) var ( @@ -21,6 +23,7 @@ var ( v3check = func(size int) bool { return size <= maxMessageLength } + v5takeString = takeRideString ) func TestAddressFromString(t *testing.T) { @@ -98,19 +101,355 @@ func TestAssetBalanceV4(t *testing.T) { } func TestIntFromState(t *testing.T) { - t.SkipNow() + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.IntegerDataEntry{Key: "key", Value: 100500}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := intFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestBytesFromState(t *testing.T) { - t.SkipNow() + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.BinaryDataEntry{Key: "key", Value: []byte("value")}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := bytesFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestStringFromState(t *testing.T) { - t.SkipNow() + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.StringDataEntry{Key: "key", Value: "value"}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideString("value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideString("value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := stringFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestBooleanFromState(t *testing.T) { - t.SkipNow() + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.BooleanDataEntry{Key: "key", Value: true}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideUnit{}}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := booleanFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestIntFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.IntegerDataEntry{Key: "key", Value: 100500}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideString("xxx")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := intFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBytesFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.BinaryDataEntry{Key: "key", Value: []byte("value")}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideString("xxx")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := bytesFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestStringFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.StringDataEntry{Key: "key", Value: "value"}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideString("value")}, + {[]rideType{rideString("xxx")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := stringFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBooleanFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.BooleanDataEntry{Key: "key", Value: true}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideString("xxx")}, false, rideUnit{}}, + {[]rideType{}, false, rideUnit{}}, + {[]rideType{rideUnit{}}, false, rideUnit{}}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideUnit{}}, + } { + r, err := booleanFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestAddressFromRecipient(t *testing.T) { @@ -146,7 +485,12 @@ func TestSigVerify(t *testing.T) { {[]rideType{rideInt(12345)}, v2check, true, nil}, {[]rideType{rideString("dsfjsadfl"), rideInt(12345)}, v2check, true, nil}, } { - te := &MockRideEnvironment{checkMessageLengthFunc: test.check} + te := &MockRideEnvironment{ + checkMessageLengthFunc: test.check, + libVersionFunc: func() int { + return 3 + }, + } r, err := sigVerify(te, test.args...) if test.fail { assert.Error(t, err) @@ -388,20 +732,355 @@ func TestCheckMerkleProof(t *testing.T) { } } -func TestInvValueFromState(t *testing.T) { - t.SkipNow() +func TestIntValueFromState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.IntegerDataEntry{Key: "key", Value: 100500}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := intValueFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBytesValueFromState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.BinaryDataEntry{Key: "key", Value: []byte("value")}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := bytesValueFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestStringValueFromState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.StringDataEntry{Key: "key", Value: "value"}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideString("value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideString("value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := stringValueFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestBooleanValueFromState(t *testing.T) { - t.SkipNow() + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + correctAlias := proto.NewAlias('T', "good") + incorrectAddress := proto.MustAddressFromString("3N3isZTp6tchjYox99bpxFkqxxySKY6FQsi") + incorrectAlias := proto.NewAlias('T', "bad") + correctAddressRecipient := proto.NewRecipientFromAddress(correctAddress) + correctAliasRecipient := proto.NewRecipientFromAlias(*correctAlias) + incorrectAddressRecipient := proto.NewRecipientFromAddress(incorrectAddress) + incorrectAliasRecipient := proto.NewRecipientFromAlias(*incorrectAlias) + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + if (account == correctAddressRecipient || account == correctAliasRecipient) && key == "key" { + return &proto.BooleanDataEntry{Key: "key", Value: true}, nil + } + return nil, errors.New("not found") + }, + } + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideRecipient(correctAddressRecipient), rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideRecipient(correctAddressRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAddressRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(incorrectAliasRecipient), rideString("key")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAddressRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideRecipient(correctAliasRecipient), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := booleanValueFromState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} +func TestIntValueFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.IntegerDataEntry{Key: "key", Value: 100500}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideInt(100500)}, + {[]rideType{rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := intValueFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } -func TestBytesValueFromState(t *testing.T) { - t.SkipNow() +func TestBytesValueFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.BinaryDataEntry{Key: "key", Value: []byte("value")}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideBytes("value")}, + {[]rideType{rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := bytesValueFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } -func TestStringValueFromState(t *testing.T) { - t.SkipNow() +func TestStringValueFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.StringDataEntry{Key: "key", Value: "value"}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideString("value")}, + {[]rideType{rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := stringValueFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestBooleanValueFromSelfState(t *testing.T) { + correctAddress := proto.MustAddressFromString("3Myqjf1D44wR8Vko4Tr5CwSzRNo2Vg9S7u7") + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return &MockSmartState{ + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + if *account.Address == correctAddress && key == "key" { + return &proto.BooleanDataEntry{Key: "key", Value: true}, nil + } + return nil, errors.New("not found") + }, + } + }, + thisFunc: func() rideType { + return rideAddress(correctAddress) + }, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("key")}, false, rideBoolean(true)}, + {[]rideType{rideString("xxx")}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideUnit{}}, false, rideThrow("failed to extract from Unit value")}, + {[]rideType{rideString("xxx"), rideInt(12345)}, false, rideThrow("failed to extract from Unit value")}, + } { + r, err := booleanValueFromSelfState(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } } func TestTransferFromProtobuf(t *testing.T) { diff --git a/pkg/ride/functions_strings.go b/pkg/ride/functions_strings.go index d5e571fa1..0e14d83ce 100644 --- a/pkg/ride/functions_strings.go +++ b/pkg/ride/functions_strings.go @@ -95,7 +95,7 @@ func twoStringsArgs(args []rideType) (string, string, error) { return string(s1), string(s2), nil } -func concatStrings(_ RideEnvironment, args ...rideType) (rideType, error) { +func concatStrings(_ Environment, args ...rideType) (rideType, error) { s1, s2, err := twoStringsArgs(args) if err != nil { return nil, errors.Wrap(err, "concatStrings") @@ -112,15 +112,15 @@ func concatStrings(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(out), nil } -func takeString(_ RideEnvironment, args ...rideType) (rideType, error) { +func takeString(env Environment, args ...rideType) (rideType, error) { s, n, err := stringAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "takeString") } - return takeRideString(s, n), nil + return env.takeString(s, n), nil } -func dropString(_ RideEnvironment, args ...rideType) (rideType, error) { +func dropString(_ Environment, args ...rideType) (rideType, error) { s, n, err := stringAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "dropString") @@ -128,7 +128,7 @@ func dropString(_ RideEnvironment, args ...rideType) (rideType, error) { return dropRideString(s, n), nil } -func sizeString(_ RideEnvironment, args ...rideType) (rideType, error) { +func sizeString(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "sizeString") @@ -136,7 +136,7 @@ func sizeString(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(utf8.RuneCountInString(string(s))), nil } -func indexOfSubstring(_ RideEnvironment, args ...rideType) (rideType, error) { +func indexOfSubstring(_ Environment, args ...rideType) (rideType, error) { s1, s2, err := twoStringsArgs(args) if err != nil { return nil, errors.Wrap(err, "indexOfSubstring") @@ -148,7 +148,7 @@ func indexOfSubstring(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(i), nil } -func indexOfSubstringWithOffset(_ RideEnvironment, args ...rideType) (rideType, error) { +func indexOfSubstringWithOffset(_ Environment, args ...rideType) (rideType, error) { s1, s2, n, err := twoStringsAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "lastIndexOfSubstringWithOffset") @@ -163,7 +163,7 @@ func indexOfSubstringWithOffset(_ RideEnvironment, args ...rideType) (rideType, return rideInt(i + n), nil } -func stringToBytes(_ RideEnvironment, args ...rideType) (rideType, error) { +func stringToBytes(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "stringToBytes") @@ -171,7 +171,7 @@ func stringToBytes(_ RideEnvironment, args ...rideType) (rideType, error) { return rideBytes(s), nil } -func dropRightString(_ RideEnvironment, args ...rideType) (rideType, error) { +func dropRightString(_ Environment, args ...rideType) (rideType, error) { s, n, err := stringAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "dropRightString") @@ -179,7 +179,7 @@ func dropRightString(_ RideEnvironment, args ...rideType) (rideType, error) { return takeRideString(s, utf8.RuneCountInString(s)-n), nil } -func takeRightString(_ RideEnvironment, args ...rideType) (rideType, error) { +func takeRightString(_ Environment, args ...rideType) (rideType, error) { s, n, err := stringAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "takeRightString") @@ -187,7 +187,7 @@ func takeRightString(_ RideEnvironment, args ...rideType) (rideType, error) { return dropRideString(s, utf8.RuneCountInString(s)-n), nil } -func splitString(_ RideEnvironment, args ...rideType) (rideType, error) { +func splitString(_ Environment, args ...rideType) (rideType, error) { s1, s2, err := twoStringsArgs(args) if err != nil { return nil, errors.Wrap(err, "splitString") @@ -199,7 +199,7 @@ func splitString(_ RideEnvironment, args ...rideType) (rideType, error) { return r, nil } -func parseInt(_ RideEnvironment, args ...rideType) (rideType, error) { +func parseInt(_ Environment, args ...rideType) (rideType, error) { s, err := stringArg(args) if err != nil { return nil, errors.Wrap(err, "parseInt") @@ -211,7 +211,7 @@ func parseInt(_ RideEnvironment, args ...rideType) (rideType, error) { return rideInt(i), nil } -func parseIntValue(env RideEnvironment, args ...rideType) (rideType, error) { +func parseIntValue(env Environment, args ...rideType) (rideType, error) { maybeInt, err := parseInt(env, args...) if err != nil { return nil, errors.Wrap(err, "parseIntValue") @@ -219,7 +219,7 @@ func parseIntValue(env RideEnvironment, args ...rideType) (rideType, error) { return extractValue(maybeInt) } -func lastIndexOfSubstring(_ RideEnvironment, args ...rideType) (rideType, error) { +func lastIndexOfSubstring(_ Environment, args ...rideType) (rideType, error) { s1, s2, err := twoStringsArgs(args) if err != nil { return nil, errors.Wrap(err, "lastIndexOfSubstring") @@ -231,7 +231,7 @@ func lastIndexOfSubstring(_ RideEnvironment, args ...rideType) (rideType, error) return rideInt(i), nil } -func lastIndexOfSubstringWithOffset(_ RideEnvironment, args ...rideType) (rideType, error) { +func lastIndexOfSubstringWithOffset(_ Environment, args ...rideType) (rideType, error) { s1, s2, n, err := twoStringsAndIntArgs(args) if err != nil { return nil, errors.Wrap(err, "lastIndexOfSubstringWithOffset") @@ -249,7 +249,7 @@ func lastIndexOfSubstringWithOffset(_ RideEnvironment, args ...rideType) (rideTy return rideInt(i), nil } -func makeString(_ RideEnvironment, args ...rideType) (rideType, error) { +func makeString(_ Environment, args ...rideType) (rideType, error) { if err := checkArgs(args, 2); err != nil { return nil, errors.Wrap(err, "makeString") } @@ -285,7 +285,7 @@ func makeString(_ RideEnvironment, args ...rideType) (rideType, error) { return rideString(strings.Join(parts, sep)), nil } -func contains(_ RideEnvironment, args ...rideType) (rideType, error) { +func contains(_ Environment, args ...rideType) (rideType, error) { s1, s2, err := twoStringsArgs(args) if err != nil { return nil, errors.Wrap(err, "contains") @@ -308,26 +308,27 @@ func runesDrop(s string, n int) string { return res } -// TODO: This is the correct implementation of takeString function that handles runes in UTF-8 string correct -//func runesTake(s string, n int) string { -// out := make([]rune, n) -// copy(out, []rune(s)[:n]) -// return string(out) -//} -// -//func takeRideString(s string, n int) rideString { -// l := utf8.RuneCountInString(s) -// t := n -// if t > l { -// t = l -// } -// if t < 0 { -// t = 0 -// } -// return rideString(runesTake(s, t)) -//} +// This is the CORRECT implementation of takeString function that handles runes in UTF-8 string correct +func runesTake(s string, n int) string { + out := make([]rune, n) + copy(out, []rune(s)[:n]) + return string(out) +} func takeRideString(s string, n int) rideString { + l := utf8.RuneCountInString(s) + t := n + if t > l { + t = l + } + if t < 0 { + t = 0 + } + return rideString(runesTake(s, t)) +} + +// This is the WRONG implementation of takeString function that handles runes in UTF-8 string INCORRECT +func takeRideStringWrong(s string, n int) rideString { b := utf16.Encode([]rune(s)) l := len(b) t := n diff --git a/pkg/ride/functions_strings_test.go b/pkg/ride/functions_strings_test.go index df75ba07b..8912e6da8 100644 --- a/pkg/ride/functions_strings_test.go +++ b/pkg/ride/functions_strings_test.go @@ -37,6 +37,43 @@ func TestConcatStrings(t *testing.T) { } func TestTakeString(t *testing.T) { + env := &MockRideEnvironment{ + takeStringFunc: v5takeString, + } + for _, test := range []struct { + args []rideType + fail bool + r rideType + }{ + {[]rideType{rideString("abc"), rideInt(2)}, false, rideString("ab")}, + {[]rideType{rideString("abc"), rideInt(4)}, false, rideString("abc")}, + {[]rideType{rideString("abc"), rideInt(0)}, false, rideString("")}, + {[]rideType{rideString("abc"), rideInt(-4)}, false, rideString("")}, + {[]rideType{rideString(""), rideInt(0)}, false, rideString("")}, + {[]rideType{rideString(""), rideInt(3)}, false, rideString("")}, + {[]rideType{rideString("abc")}, true, nil}, + {[]rideType{rideUnit{}}, true, nil}, + {[]rideType{rideInt(1), rideString("x")}, true, nil}, + {[]rideType{rideInt(1)}, true, nil}, + {[]rideType{}, true, nil}, + {[]rideType{rideString("DRAGORION : Cradle of Many Strings\n[MYTHIC]🔶🔶🔶🔶🔶\n\nCeli, child of the first light. One of the main characters of the story, she is the first to see the vision of Cloudscape and its inhabitants from the Earth's dimension after the great destruction.\n\nDragorion - avatars sung into being by Eneria to bring sleep to the people of Cloudscape. They speak in dreams as lullabies, symphonies, hymns, arias and melodies. ~Legendarium\n\n©️Art of Monztre\n"), rideInt(50)}, false, rideString("DRAGORION : Cradle of Many Strings\n[MYTHIC]🔶🔶🔶🔶🔶\n\n")}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬x"), rideInt(2)}, false, rideString("x冬")}, // the result is `x?` but it should be `x冬` + } { + r, err := takeString(env, test.args...) + if test.fail { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, test.r, r) + } + } +} + +func TestIncorrectTakeString(t *testing.T) { + env := &MockRideEnvironment{ + takeStringFunc: takeRideStringWrong, + } for _, test := range []struct { args []rideType fail bool @@ -55,7 +92,7 @@ func TestTakeString(t *testing.T) { {[]rideType{}, true, nil}, {[]rideType{rideString("DRAGORION : Cradle of Many Strings\n[MYTHIC]🔶🔶🔶🔶🔶\n\nCeli, child of the first light. One of the main characters of the story, she is the first to see the vision of Cloudscape and its inhabitants from the Earth's dimension after the great destruction.\n\nDragorion - avatars sung into being by Eneria to bring sleep to the people of Cloudscape. They speak in dreams as lullabies, symphonies, hymns, arias and melodies. ~Legendarium\n\n©️Art of Monztre\n"), rideInt(50)}, false, rideString("DRAGORION : Cradle of Many Strings\n[MYTHIC]🔶🔶🔶?")}, } { - r, err := takeString(nil, test.args...) + r, err := takeString(env, test.args...) if test.fail { assert.Error(t, err) } else { @@ -82,6 +119,8 @@ func TestDropString(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬x"), rideInt(2)}, false, rideString("x")}, } { r, err := dropString(nil, test.args...) if test.fail { @@ -108,6 +147,8 @@ func TestSizeString(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬x")}, false, rideInt(3)}, } { r, err := sizeString(nil, test.args...) if test.fail { @@ -133,6 +174,11 @@ func TestIndexOfSubstring(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬xqweqwe"), rideString("we")}, false, rideInt(4)}, // unicode indexOf + {[]rideType{takeRideString("世界x冬x", 4), takeRideString("冬", 1)}, false, rideInt(3)}, // unicode indexOf + {[]rideType{rideString("x冬xqweqwe"), rideString("ww")}, false, rideUnit{}}, // unicode indexOf (not present) + {[]rideType{rideString(""), rideString("x冬x")}, false, rideUnit{}}, // unicode indexOf from empty string } { r, err := indexOfSubstring(nil, test.args...) if test.fail { @@ -161,6 +207,10 @@ func TestIndexOfSubstringWithOffset(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬xqweqwe"), rideString("x冬xqw"), rideInt(0)}, false, rideInt(0)}, // unicode indexOf with zero offset + {[]rideType{rideString("冬weqwe"), rideString("we"), rideInt(2)}, false, rideInt(4)}, // unicode indexOf with start offset + {[]rideType{rideString(""), rideString("x冬x"), rideInt(1)}, false, rideUnit{}}, // unicode indexOf from empty string with offset } { r, err := indexOfSubstringWithOffset(nil, test.args...) if test.fail { @@ -216,6 +266,8 @@ func TestDropRightString(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬x"), rideInt(2)}, false, rideString("x")}, } { r, err := dropRightString(nil, test.args...) if test.fail { @@ -245,6 +297,8 @@ func TestTakeRightString(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("x冬x"), rideInt(2)}, false, rideString("冬x")}, } { r, err := takeRightString(nil, test.args...) if test.fail { @@ -274,6 +328,8 @@ func TestSplitString(t *testing.T) { {[]rideType{rideInt(1), rideString("x")}, true, nil}, {[]rideType{rideInt(1)}, true, nil}, {[]rideType{}, true, nil}, + // scala tests from https://github.com/wavesplatform/Waves/pull/3367 + {[]rideType{rideString("strx冬x1;🤦;🤦strx冬x2;🤦strx冬x3"), rideString(";🤦")}, false, rideList{rideString("strx冬x1"), rideString(""), rideString("strx冬x2"), rideString("strx冬x3")}}, } { r, err := splitString(nil, test.args...) if test.fail { diff --git a/pkg/ride/functions_test.go b/pkg/ride/functions_test.go index 03dd571c7..972d059e5 100644 --- a/pkg/ride/functions_test.go +++ b/pkg/ride/functions_test.go @@ -11,7 +11,7 @@ func TestNames(t *testing.T) { assert.Equal(t, "!", functionNameV2(0)) assert.Equal(t, "!=", functionNameV3(1)) assert.Equal(t, "wavesBalance", functionNameV2(67)) - assert.Equal(t, "DataTransaction", functionNameV4(180)) + assert.Equal(t, "DeleteEntry", functionNameV4(182)) } func TestCheckFunction(t *testing.T) { diff --git a/pkg/ride/generate/main.go b/pkg/ride/generate/main.go index f310832a3..a085f2a69 100644 --- a/pkg/ride/generate/main.go +++ b/pkg/ride/generate/main.go @@ -76,8 +76,8 @@ func functionsV2() map[string]string { m["wavesBalance"] = "wavesBalanceV3" m["Address"] = "address" m["Alias"] = "alias" - m["DataEntry"] = "dataEntry" m["AssetPair"] = "assetPair" + m["DataEntry"] = "dataEntry" m["DataTransaction"] = "dataTransaction" return m } @@ -149,12 +149,16 @@ func catalogueV2() map[string]int { m["wavesBalance"] = 109 m["Address"] = 1 m["Alias"] = 1 + m["AssetPair"] = 2 m["DataEntry"] = 2 m["DataTransaction"] = 9 - m["AssetPair"] = 2 return m } +func freeConstructorsV2() []string { + return []string{"Address", "Alias", "AssetPair", "DataEntry", "DataTransaction"} +} + func functionsV3() map[string]string { m := functionsV2() m["108"] = "pow" @@ -279,6 +283,10 @@ func catalogueV3() map[string]int { return m } +func freeConstructorsV3() []string { + return append(freeConstructorsV2(), "WriteSet", "TransferSet", "ScriptTransfer", "ScriptResult") +} + func functionsV4() map[string]string { m := functionsV3() // Remove obsolete constructors @@ -295,6 +303,7 @@ func functionsV4() map[string]string { m["Reissue"] = "reissue" m["Burn"] = "burn" m["SponsorFee"] = "sponsorship" + m["AttachedPayment"] = "attachedPayment" // Functions delete(m, "wavesBalance") // Remove wavesBalanceV3 @@ -361,6 +370,7 @@ func catalogueV4() map[string]int { m["Reissue"] = 3 m["Burn"] = 2 m["SponsorFee"] = 2 + m["AttachedPayment"] = 2 m["201"] = 6 m["202"] = 6 @@ -463,6 +473,108 @@ func catalogueV4() map[string]int { return m } +func freeConstructorsV4() []string { + return append(freeConstructorsV3(), "IntegerEntry", "BooleanEntry", "BinaryEntry", "StringEntry", + "DeleteEntry", "Reissue", "Burn", "SponsorFee", "AttachedPayment") +} + +func functionsV5() map[string]string { + m := functionsV4() + m["118"] = "powBigInt" + m["119"] = "logBigInt" + m["310"] = "toBigInt" + m["311"] = "sumBigInt" + m["312"] = "subtractBigInt" + m["313"] = "multiplyBigInt" + m["314"] = "divideBigInt" + m["315"] = "moduloBigInt" + m["316"] = "fractionBigInt" + m["317"] = "fractionBigIntRounds" + m["318"] = "unaryMinusBigInt" + m["319"] = "gtBigInt" + m["320"] = "geBigInt" + m["408"] = "maxListBigInt" + m["409"] = "minListBigInt" + m["413"] = "bigIntToBytes" + m["414"] = "bytesToBigInt" + m["415"] = "bytesToBigIntLim" + m["416"] = "bigIntToInt" + m["422"] = "bigIntToString" + m["423"] = "stringToBigInt" + m["424"] = "stringToBigIntOpt" + m["425"] = "medianListBigInt" + m["1009"] = "hashScriptAtAddress" + m["1020"] = "invoke" + m["1021"] = "reentrantInvoke" + m["1054"] = "isDataStorageUntouched" + m["1055"] = "intFromSelfState" + m["1056"] = "booleanFromSelfState" + m["1057"] = "bytesFromSelfState" + m["1058"] = "stringFromSelfState" + m["1081"] = "calculateLeaseID" + m["1092"] = "simplifiedLease" + m["1093"] = "fullLease" + m["fraction"] = "fractionIntRounds" + m["LeaseCancel"] = "leaseCancel" + m["@extrNative(1055)"] = "intValueFromSelfState" + m["@extrNative(1056)"] = "booleanValueFromSelfState" + m["@extrNative(1057)"] = "bytesValueFromSelfState" + m["@extrNative(1058)"] = "stringValueFromSelfState" + return m +} + +func catalogueV5() map[string]int { + m := catalogueV4() + m["107"] = 14 + m["118"] = 200 + m["119"] = 200 + m["310"] = 1 + m["311"] = 8 + m["312"] = 8 + m["313"] = 64 + m["314"] = 64 + m["315"] = 64 + m["316"] = 128 + m["317"] = 128 + m["318"] = 8 + m["319"] = 8 + m["320"] = 8 + m["408"] = 192 + m["409"] = 192 + m["413"] = 65 + m["414"] = 65 + m["415"] = 65 + m["416"] = 1 + m["422"] = 65 + m["423"] = 65 + m["424"] = 65 + m["425"] = 160 + m["1009"] = 200 + m["1020"] = 75 + m["1021"] = 75 + m["1054"] = 10 + m["1055"] = 10 + m["1056"] = 10 + m["1057"] = 10 + m["1058"] = 10 + m["1081"] = 1 + m["1092"] = 1 + m["1093"] = 1 + m["fraction"] = 17 + m["LeaseCancel"] = 1 + m["@extrNative(1055)"] = 10 + m["@extrNative(1056)"] = 10 + m["@extrNative(1057)"] = 10 + m["@extrNative(1058)"] = 10 + delete(m, "Up") + delete(m, "HalfDown") + return m +} + +func freeConstructorsV5() []string { + return append(freeConstructorsV4(), "LeaseCancel") +} + type constantDescription struct { typeName string constructor string @@ -516,6 +628,13 @@ func constantsV4() map[string]constantDescription { return constantsV3() } +func constantsV5() map[string]constantDescription { + c := constantsV4() + delete(c, "UP") + delete(c, "HALFDOWN") + return c +} + func constructorsFromConstants(m map[string]string, c map[string]constantDescription) { for _, v := range c { if v.constructor == "" { @@ -581,20 +700,26 @@ func createConstants(sb *strings.Builder, ver string, c map[string]constantDescr } func createConstructors(sb *strings.Builder, c map[string]constantDescription) { - for _, v := range c { - if v.constructor == "" { - tn := v.typeName - sb.WriteString(fmt.Sprintf("func new%s(RideEnvironment) rideType {\n", tn)) + keys := make([]string, 0, len(c)) + for k := range c { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + if c[k].constructor == "" { + tn := c[k].typeName + sb.WriteString(fmt.Sprintf("func new%s(Environment) rideType {\n", tn)) sb.WriteString(fmt.Sprintf("return rideNamedType{name: \"%s\"}\n", tn)) sb.WriteString("}\n\n") - sb.WriteString(fmt.Sprintf("func create%s(env RideEnvironment, args ...rideType) (rideType, error) {\n", tn)) + sb.WriteString(fmt.Sprintf("func create%s(env Environment, args ...rideType) (rideType, error) {\n", tn)) sb.WriteString(fmt.Sprintf("return rideNamedType{name: \"%s\"}, nil\n", tn)) sb.WriteString("}\n\n") } } } -func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c map[string]int) { +func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c map[string]int, n []string) { keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) @@ -602,7 +727,9 @@ func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c sort.Strings(keys) // Create sorted list of functions - sb.WriteString(fmt.Sprintf("var _functions_%s = [...]rideFunction{", ver)) + sb.WriteString(fmt.Sprintf("var _functions_%s [%d]rideFunction\n", ver, len(keys))) + sb.WriteString("func init() {\n") + sb.WriteString(fmt.Sprintf("_functions_%s = [%d]rideFunction{", ver, len(keys))) for i, k := range keys { sb.WriteString(m[k]) if i < len(m)-1 { @@ -610,6 +737,7 @@ func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c } } sb.WriteString("}\n") + sb.WriteString("}\n\n") // Create list of costs sb.WriteString(fmt.Sprintf("var _catalogue_%s = [...]int{", ver)) @@ -619,8 +747,9 @@ func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c sb.WriteString(", ") } } - sb.WriteString("}\n") + sb.WriteString("}\n\n") + // Create map of function costs sb.WriteString(fmt.Sprintf("var Catalogue%s = map[string]int{", ver)) for i, k := range keys { sb.WriteString(fmt.Sprintf("\"%s\":%d", k, c[k])) @@ -628,7 +757,17 @@ func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c sb.WriteString(", ") } } - sb.WriteString("}\n") + sb.WriteString("}\n\n") + + // Create map for evaluation zero cost constructors + sb.WriteString(fmt.Sprintf("var FreeFunctions%s = map[string]struct{}{", ver)) + for i, k := range n { + sb.WriteString(fmt.Sprintf("\"%s\":{}", k)) + if i < len(m)-1 { + sb.WriteString(", ") + } + } + sb.WriteString("}\n\n") // Create string of concatenated names of functions sb.WriteString(fmt.Sprintf("const _names_%s = \"%s\"\n", ver, strings.Join(keys, ""))) @@ -644,28 +783,31 @@ func createFunctionsList(sb *strings.Builder, ver string, m map[string]string, c } } sb.WriteString("}\n\n") + sb.WriteString(fmt.Sprintf("func functionName%s(i int) string {\n", ver)) sb.WriteString(fmt.Sprintf("if i < 0 || i > %d {\n", len(keys)-1)) sb.WriteString("return \"\"\n") sb.WriteString("}\n") - sb.WriteString(fmt.Sprintf("return _names_%s[_index_%s[i]:_index_%s[i+1]]\n}\n", ver, ver, ver)) + sb.WriteString(fmt.Sprintf("return _names_%s[_index_%s[i]:_index_%s[i+1]]\n}\n\n", ver, ver, ver)) + sb.WriteString(fmt.Sprintf("func function%s(id int) rideFunction {\n", ver)) sb.WriteString(fmt.Sprintf("if id < 0 || id > %d {\n", len(keys)-1)) sb.WriteString("return nil\n") sb.WriteString("}\n") - sb.WriteString(fmt.Sprintf("return _functions_%s[id]\n}\n", ver)) + sb.WriteString(fmt.Sprintf("return _functions_%s[id]\n}\n\n", ver)) + sb.WriteString(fmt.Sprintf("func checkFunction%s(name string) (uint16, bool) {\n", ver)) sb.WriteString(fmt.Sprintf("for i := 0; i <= %d; i++ {\n", len(keys)-1)) sb.WriteString(fmt.Sprintf("if _names_%s[_index_%s[i]:_index_%s[i+1]] == name {\n", ver, ver, ver)) sb.WriteString("return uint16(i), true\n") sb.WriteString("}\n}\n") sb.WriteString("return 0, false\n") - sb.WriteString("}\n") + sb.WriteString("}\n\n") sb.WriteString(fmt.Sprintf("func cost%s(id int) int {\n", ver)) sb.WriteString(fmt.Sprintf("if id < 0 || id > %d {\n", len(keys)-1)) sb.WriteString("return -1\n") sb.WriteString("}\n") - sb.WriteString(fmt.Sprintf("return _catalogue_%s[id]\n}\n", ver)) + sb.WriteString(fmt.Sprintf("return _catalogue_%s[id]\n}\n\n", ver)) } func createTuples(sb *strings.Builder) { @@ -686,7 +828,7 @@ func createTuples(sb *strings.Builder) { sb.WriteString(fmt.Sprintf("%s rideType\n", el)) } sb.WriteString("}\n\n") - sb.WriteString(fmt.Sprintf("func newTuple%d(_ RideEnvironment, args ...rideType) (rideType, error) {\n", n)) + sb.WriteString(fmt.Sprintf("func newTuple%d(_ Environment, args ...rideType) (rideType, error) {\n", n)) sb.WriteString(fmt.Sprintf("if len(args) != %d {\n", n)) sb.WriteString("return nil, errors.New(\"invalid number of arguments\")\n") sb.WriteString("}\n") @@ -734,9 +876,10 @@ func main() { sb.WriteString("// Code generated by ride/generate/main.go. DO NOT EDIT.\n") sb.WriteString("\n") sb.WriteString("package ride\n") - createFunctionsList(sb, "V2", functionsV2(), catalogueV2()) - createFunctionsList(sb, "V3", functionsV3(), catalogueV3()) - createFunctionsList(sb, "V4", functionsV4(), catalogueV4()) + createFunctionsList(sb, "V2", functionsV2(), catalogueV2(), freeConstructorsV2()) + createFunctionsList(sb, "V3", functionsV3(), catalogueV3(), freeConstructorsV3()) + createFunctionsList(sb, "V4", functionsV4(), catalogueV4(), freeConstructorsV4()) + createFunctionsList(sb, "V5", functionsV5(), catalogueV5(), freeConstructorsV5()) code := sb.String() b, err := format.Source([]byte(code)) if err != nil { @@ -755,6 +898,7 @@ func main() { createConstants(sb, "V2", constantsV2()) createConstants(sb, "V3", constantsV3()) createConstants(sb, "V4", constantsV4()) + createConstants(sb, "V5", constantsV5()) createConstructors(sb, constantsV4()) code = sb.String() b, err = format.Source([]byte(code)) @@ -780,7 +924,7 @@ func main() { sb.WriteString(")\n") for _, l := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} { fn := fmt.Sprintf("bls12Groth16Verify_%d", l) - sb.WriteString(fmt.Sprintf("func %s(env RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(env Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("if err := checkArgs(args, 3); err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") @@ -801,14 +945,14 @@ func main() { sb.WriteString("}\n") sb.WriteString("ok, err := crypto.Bls12381{}.Groth16Verify(key, proof, inputs)\n") sb.WriteString("if err != nil {\n") - sb.WriteString("return rideUnit{}, err\n") + sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") sb.WriteString("return rideBoolean(ok), nil\n") sb.WriteString("}\n\n") } for _, l := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} { fn := fmt.Sprintf("bn256Groth16Verify_%d", l) - sb.WriteString(fmt.Sprintf("func %s(env RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(env Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("if err := checkArgs(args, 3); err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") @@ -829,14 +973,14 @@ func main() { sb.WriteString("}\n") sb.WriteString("ok, err := crypto.Bn256{}.Groth16Verify(key, proof, inputs)\n") sb.WriteString("if err != nil {\n") - sb.WriteString("return rideUnit{}, err\n") + sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") sb.WriteString("return rideBoolean(ok), nil\n") sb.WriteString("}\n\n") } for _, l := range []int{8, 16, 32, 64, 128} { fn := fmt.Sprintf("sigVerify_%d", l) - sb.WriteString(fmt.Sprintf("func %s(env RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(env Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("if err := checkArgs(args, 3); err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") @@ -869,7 +1013,7 @@ func main() { } for _, l := range []int{16, 32, 64, 128} { fn := fmt.Sprintf("rsaVerify_%d", l) - sb.WriteString(fmt.Sprintf("func %s(_ RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(_ Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("if err := checkArgs(args, 4); err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) sb.WriteString("}\n") @@ -915,7 +1059,7 @@ func main() { } for _, l := range []int{16, 32, 64, 128} { fn := fmt.Sprintf("keccak256_%d", l) - sb.WriteString(fmt.Sprintf("func %s(env RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(env Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("data, err := bytesOrStringArg(args)\n") sb.WriteString("if err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) @@ -932,7 +1076,7 @@ func main() { } for _, l := range []int{16, 32, 64, 128} { fn := fmt.Sprintf("blake2b256_%d", l) - sb.WriteString(fmt.Sprintf("func %s(_ RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(_ Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("data, err := bytesOrStringArg(args)\n") sb.WriteString("if err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) @@ -949,7 +1093,7 @@ func main() { } for _, l := range []int{16, 32, 64, 128} { fn := fmt.Sprintf("sha256_%d", l) - sb.WriteString(fmt.Sprintf("func %s(_ RideEnvironment, args ...rideType) (rideType, error) {\n", fn)) + sb.WriteString(fmt.Sprintf("func %s(_ Environment, args ...rideType) (rideType, error) {\n", fn)) sb.WriteString("data, err := bytesOrStringArg(args)\n") sb.WriteString("if err != nil {\n") sb.WriteString(fmt.Sprintf("return nil, errors.Wrap(err, \"%s\")\n", fn)) diff --git a/pkg/ride/math/math.go b/pkg/ride/math/math.go index c02d247f7..05db7816c 100644 --- a/pkg/ride/math/math.go +++ b/pkg/ride/math/math.go @@ -1,6 +1,8 @@ package math import ( + "math/big" + "github.com/ericlagergren/decimal" "github.com/ericlagergren/decimal/math" "github.com/pkg/errors" @@ -12,7 +14,17 @@ var ( ten = decimal.New(10, 0) ) -func convertToResult(v *decimal.Big, scale int, mode decimal.RoundingMode) (int64, error) { +func checkScales(baseScale, exponentScale, resultScale int) bool { + // 8 is the maximum scale for RIDE Int values + return baseScale >= 0 && baseScale <= 8 && exponentScale >= 0 && exponentScale <= 8 && resultScale >= 0 && resultScale <= 8 +} + +func checkScalesBigInt(baseScale, exponentScale, resultScale int) bool { + // 18 is the maximum scale for RIDE BigInt values + return baseScale >= 0 && baseScale <= 18 && exponentScale >= 0 && exponentScale <= 18 && resultScale >= 0 && resultScale <= 18 +} + +func convertToIntResult(v *decimal.Big, scale int, mode decimal.RoundingMode) (int64, error) { context := decimal.Context128 context.RoundingMode = mode r := decimal.WithContext(context).Set(v) @@ -27,31 +39,57 @@ func convertToResult(v *decimal.Big, scale int, mode decimal.RoundingMode) (int6 return res, nil } +func convertToBigIntResult(v *decimal.Big, scale int, mode decimal.RoundingMode) (*big.Int, error) { + if v.IsNaN(0) || v.IsInf(0) { + return nil, errors.New("result is NaN or Infinity") + } + context := decimal.Context128 + context.RoundingMode = mode + // r = v * 10^s + r := decimal.WithContext(context).Set(v) + s := decimal.WithContext(decimal.Context128).SetMantScale(int64(scale), 0) + m := decimal.WithContext(decimal.Context128) + math.Pow(m, ten, s) + r.Mul(r, m) + return r.RoundToInt().Int(nil), nil +} + +func pow(base, exponent *decimal.Big) (*decimal.Big, error) { + if base.IsInt() && exponent.Cmp(zero) == 0 { + return one, nil + } + r := decimal.WithContext(decimal.Context128) + r = math.Pow(r, base, exponent) + if r.Context.Err() != nil { + return nil, errors.New(r.Context.Conditions.Error()) + } + return r, nil +} + func Pow(base, exponent int64, baseScale, exponentScale, resultScale int, mode decimal.RoundingMode) (int64, error) { - if baseScale < 0 || baseScale > 8 || - exponentScale < 0 || exponentScale > 8 || - resultScale < 0 || resultScale > 8 { - return 0, errors.New("pow: invalid scale") + if !checkScales(baseScale, exponentScale, resultScale) { + return 0, errors.New("invalid scale") } b := decimal.WithContext(decimal.Context128).SetMantScale(base, baseScale) e := decimal.WithContext(decimal.Context128).SetMantScale(exponent, exponentScale) - if b.IsInt() && e.Cmp(zero) == 0 { - res, err := convertToResult(one, resultScale, mode) - if err != nil { - return 0, errors.Wrap(err, "pow") - } - return res, nil + r, err := pow(b, e) + if err != nil { + return 0, err } - r := decimal.WithContext(decimal.Context128) - r = math.Pow(r, b, e) - if r.Context.Err() != nil { - return 0, errors.Errorf("pow: %s", r.Context.Conditions.Error()) + return convertToIntResult(r, resultScale, mode) +} + +func PowBigInt(base, exponent *big.Int, baseScale, exponentScale, resultScale int, mode decimal.RoundingMode) (*big.Int, error) { + if !checkScalesBigInt(baseScale, exponentScale, resultScale) { + return nil, errors.New("invalid scale") } - res, err := convertToResult(r, resultScale, mode) + b := decimal.WithContext(decimal.Context128).SetBigMantScale(base, baseScale) + e := decimal.WithContext(decimal.Context128).SetBigMantScale(exponent, exponentScale) + r, err := pow(b, e) if err != nil { - return 0, errors.Wrap(err, "pow") + return nil, err } - return res, nil + return convertToBigIntResult(r, resultScale, mode) } func Fraction(value, numerator, denominator int64) (int64, error) { @@ -64,48 +102,63 @@ func Fraction(value, numerator, denominator int64) (int64, error) { if err := v.Context.Err(); err != nil { return 0, errors.Wrap(err, "Fraction") } - res, err := convertToResult(v, 0, decimal.ToZero) + res, err := convertToIntResult(v, 0, decimal.ToZero) if err != nil { return 0, errors.Wrap(err, "Fraction") } return res, nil } -func Log(base, exponent int64, baseScale, exponentScale, resultScale int, mode decimal.RoundingMode) (int64, error) { - if baseScale < 0 || baseScale > 8 || - exponentScale < 0 || exponentScale > 8 || - resultScale < 0 || resultScale > 8 { - return 0, errors.New("log: invalid scale") - } - b := decimal.WithContext(decimal.Context128).SetMantScale(base, baseScale) - e := decimal.WithContext(decimal.Context128).SetMantScale(exponent, exponentScale) +func log(base, exponent *decimal.Big, resultScale int) (*decimal.Big, error) { r := decimal.WithContext(decimal.Context128).SetMantScale(0, resultScale) bl := decimal.WithContext(decimal.Context128) - math.Log(bl, b) + math.Log(bl, base) if bl.Context.Err() != nil { - return 0, errors.New(bl.Context.Conditions.Error()) + return nil, errors.New(bl.Context.Conditions.Error()) } el := decimal.WithContext(decimal.Context128) - math.Log(el, e) + math.Log(el, exponent) if el.Context.Err() != nil { - return 0, errors.New(el.Context.Conditions.Error()) + return nil, errors.New(el.Context.Conditions.Error()) } r.Quo(bl, el) if r.Context.Err() != nil { - return 0, errors.New(r.Context.Conditions.Error()) + return nil, errors.New(r.Context.Conditions.Error()) } - res, err := convertToResult(r, resultScale, mode) + return r, nil +} + +func Log(base, exponent int64, baseScale, exponentScale, resultScale int, mode decimal.RoundingMode) (int64, error) { + if !checkScales(baseScale, exponentScale, resultScale) { + return 0, errors.New("invalid scale") + } + b := decimal.WithContext(decimal.Context128).SetMantScale(base, baseScale) + e := decimal.WithContext(decimal.Context128).SetMantScale(exponent, exponentScale) + r, err := log(b, e, resultScale) if err != nil { - return 0, errors.Wrap(err, "log") + return 0, err } - return res, nil + return convertToIntResult(r, resultScale, mode) +} + +func LogBigInt(base, exponent *big.Int, baseScale, exponentScale, resultScale int, mode decimal.RoundingMode) (*big.Int, error) { + if !checkScalesBigInt(baseScale, exponentScale, resultScale) { + return nil, errors.New("invalid scale") + } + b := decimal.WithContext(decimal.Context128).SetBigMantScale(base, baseScale) + e := decimal.WithContext(decimal.Context128).SetBigMantScale(exponent, exponentScale) + r, err := log(b, e, resultScale) + if err != nil { + return nil, err + } + return convertToBigIntResult(r, resultScale, mode) } -func ModDivision(x int64, y int64) int64 { +func ModDivision(x, y int64) int64 { return x - FloorDiv(x, y)*y } -func FloorDiv(x int64, y int64) int64 { +func FloorDiv(x, y int64) int64 { r := x / y // if the signs are different and modulo not zero, round down if (x^y) < 0 && (r*y != x) { @@ -113,3 +166,34 @@ func FloorDiv(x int64, y int64) int64 { } return r } + +func FloorDivBigInt(x, y *big.Int) *big.Int { + var r *big.Int + if x.Sign() == y.Sign() { + if x.Cmp(y) < 0 { + // abs(y-x)/2 + x + r = y.Sub(y, x) + r = r.Abs(r) + r = r.Div(r, big.NewInt(2)) + r = r.Add(r, x) + return r + } + // abs(x-y)/2 + y + r = x.Sub(x, y) + r = r.Abs(r) + r = r.Div(r, big.NewInt(2)) + r = r.Add(r, y) + return r + } + d := x.Add(x, y) + two := big.NewInt(2) + zero := big.NewInt(0) + d2 := big.NewInt(0).Mod(d, two) + if d.Cmp(zero) >= 0 || d2.Cmp(zero) == 0 { + r = d.Div(d, two) + return r + } + r = d.Sub(d, big.NewInt(1)) + r = r.Div(r, two) + return r +} diff --git a/pkg/ride/parser.go b/pkg/ride/parser.go index 20e4542ef..9e5dcaeaa 100644 --- a/pkg/ride/parser.go +++ b/pkg/ride/parser.go @@ -77,7 +77,7 @@ func (p *parser) parse() (*Tree, error) { switch v := int(vb); v { case 0: return p.parseDApp() - case 1, 2, 3, 4: + case 1, 2, 3, 4, 5: return p.parseScript(v) default: return nil, errors.Errorf("unsupported script version %d", v) diff --git a/pkg/ride/program.go b/pkg/ride/program.go index e384d7b9b..be563e7db 100644 --- a/pkg/ride/program.go +++ b/pkg/ride/program.go @@ -8,7 +8,7 @@ type callable struct { } type RideScript interface { - Run(env RideEnvironment) (RideResult, error) + Run(env Environment) (Result, error) code() []byte } @@ -19,7 +19,7 @@ type SimpleScript struct { Constants []rideType } -func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { +func (s *SimpleScript) Run(env Environment) (Result, error) { fs, err := selectFunctions(s.LibVersion) if err != nil { return nil, errors.Wrap(err, "simple script execution failed") @@ -61,7 +61,7 @@ type DAppScript struct { EntryPoints map[string]callable } -func (s *DAppScript) Run(env RideEnvironment) (RideResult, error) { +func (s *DAppScript) Run(env Environment) (Result, error) { if _, ok := s.EntryPoints[""]; !ok { return nil, errors.Errorf("no verifier") } diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 703ed35e3..8c977b3c8 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -2,21 +2,29 @@ package ride import "github.com/wavesplatform/gowaves/pkg/proto" -type RideResult interface { +type Result interface { Result() bool UserError() string + userResult() rideType ScriptActions() []proto.ScriptAction + Complexity() int } type ScriptResult struct { - res bool - msg string + res bool + msg string + param rideType + complexity int } func (r ScriptResult) Result() bool { return r.res } +func (r ScriptResult) userResult() rideType { + return r.param +} + func (r ScriptResult) UserError() string { return r.msg } @@ -25,16 +33,26 @@ func (r ScriptResult) ScriptActions() []proto.ScriptAction { return nil } +func (r ScriptResult) Complexity() int { + return r.complexity +} + type DAppResult struct { - res bool // true - success, false - call failed, read msg - actions []proto.ScriptAction - msg string + res bool // true - success, false - call failed, read msg + actions []proto.ScriptAction + msg string + param rideType + complexity int } func (r DAppResult) Result() bool { return r.res } +func (r DAppResult) userResult() rideType { + return r.param +} + func (r DAppResult) UserError() string { return r.msg } @@ -42,3 +60,7 @@ func (r DAppResult) UserError() string { func (r DAppResult) ScriptActions() []proto.ScriptAction { return r.actions } + +func (r DAppResult) Complexity() int { + return r.complexity +} diff --git a/pkg/ride/runtime.go b/pkg/ride/runtime.go index f12850dd1..e9074ccde 100644 --- a/pkg/ride/runtime.go +++ b/pkg/ride/runtime.go @@ -2,6 +2,7 @@ package ride import ( "bytes" + "math/big" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" @@ -72,6 +73,30 @@ func (l rideInt) get(prop string) (rideType, error) { return nil, errors.Errorf("type '%s' has no property '%s'", l.instanceOf(), prop) } +type rideBigInt struct { + v *big.Int +} + +func (l rideBigInt) instanceOf() string { + return "BigInt" +} + +func (l rideBigInt) eq(other rideType) bool { + if o, ok := other.(rideBigInt); ok { + return l.v.Cmp(o.v) == 0 + } + return false +} + +func (l rideBigInt) get(prop string) (rideType, error) { + //TODO: there is possibility of few properties like 'bytes', 'int' and so on + return nil, errors.Errorf("type '%s' has no property '%s'", l.instanceOf(), prop) +} + +func (l rideBigInt) String() string { + return l.v.String() +} + type rideString string func (s rideString) instanceOf() string { @@ -330,10 +355,10 @@ func (a rideList) get(prop string) (rideType, error) { return nil, errors.Errorf("type '%s' has no property '%s'", a.instanceOf(), prop) } -type rideFunction func(env RideEnvironment, args ...rideType) (rideType, error) +type rideFunction func(env Environment, args ...rideType) (rideType, error) -//go:generate moq -out runtime_moq_test.go . RideEnvironment:MockRideEnvironment -type RideEnvironment interface { +//go:generate moq -out runtime_moq_test.go . Environment:MockRideEnvironment +type Environment interface { scheme() byte height() rideInt transaction() rideObject @@ -341,8 +366,13 @@ type RideEnvironment interface { block() rideObject txID() rideType // Invoke transaction ID state() types.SmartState + timestamp() uint64 + setNewDAppAddress(address proto.Address) checkMessageLength(int) bool + takeString(s string, n int) rideString invocation() rideObject // Invocation object made of invoke transaction + setInvocation(inv rideObject) + libVersion() int } -type rideConstructor func(RideEnvironment) rideType +type rideConstructor func(Environment) rideType diff --git a/pkg/ride/runtime_moq_test.go b/pkg/ride/runtime_moq_test.go index ce0b328b2..97ec5f091 100644 --- a/pkg/ride/runtime_moq_test.go +++ b/pkg/ride/runtime_moq_test.go @@ -4,20 +4,21 @@ package ride import ( + "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" "sync" ) -// Ensure, that MockRideEnvironment does implement RideEnvironment. +// Ensure, that MockRideEnvironment does implement Environment. // If this is not the case, regenerate this file with moq. -var _ RideEnvironment = &MockRideEnvironment{} +var _ Environment = &MockRideEnvironment{} -// MockRideEnvironment is a mock implementation of RideEnvironment. +// MockRideEnvironment is a mock implementation of Environment. // -// func TestSomethingThatUsesRideEnvironment(t *testing.T) { +// func TestSomethingThatUsesEnvironment(t *testing.T) { // -// // make and configure a mocked RideEnvironment -// mockedRideEnvironment := &MockRideEnvironment{ +// // make and configure a mocked Environment +// mockedEnvironment := &MockRideEnvironment{ // blockFunc: func() rideObject { // panic("mock out the block method") // }, @@ -30,15 +31,30 @@ var _ RideEnvironment = &MockRideEnvironment{} // invocationFunc: func() rideObject { // panic("mock out the invocation method") // }, +// libVersionFunc: func() int { +// panic("mock out the libVersion method") +// }, // schemeFunc: func() byte { // panic("mock out the scheme method") // }, +// setInvocationFunc: func(inv rideObject) { +// panic("mock out the setInvocation method") +// }, +// setNewDAppAddressFunc: func(address proto.Address) { +// panic("mock out the setNewDAppAddress method") +// }, // stateFunc: func() types.SmartState { // panic("mock out the state method") // }, +// takeStringFunc: func(s string, n int) rideString { +// panic("mock out the takeString method") +// }, // thisFunc: func() rideType { // panic("mock out the this method") // }, +// timestampFunc: func() uint64 { +// panic("mock out the timestamp method") +// }, // transactionFunc: func() rideObject { // panic("mock out the transaction method") // }, @@ -47,7 +63,7 @@ var _ RideEnvironment = &MockRideEnvironment{} // }, // } // -// // use mockedRideEnvironment in code that requires RideEnvironment +// // use mockedEnvironment in code that requires Environment // // and then make assertions. // // } @@ -64,15 +80,30 @@ type MockRideEnvironment struct { // invocationFunc mocks the invocation method. invocationFunc func() rideObject + // libVersionFunc mocks the libVersion method. + libVersionFunc func() int + // schemeFunc mocks the scheme method. schemeFunc func() byte + // setInvocationFunc mocks the setInvocation method. + setInvocationFunc func(inv rideObject) + + // setNewDAppAddressFunc mocks the setNewDAppAddress method. + setNewDAppAddressFunc func(address proto.Address) + // stateFunc mocks the state method. stateFunc func() types.SmartState + // takeStringFunc mocks the takeString method. + takeStringFunc func(s string, n int) rideString + // thisFunc mocks the this method. thisFunc func() rideType + // timestampFunc mocks the timestamp method. + timestampFunc func() uint64 + // transactionFunc mocks the transaction method. transactionFunc func() rideObject @@ -95,15 +126,38 @@ type MockRideEnvironment struct { // invocation holds details about calls to the invocation method. invocation []struct { } + // libVersion holds details about calls to the libVersion method. + libVersion []struct { + } // scheme holds details about calls to the scheme method. scheme []struct { } + // setInvocation holds details about calls to the setInvocation method. + setInvocation []struct { + // Inv is the inv argument value. + Inv rideObject + } + // setNewDAppAddress holds details about calls to the setNewDAppAddress method. + setNewDAppAddress []struct { + // Address is the address argument value. + Address proto.Address + } // state holds details about calls to the state method. state []struct { } + // takeString holds details about calls to the takeString method. + takeString []struct { + // S is the s argument value. + S string + // N is the n argument value. + N int + } // this holds details about calls to the this method. this []struct { } + // timestamp holds details about calls to the timestamp method. + timestamp []struct { + } // transaction holds details about calls to the transaction method. transaction []struct { } @@ -115,9 +169,14 @@ type MockRideEnvironment struct { lockcheckMessageLength sync.RWMutex lockheight sync.RWMutex lockinvocation sync.RWMutex + locklibVersion sync.RWMutex lockscheme sync.RWMutex + locksetInvocation sync.RWMutex + locksetNewDAppAddress sync.RWMutex lockstate sync.RWMutex + locktakeString sync.RWMutex lockthis sync.RWMutex + locktimestamp sync.RWMutex locktransaction sync.RWMutex locktxID sync.RWMutex } @@ -125,7 +184,7 @@ type MockRideEnvironment struct { // block calls blockFunc. func (mock *MockRideEnvironment) block() rideObject { if mock.blockFunc == nil { - panic("MockRideEnvironment.blockFunc: method is nil but RideEnvironment.block was just called") + panic("MockRideEnvironment.blockFunc: method is nil but Environment.block was just called") } callInfo := struct { }{} @@ -137,7 +196,7 @@ func (mock *MockRideEnvironment) block() rideObject { // blockCalls gets all the calls that were made to block. // Check the length with: -// len(mockedRideEnvironment.blockCalls()) +// len(mockedEnvironment.blockCalls()) func (mock *MockRideEnvironment) blockCalls() []struct { } { var calls []struct { @@ -151,7 +210,7 @@ func (mock *MockRideEnvironment) blockCalls() []struct { // checkMessageLength calls checkMessageLengthFunc. func (mock *MockRideEnvironment) checkMessageLength(in1 int) bool { if mock.checkMessageLengthFunc == nil { - panic("MockRideEnvironment.checkMessageLengthFunc: method is nil but RideEnvironment.checkMessageLength was just called") + panic("MockRideEnvironment.checkMessageLengthFunc: method is nil but Environment.checkMessageLength was just called") } callInfo := struct { In1 int @@ -166,7 +225,7 @@ func (mock *MockRideEnvironment) checkMessageLength(in1 int) bool { // checkMessageLengthCalls gets all the calls that were made to checkMessageLength. // Check the length with: -// len(mockedRideEnvironment.checkMessageLengthCalls()) +// len(mockedEnvironment.checkMessageLengthCalls()) func (mock *MockRideEnvironment) checkMessageLengthCalls() []struct { In1 int } { @@ -182,7 +241,7 @@ func (mock *MockRideEnvironment) checkMessageLengthCalls() []struct { // height calls heightFunc. func (mock *MockRideEnvironment) height() rideInt { if mock.heightFunc == nil { - panic("MockRideEnvironment.heightFunc: method is nil but RideEnvironment.height was just called") + panic("MockRideEnvironment.heightFunc: method is nil but Environment.height was just called") } callInfo := struct { }{} @@ -194,7 +253,7 @@ func (mock *MockRideEnvironment) height() rideInt { // heightCalls gets all the calls that were made to height. // Check the length with: -// len(mockedRideEnvironment.heightCalls()) +// len(mockedEnvironment.heightCalls()) func (mock *MockRideEnvironment) heightCalls() []struct { } { var calls []struct { @@ -208,7 +267,7 @@ func (mock *MockRideEnvironment) heightCalls() []struct { // invocation calls invocationFunc. func (mock *MockRideEnvironment) invocation() rideObject { if mock.invocationFunc == nil { - panic("MockRideEnvironment.invocationFunc: method is nil but RideEnvironment.invocation was just called") + panic("MockRideEnvironment.invocationFunc: method is nil but Environment.invocation was just called") } callInfo := struct { }{} @@ -220,7 +279,7 @@ func (mock *MockRideEnvironment) invocation() rideObject { // invocationCalls gets all the calls that were made to invocation. // Check the length with: -// len(mockedRideEnvironment.invocationCalls()) +// len(mockedEnvironment.invocationCalls()) func (mock *MockRideEnvironment) invocationCalls() []struct { } { var calls []struct { @@ -231,10 +290,36 @@ func (mock *MockRideEnvironment) invocationCalls() []struct { return calls } +// libVersion calls libVersionFunc. +func (mock *MockRideEnvironment) libVersion() int { + if mock.libVersionFunc == nil { + panic("MockRideEnvironment.libVersionFunc: method is nil but Environment.libVersion was just called") + } + callInfo := struct { + }{} + mock.locklibVersion.Lock() + mock.calls.libVersion = append(mock.calls.libVersion, callInfo) + mock.locklibVersion.Unlock() + return mock.libVersionFunc() +} + +// libVersionCalls gets all the calls that were made to libVersion. +// Check the length with: +// len(mockedEnvironment.libVersionCalls()) +func (mock *MockRideEnvironment) libVersionCalls() []struct { +} { + var calls []struct { + } + mock.locklibVersion.RLock() + calls = mock.calls.libVersion + mock.locklibVersion.RUnlock() + return calls +} + // scheme calls schemeFunc. func (mock *MockRideEnvironment) scheme() byte { if mock.schemeFunc == nil { - panic("MockRideEnvironment.schemeFunc: method is nil but RideEnvironment.scheme was just called") + panic("MockRideEnvironment.schemeFunc: method is nil but Environment.scheme was just called") } callInfo := struct { }{} @@ -246,7 +331,7 @@ func (mock *MockRideEnvironment) scheme() byte { // schemeCalls gets all the calls that were made to scheme. // Check the length with: -// len(mockedRideEnvironment.schemeCalls()) +// len(mockedEnvironment.schemeCalls()) func (mock *MockRideEnvironment) schemeCalls() []struct { } { var calls []struct { @@ -257,10 +342,72 @@ func (mock *MockRideEnvironment) schemeCalls() []struct { return calls } +// setInvocation calls setInvocationFunc. +func (mock *MockRideEnvironment) setInvocation(inv rideObject) { + if mock.setInvocationFunc == nil { + panic("MockRideEnvironment.setInvocationFunc: method is nil but Environment.setInvocation was just called") + } + callInfo := struct { + Inv rideObject + }{ + Inv: inv, + } + mock.locksetInvocation.Lock() + mock.calls.setInvocation = append(mock.calls.setInvocation, callInfo) + mock.locksetInvocation.Unlock() + mock.setInvocationFunc(inv) +} + +// setInvocationCalls gets all the calls that were made to setInvocation. +// Check the length with: +// len(mockedEnvironment.setInvocationCalls()) +func (mock *MockRideEnvironment) setInvocationCalls() []struct { + Inv rideObject +} { + var calls []struct { + Inv rideObject + } + mock.locksetInvocation.RLock() + calls = mock.calls.setInvocation + mock.locksetInvocation.RUnlock() + return calls +} + +// setNewDAppAddress calls setNewDAppAddressFunc. +func (mock *MockRideEnvironment) setNewDAppAddress(address proto.Address) { + if mock.setNewDAppAddressFunc == nil { + panic("MockRideEnvironment.setNewDAppAddressFunc: method is nil but Environment.setNewDAppAddress was just called") + } + callInfo := struct { + Address proto.Address + }{ + Address: address, + } + mock.locksetNewDAppAddress.Lock() + mock.calls.setNewDAppAddress = append(mock.calls.setNewDAppAddress, callInfo) + mock.locksetNewDAppAddress.Unlock() + mock.setNewDAppAddressFunc(address) +} + +// setNewDAppAddressCalls gets all the calls that were made to setNewDAppAddress. +// Check the length with: +// len(mockedEnvironment.setNewDAppAddressCalls()) +func (mock *MockRideEnvironment) setNewDAppAddressCalls() []struct { + Address proto.Address +} { + var calls []struct { + Address proto.Address + } + mock.locksetNewDAppAddress.RLock() + calls = mock.calls.setNewDAppAddress + mock.locksetNewDAppAddress.RUnlock() + return calls +} + // state calls stateFunc. func (mock *MockRideEnvironment) state() types.SmartState { if mock.stateFunc == nil { - panic("MockRideEnvironment.stateFunc: method is nil but RideEnvironment.state was just called") + panic("MockRideEnvironment.stateFunc: method is nil but Environment.state was just called") } callInfo := struct { }{} @@ -272,7 +419,7 @@ func (mock *MockRideEnvironment) state() types.SmartState { // stateCalls gets all the calls that were made to state. // Check the length with: -// len(mockedRideEnvironment.stateCalls()) +// len(mockedEnvironment.stateCalls()) func (mock *MockRideEnvironment) stateCalls() []struct { } { var calls []struct { @@ -283,10 +430,45 @@ func (mock *MockRideEnvironment) stateCalls() []struct { return calls } +// takeString calls takeStringFunc. +func (mock *MockRideEnvironment) takeString(s string, n int) rideString { + if mock.takeStringFunc == nil { + panic("MockRideEnvironment.takeStringFunc: method is nil but Environment.takeString was just called") + } + callInfo := struct { + S string + N int + }{ + S: s, + N: n, + } + mock.locktakeString.Lock() + mock.calls.takeString = append(mock.calls.takeString, callInfo) + mock.locktakeString.Unlock() + return mock.takeStringFunc(s, n) +} + +// takeStringCalls gets all the calls that were made to takeString. +// Check the length with: +// len(mockedEnvironment.takeStringCalls()) +func (mock *MockRideEnvironment) takeStringCalls() []struct { + S string + N int +} { + var calls []struct { + S string + N int + } + mock.locktakeString.RLock() + calls = mock.calls.takeString + mock.locktakeString.RUnlock() + return calls +} + // this calls thisFunc. func (mock *MockRideEnvironment) this() rideType { if mock.thisFunc == nil { - panic("MockRideEnvironment.thisFunc: method is nil but RideEnvironment.this was just called") + panic("MockRideEnvironment.thisFunc: method is nil but Environment.this was just called") } callInfo := struct { }{} @@ -298,7 +480,7 @@ func (mock *MockRideEnvironment) this() rideType { // thisCalls gets all the calls that were made to this. // Check the length with: -// len(mockedRideEnvironment.thisCalls()) +// len(mockedEnvironment.thisCalls()) func (mock *MockRideEnvironment) thisCalls() []struct { } { var calls []struct { @@ -309,10 +491,36 @@ func (mock *MockRideEnvironment) thisCalls() []struct { return calls } +// timestamp calls timestampFunc. +func (mock *MockRideEnvironment) timestamp() uint64 { + if mock.timestampFunc == nil { + panic("MockRideEnvironment.timestampFunc: method is nil but Environment.timestamp was just called") + } + callInfo := struct { + }{} + mock.locktimestamp.Lock() + mock.calls.timestamp = append(mock.calls.timestamp, callInfo) + mock.locktimestamp.Unlock() + return mock.timestampFunc() +} + +// timestampCalls gets all the calls that were made to timestamp. +// Check the length with: +// len(mockedEnvironment.timestampCalls()) +func (mock *MockRideEnvironment) timestampCalls() []struct { +} { + var calls []struct { + } + mock.locktimestamp.RLock() + calls = mock.calls.timestamp + mock.locktimestamp.RUnlock() + return calls +} + // transaction calls transactionFunc. func (mock *MockRideEnvironment) transaction() rideObject { if mock.transactionFunc == nil { - panic("MockRideEnvironment.transactionFunc: method is nil but RideEnvironment.transaction was just called") + panic("MockRideEnvironment.transactionFunc: method is nil but Environment.transaction was just called") } callInfo := struct { }{} @@ -324,7 +532,7 @@ func (mock *MockRideEnvironment) transaction() rideObject { // transactionCalls gets all the calls that were made to transaction. // Check the length with: -// len(mockedRideEnvironment.transactionCalls()) +// len(mockedEnvironment.transactionCalls()) func (mock *MockRideEnvironment) transactionCalls() []struct { } { var calls []struct { @@ -338,7 +546,7 @@ func (mock *MockRideEnvironment) transactionCalls() []struct { // txID calls txIDFunc. func (mock *MockRideEnvironment) txID() rideType { if mock.txIDFunc == nil { - panic("MockRideEnvironment.txIDFunc: method is nil but RideEnvironment.txID was just called") + panic("MockRideEnvironment.txIDFunc: method is nil but Environment.txID was just called") } callInfo := struct { }{} @@ -350,7 +558,7 @@ func (mock *MockRideEnvironment) txID() rideType { // txIDCalls gets all the calls that were made to txID. // Check the length with: -// len(mockedRideEnvironment.txIDCalls()) +// len(mockedEnvironment.txIDCalls()) func (mock *MockRideEnvironment) txIDCalls() []struct { } { var calls []struct { diff --git a/pkg/ride/selectors.go b/pkg/ride/selectors.go index 37869f59b..65a82dc48 100644 --- a/pkg/ride/selectors.go +++ b/pkg/ride/selectors.go @@ -10,6 +10,8 @@ func selectFunctions(v int) (func(id int) rideFunction, error) { return functionV3, nil case 4: return functionV4, nil + case 5: + return functionV5, nil default: return nil, errors.Errorf("unsupported library version '%d'", v) } @@ -23,11 +25,28 @@ func selectFunctionChecker(v int) (func(name string) (uint16, bool), error) { return checkFunctionV3, nil case 4: return checkFunctionV4, nil + case 5: + return checkFunctionV5, nil default: return nil, errors.Errorf("unsupported library version '%d'", v) } } +func selectEvaluationCostsProvider(v int) (map[string]int, map[string]struct{}, error) { + switch v { + case 1, 2: + return CatalogueV2, FreeFunctionsV2, nil + case 3: + return CatalogueV3, FreeFunctionsV3, nil + case 4: + return CatalogueV4, FreeFunctionsV4, nil + case 5: + return CatalogueV5, FreeFunctionsV5, nil + default: + return nil, nil, errors.Errorf("unsupported library version '%d'", v) + } +} + func selectFunctionNameProvider(v int) (func(int) string, error) { switch v { case 1, 2: @@ -36,24 +55,13 @@ func selectFunctionNameProvider(v int) (func(int) string, error) { return functionNameV3, nil case 4: return functionNameV4, nil + case 5: + return functionNameV5, nil default: return nil, errors.Errorf("unsupported library version '%d'", v) } } -//func selectCostProvider(v int) (func(int) int, error) { -// switch v { -// case 1, 2: -// return costV2, nil -// case 3: -// return costV3, nil -// case 4: -// return costV4, nil -// default: -// return nil, errors.Errorf("unsupported library version '%d'", v) -// } -//} -// func selectConstants(v int) (func(int) rideConstructor, error) { switch v { case 1: @@ -64,6 +72,8 @@ func selectConstants(v int) (func(int) rideConstructor, error) { return constantV3, nil case 4: return constantV4, nil + case 5: + return constantV5, nil default: return nil, errors.Errorf("unsupported library version '%d'", v) } @@ -79,6 +89,8 @@ func selectConstantsChecker(v int) (func(name string) (uint16, bool), error) { return checkConstantV3, nil case 4: return checkConstantV4, nil + case 5: + return checkConstantV5, nil default: return nil, errors.Errorf("unsupported library version '%d'", v) } diff --git a/pkg/ride/tree_estimation_test.go b/pkg/ride/tree_estimation_test.go index 017703969..da4f4fdbd 100644 --- a/pkg/ride/tree_estimation_test.go +++ b/pkg/ride/tree_estimation_test.go @@ -159,6 +159,7 @@ func TestEstimatorCommon(t *testing.T) { {`V4: 922-833`, "AAIEAAAAAAAAAAgIAhIAEgASAAAAABoAAAAADXNjcmlwdFZlcnNpb24CAAAADnYzLjA3XzIwMjAwOTEzAAAAAAdwZXJjZW50AAAAAAAAAABkAAAAAAtyaXNrUGVyY2VudAAAAAAAAAAAFAAAAAALdGVhbVBlcmNlbnQAAAAAAAAAAAoAAAAADmFkbWluUHVibGljS2V5AQAAACD/zQv9xtp+IwicmSq/7YB3qzF8dYREKcB8rX1b2hNXAwAAAAAOZnRlYW1QdWJsaWNLZXkBAAAAIIN6TMTYLvwQfnpKcKqqAAZ8882v9yZAFQ900E5yClNCAAAAAA5tbWJvdFB1YmxpY0tleQEAAAAgSqCTD7MZSfeiXlZ7r112NWe+YGAAI7co5SLZqPgB7C8AAAAACWVtcHR5TGlzdAkABEwAAAACAQAAAAAJAARMAAAAAgEAAAAACQAETAAAAAIBAAAAAAkABEwAAAACAQAAAAAJAARMAAAAAgEAAAAACQAETAAAAAIBAAAAAAkABEwAAAACAQAAAAAFAAAAA25pbAAAAAATZ3VhcmFudG9yUHVibGljS2V5cwkABE4AAAACCQAETAAAAAIBAAAAIP/NC/3G2n4jCJyZKr/tgHerMXx1hEQpwHytfVvaE1cDBQAAAANuaWwFAAAACWVtcHR5TGlzdAAAAAANZ3VhcmFudG9yU2l6ZQkAAGUAAAACCQABkAAAAAEFAAAAE2d1YXJhbnRvclB1YmxpY0tleXMJAAGQAAAAAQUAAAAJZW1wdHlMaXN0AAAAAA1taW5TaWduYXR1cmVzCQAAZAAAAAIJAABpAAAAAgUAAAANZ3VhcmFudG9yU2l6ZQAAAAAAAAAAAgkAAGoAAAACBQAAAA1ndWFyYW50b3JTaXplAAAAAAAAAAACAAAAAAlmbW10QXNzZXQBAAAAIGYr8dw8TDanuTqo+vs1Q9xNuAeFp1N2ZT91Xozrfzj0AAAAAAl4ZmVlQXNzZXQBAAAAID7aqaNufgAR8AeMAT3F3i6NRzE7nRhBON4sOuYerrY3AAAAAAlwb3J0Zm9saW8JAARNAAAAAgkABE0AAAACCQAETAAAAAIBAAAAIB6UBxNSdqEllf3IYaiCXxB/3zpPKbv8mkY/Wv02T5+RCQAETAAAAAIBAAAAIGz6av/F7aqMC3+1KpPSogwvgoLbdHoEjFP7/RMfc6D/CQAETAAAAAIFAAAABHVuaXQJAARMAAAAAgEAAAAgLiDD9uqKn4lRu7/oiBETNux+2MJCA3JlDVjNcyZCZYIJAARMAAAAAgEAAAAgDrECagw+n0f35EaU5062t7xDfH5ladDpGJsi5gny6M4JAARMAAAAAgEAAAAg9h42QtOX3fJaWBUg7iwP2i1GBoqANpKuVYlZnrDFLKEJAARMAAAAAgEAAAAglVMgFzLH9/gxbVKojbVZ08/r8nPtlHFX5Z0m586HauAJAARMAAAAAgEAAAAgQxj0G3VSMI+7+iJkvwQoTrekocmcbhiCndEGv8vAJAIJAARMAAAAAgEAAAAgoVJa1UnWcbrDrx+GyZJ/6g+KWhwfmKQrcwaOzJr+1WcFAAAAA25pbAUAAAAJeGZlZUFzc2V0BQAAAAlmbW10QXNzZXQAAAAABWFkbWluCQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXyvBTGJ3PniBi4dPVWqjby+gPf9AH2sQ1AAAAAAVmdGVhbQkBAAAAB0FkZHJlc3MAAAABAQAAABoBVxC7GUc6JOl3erhvhB+nL92RfEkunZJulwAAAAAFZmRhcHAJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVeUGM4qgYZsQxeQti8+oFzAKUNnZKGyBg0AAAAACmhlZGdlRnVuZHMJAABlAAAAAggJAQAAAAV2YWx1ZQAAAAEJAAPsAAAAAQUAAAAJZm1tdEFzc2V0AAAACHF1YW50aXR5CQAAZAAAAAIJAABkAAAAAgkAA/AAAAACBQAAAAR0aGlzBQAAAAlmbW10QXNzZXQJAAPwAAAAAgUAAAAFZnRlYW0FAAAACWZtbXRBc3NldAkAA/AAAAACBQAAAAVmZGFwcAUAAAAJZm1tdEFzc2V0AAAAABJ0ZWFtUGF5b3V0c0RhdGFLZXkCAAAAC3RlYW1QYXlvdXRzAAAAABRzY3JpcHRWZXJzaW9uRGF0YUtleQIAAAANc2NyaXB0VmVyc2lvbgAAAAAQdGltZXN0YW1wRGF0YUtleQIAAAAJdGltZXN0YW1wAAAAABFsYXN0QWN0aW9uRGF0YUtleQIAAAAKbGFzdEFjdGlvbgAAAAALZGFwcERhdGFLZXkJAAJYAAAAAQgFAAAABHRoaXMAAAAFYnl0ZXMAAAAAE2lzQ29udHJhY3RTdXNwZW5kZWQJAQAAAAEhAAAAAQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBsAAAACBQAAAAVhZG1pbgUAAAALZGFwcERhdGFLZXkHAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEAAAAFYXNzZXQKAQAAAA9pc0Fzc2V0RGlzYWJsZWQAAAABAAAADGFzc2V0RGF0YUtleQkBAAAAASEAAAABCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGwAAAAIFAAAABWFkbWluBQAAAAxhc3NldERhdGFLZXkHCgEAAAAKZGlmZmVyZW5jZQAAAAIAAAAMZmNvbGRCYWxhbmNlAAAADGZkYXBwQmFsYW5jZQkAAGUAAAACCQAAawAAAAMJAABkAAAAAgUAAAAMZmNvbGRCYWxhbmNlBQAAAAxmZGFwcEJhbGFuY2UFAAAAC3Jpc2tQZXJjZW50BQAAAAdwZXJjZW50BQAAAAxmZGFwcEJhbGFuY2UEAAAABmFtb3VudAQAAAAHJG1hdGNoMAUAAAAFYXNzZXQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAmlkBQAAAAckbWF0Y2gwAwkBAAAAD2lzQXNzZXREaXNhYmxlZAAAAAEJAAJYAAAAAQUAAAACaWQAAAAAAAAAAAAJAQAAAApkaWZmZXJlbmNlAAAAAgkAA/AAAAACBQAAAAR0aGlzBQAAAAJpZAkAA/AAAAACBQAAAAVmZGFwcAUAAAACaWQDCQEAAAAPaXNBc3NldERpc2FibGVkAAAAAQIAAAAFV0FWRVMAAAAAAAAAAAAJAQAAAApkaWZmZXJlbmNlAAAAAggJAAPvAAAAAQUAAAAEdGhpcwAAAAdyZWd1bGFyCAkAA+8AAAABBQAAAAVmZGFwcAAAAAdyZWd1bGFyAwkAAGYAAAACBQAAAAZhbW91bnQAAAAAAAAAAAAJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAFZmRhcHAFAAAABmFtb3VudAUAAAAFYXNzZXQFAAAAA25pbAUAAAADbmlsAQAAABBnZXRTY3JpcHRWZXJzaW9uAAAAAAQAAAAQb2xkU2NyaXB0VmVyc2lvbgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAABRzY3JpcHRWZXJzaW9uRGF0YUtleQIAAAAAAwkAAAAAAAACBQAAABBvbGRTY3JpcHRWZXJzaW9uBQAAAA1zY3JpcHRWZXJzaW9uBQAAAANuaWwJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAUc2NyaXB0VmVyc2lvbkRhdGFLZXkFAAAADXNjcmlwdFZlcnNpb24FAAAAA25pbAAAAAMAAAABaQEAAAANYXV0b1JlYmFsYW5jZQAAAAAEAAAAE2xhc3RBY3Rpb25EYXRhVmFsdWUCAAAADWF1dG9SZWJhbGFuY2UDBQAAABNpc0NvbnRyYWN0U3VzcGVuZGVkCQAAAgAAAAECAAAALVRoZSBhZG1pbmlzdHJhdG9yIGhhcyBzdXNwZW5kZWQgdGhlIGNvbnRyYWN0IQMDCQEAAAACIT0AAAACCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAADmFkbWluUHVibGljS2V5CQEAAAACIT0AAAACCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAADm1tYm90UHVibGljS2V5BwkAAAIAAAABAgAAADFPbmx5IHRoZSBhZG1pbmlzdHJhdG9yIGNhbiBwZXJmb3JtIHRoaXMgZnVuY3Rpb24hAwkAAGYAAAACCQABkAAAAAEIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAACQAAAgAAAAECAAAAMkRvbid0IGF0dGFjaCBwYXltZW50IHdoZW4gY2FsbGluZyB0aGlzIGZ1bmN0aW9uLi4uBAAAAA9zY3JpcHRUcmFuc2ZlcnMJAAROAAAAAgkABE4AAAACCQAETgAAAAIJAAROAAAAAgkABE4AAAACCQAETgAAAAIJAAROAAAAAgkABE4AAAACCQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAAAAkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAEJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAACCQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAAAwkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAQJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAAFCQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAABgkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAcJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAAIAwkAAGYAAAACCQABkAAAAAEFAAAAD3NjcmlwdFRyYW5zZmVycwAAAAAAAAAAAAkABE0AAAACCQAETQAAAAIJAAROAAAAAgUAAAAPc2NyaXB0VHJhbnNmZXJzCQEAAAAQZ2V0U2NyaXB0VmVyc2lvbgAAAAAJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEWxhc3RBY3Rpb25EYXRhS2V5BQAAABNsYXN0QWN0aW9uRGF0YVZhbHVlCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAQdGltZXN0YW1wRGF0YUtleQgFAAAACWxhc3RCbG9jawAAAAl0aW1lc3RhbXAJAAACAAAAAQIAAAA1Tm8gdHJhbnNmZXJzIGF2YWlsYWJsZS4gV2FpdCB1bnRpbCBpbWJhbGFuY2UgYXBwZWFycy4AAAABaQEAAAAPc2VuZFRlYW1QYXlvdXRzAAAAAAQAAAATbGFzdEFjdGlvbkRhdGFWYWx1ZQIAAAAPc2VuZFRlYW1QYXlvdXRzAwUAAAATaXNDb250cmFjdFN1c3BlbmRlZAkAAAIAAAABAgAAAC1UaGUgYWRtaW5pc3RyYXRvciBoYXMgc3VzcGVuZGVkIHRoZSBjb250cmFjdCEDAwkBAAAAAiE9AAAAAggFAAAAAWkAAAAPY2FsbGVyUHVibGljS2V5BQAAAA5hZG1pblB1YmxpY0tleQkBAAAAAiE9AAAAAggFAAAAAWkAAAAPY2FsbGVyUHVibGljS2V5BQAAAA5mdGVhbVB1YmxpY0tleQcJAAACAAAAAQIAAAAxT25seSB0aGUgYWRtaW5pc3RyYXRvciBjYW4gcGVyZm9ybSB0aGlzIGZ1bmN0aW9uIQMJAABmAAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAkAAAIAAAABAgAAADJEb24ndCBhdHRhY2ggcGF5bWVudCB3aGVuIGNhbGxpbmcgdGhpcyBmdW5jdGlvbi4uLgQAAAAOb2xkVGVhbVBheW91dHMJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAASdGVhbVBheW91dHNEYXRhS2V5AAAAAAAAAAAABAAAAAt0ZWFtUGF5b3V0cwkAAGUAAAACCQAAawAAAAMFAAAACmhlZGdlRnVuZHMFAAAAC3RlYW1QZXJjZW50BQAAAAdwZXJjZW50BQAAAA5vbGRUZWFtUGF5b3V0cwMJAABmAAAAAgUAAAALdGVhbVBheW91dHMAAAAAAAAAAAAJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAFZnRlYW0FAAAAC3RlYW1QYXlvdXRzBQAAAAlmbW10QXNzZXQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEnRlYW1QYXlvdXRzRGF0YUtleQkAAGQAAAACBQAAAA5vbGRUZWFtUGF5b3V0cwUAAAALdGVhbVBheW91dHMJAARNAAAAAgkABE0AAAACCQEAAAAQZ2V0U2NyaXB0VmVyc2lvbgAAAAAJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEWxhc3RBY3Rpb25EYXRhS2V5BQAAABNsYXN0QWN0aW9uRGF0YVZhbHVlCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAQdGltZXN0YW1wRGF0YUtleQgFAAAACWxhc3RCbG9jawAAAAl0aW1lc3RhbXAJAAACAAAAAQIAAAA4Tm8gcGF5bWVudHMgYXZhaWxhYmxlLiBXYWl0IGZvciBuZXcgaW52ZXN0bWVudHMgdG8gY29tZS4AAAABaQEAAAAQc2V0U2NyaXB0VmVyc2lvbgAAAAAEAAAAE2xhc3RBY3Rpb25EYXRhVmFsdWUCAAAAEHNldFNjcmlwdFZlcnNpb24DBQAAABNpc0NvbnRyYWN0U3VzcGVuZGVkCQAAAgAAAAECAAAALVRoZSBhZG1pbmlzdHJhdG9yIGhhcyBzdXNwZW5kZWQgdGhlIGNvbnRyYWN0IQMJAQAAAAIhPQAAAAIIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQUAAAAOYWRtaW5QdWJsaWNLZXkJAAACAAAAAQIAAAAxT25seSB0aGUgYWRtaW5pc3RyYXRvciBjYW4gcGVyZm9ybSB0aGlzIGZ1bmN0aW9uIQMJAABmAAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAkAAAIAAAABAgAAADJEb24ndCBhdHRhY2ggcGF5bWVudCB3aGVuIGNhbGxpbmcgdGhpcyBmdW5jdGlvbi4uLgQAAAAQb2xkU2NyaXB0VmVyc2lvbgkBAAAAEGdldFNjcmlwdFZlcnNpb24AAAAAAwkAAGYAAAACCQABkAAAAAEFAAAAEG9sZFNjcmlwdFZlcnNpb24AAAAAAAAAAAAJAARNAAAAAgkABE0AAAACBQAAABBvbGRTY3JpcHRWZXJzaW9uCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABFsYXN0QWN0aW9uRGF0YUtleQUAAAATbGFzdEFjdGlvbkRhdGFWYWx1ZQkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEHRpbWVzdGFtcERhdGFLZXkIBQAAAAlsYXN0QmxvY2sAAAAJdGltZXN0YW1wCQAAAgAAAAEJAAEsAAAAAgIAAAAtVGhlIHNjcmlwdCB2ZXJzaW9uIGhhcyBhbHJlYWR5IGJlZW4gdXBkYXRlZDogBQAAAA1zY3JpcHRWZXJzaW9uAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAQAAAAMaXNWYWxpZE93bmVyCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tleQQAAAAMaXNWYWxpZEFkbWluAwUAAAAMaXNWYWxpZE93bmVyBgkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAEFAAAADmFkbWluUHVibGljS2V5BAAAAAxpc1ZhbGlkTU1Cb3QDBQAAAAxpc1ZhbGlkT3duZXIGCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQUAAAAObW1ib3RQdWJsaWNLZXkEAAAAEWlzVmFsaWRHdWFyYW50b3JzCQAAZwAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgMJAAnFAAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAABCQABkQAAAAIFAAAAE2d1YXJhbnRvclB1YmxpY0tleXMAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAADCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAgkAAZEAAAACBQAAABNndWFyYW50b3JQdWJsaWNLZXlzAAAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAwkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAMJAAGRAAAAAgUAAAATZ3VhcmFudG9yUHVibGljS2V5cwAAAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAAMJAAnFAAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAECQABkQAAAAIFAAAAE2d1YXJhbnRvclB1YmxpY0tleXMAAAAAAAAAAAMAAAAAAAAAAAEAAAAAAAAAAAADCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAABQkAAZEAAAACBQAAABNndWFyYW50b3JQdWJsaWNLZXlzAAAAAAAAAAAEAAAAAAAAAAABAAAAAAAAAAAABQAAAA1taW5TaWduYXR1cmVzBAAAAAckbWF0Y2gwBQAAAAJ0eAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAPQnVyblRyYW5zYWN0aW9uBAAAAAFiBQAAAAckbWF0Y2gwAwUAAAAMaXNWYWxpZE93bmVyCQEAAAABIQAAAAEJAQAAAA9jb250YWluc0VsZW1lbnQAAAACBQAAAAlwb3J0Zm9saW8IBQAAAAFiAAAAB2Fzc2V0SWQHAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAVPcmRlcgQAAAABbwUAAAAHJG1hdGNoMAMFAAAADGlzVmFsaWRPd25lcgMDCQAAAAAAAAIIBQAAAAFvAAAACW9yZGVyVHlwZQUAAAADQnV5CQEAAAABIQAAAAEJAQAAAA9jb250YWluc0VsZW1lbnQAAAACBQAAAAlwb3J0Zm9saW8ICAUAAAABbwAAAAlhc3NldFBhaXIAAAAKcHJpY2VBc3NldAcGAwkAAAAAAAACCAUAAAABbwAAAAlvcmRlclR5cGUFAAAABFNlbGwJAQAAAAEhAAAAAQkBAAAAD2NvbnRhaW5zRWxlbWVudAAAAAIFAAAACXBvcnRmb2xpbwgIBQAAAAFvAAAACWFzc2V0UGFpcgAAAAthbW91bnRBc3NldAcHAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNUcmFuc2ZlclRyYW5zYWN0aW9uBAAAAAF0BQAAAAckbWF0Y2gwAwkBAAAAASEAAAABBQAAABNpc0NvbnRyYWN0U3VzcGVuZGVkAwMDAwUAAAAMaXNWYWxpZE93bmVyCQAAAAAAAAIIBQAAAAF0AAAACmZlZUFzc2V0SWQFAAAACXhmZWVBc3NldAcJAQAAAAEhAAAAAQkBAAAAD2NvbnRhaW5zRWxlbWVudAAAAAIFAAAACXBvcnRmb2xpbwgFAAAAAXQAAAAHYXNzZXRJZAcGAwMDBQAAAAxpc1ZhbGlkQWRtaW4JAAAAAAAAAggFAAAAAXQAAAAHYXNzZXRJZAUAAAAJZm1tdEFzc2V0BwkAAAAAAAACCAUAAAABdAAAAApmZWVBc3NldElkBQAAAAl4ZmVlQXNzZXQHCQAAAAAAAAIJAAQkAAAAAQgFAAAAAXQAAAAJcmVjaXBpZW50BQAAAAVmZGFwcAcGAwMDAwUAAAARaXNWYWxpZEd1YXJhbnRvcnMJAQAAAAIhPQAAAAIIBQAAAAF0AAAAB2Fzc2V0SWQFAAAACWZtbXRBc3NldAcJAQAAAAIhPQAAAAIIBQAAAAF0AAAAB2Fzc2V0SWQFAAAACXhmZWVBc3NldAcJAQAAAA9jb250YWluc0VsZW1lbnQAAAACBQAAAAlwb3J0Zm9saW8IBQAAAAF0AAAAB2Fzc2V0SWQHCQAAAAAAAAIJAAQkAAAAAQgFAAAAAXQAAAAJcmVjaXBpZW50BQAAAAVmZGFwcAcHAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABBMZWFzZVRyYW5zYWN0aW9uBAAAAAFsBQAAAAckbWF0Y2gwBQAAAAxpc1ZhbGlkTU1Cb3QDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAFkxlYXNlQ2FuY2VsVHJhbnNhY3Rpb24DBQAAAAxpc1ZhbGlkTU1Cb3QGBQAAABFpc1ZhbGlkR3VhcmFudG9ycwMDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAF0ludm9rZVNjcmlwdFRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAUU2V0U2NyaXB0VHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgMFAAAADGlzVmFsaWRBZG1pbgUAAAARaXNWYWxpZEd1YXJhbnRvcnMHB9AmlPU=", 1699, 1708, 833}, {`V4: 922-802`, "AAIEAAAAAAAAAAgIAhIAEgASAAAAABkAAAAADXNjcmlwdFZlcnNpb24CAAAADnYzLjA1XzIwMjAwOTEzAAAAAAdwZXJjZW50AAAAAAAAAABkAAAAAAtyaXNrUGVyY2VudAAAAAAAAAAAFAAAAAALdGVhbVBlcmNlbnQAAAAAAAAAAAoAAAAADmFkbWluUHVibGljS2V5AQAAACD/zQv9xtp+IwicmSq/7YB3qzF8dYREKcB8rX1b2hNXAwAAAAAOZnRlYW1QdWJsaWNLZXkBAAAAIIN6TMTYLvwQfnpKcKqqAAZ8882v9yZAFQ900E5yClNCAAAAAA5tbWJvdFB1YmxpY0tleQEAAAAgSqCTD7MZSfeiXlZ7r112NWe+YGAAI7co5SLZqPgB7C8AAAAACWVtcHR5TGlzdAkABEwAAAACAQAAAAAJAARMAAAAAgEAAAAACQAETAAAAAIBAAAAAAkABEwAAAACAQAAAAAJAARMAAAAAgEAAAAACQAETAAAAAIBAAAAAAkABEwAAAACAQAAAAAFAAAAA25pbAAAAAATZ3VhcmFudG9yUHVibGljS2V5cwkABE4AAAACCQAETAAAAAIBAAAAIP/NC/3G2n4jCJyZKr/tgHerMXx1hEQpwHytfVvaE1cDBQAAAANuaWwFAAAACWVtcHR5TGlzdAAAAAANZ3VhcmFudG9yU2l6ZQkAAGUAAAACCQABkAAAAAEFAAAAE2d1YXJhbnRvclB1YmxpY0tleXMJAAGQAAAAAQUAAAAJZW1wdHlMaXN0AAAAAA1taW5TaWduYXR1cmVzCQAAZAAAAAIJAABpAAAAAgUAAAANZ3VhcmFudG9yU2l6ZQAAAAAAAAAAAgkAAGoAAAACBQAAAA1ndWFyYW50b3JTaXplAAAAAAAAAAACAAAAAAlmbW10QXNzZXQBAAAAIGYr8dw8TDanuTqo+vs1Q9xNuAeFp1N2ZT91Xozrfzj0AAAAAAl4ZmVlQXNzZXQBAAAAID7aqaNufgAR8AeMAT3F3i6NRzE7nRhBON4sOuYerrY3AAAAAAlwb3J0Zm9saW8JAARNAAAAAgkABE0AAAACCQAETAAAAAIBAAAAIB6UBxNSdqEllf3IYaiCXxB/3zpPKbv8mkY/Wv02T5+RCQAETAAAAAIBAAAAIGz6av/F7aqMC3+1KpPSogwvgoLbdHoEjFP7/RMfc6D/CQAETAAAAAIFAAAABHVuaXQJAARMAAAAAgEAAAAgLiDD9uqKn4lRu7/oiBETNux+2MJCA3JlDVjNcyZCZYIJAARMAAAAAgEAAAAgDrECagw+n0f35EaU5062t7xDfH5ladDpGJsi5gny6M4JAARMAAAAAgEAAAAg9h42QtOX3fJaWBUg7iwP2i1GBoqANpKuVYlZnrDFLKEJAARMAAAAAgEAAAAglVMgFzLH9/gxbVKojbVZ08/r8nPtlHFX5Z0m586HauAJAARMAAAAAgEAAAAgQxj0G3VSMI+7+iJkvwQoTrekocmcbhiCndEGv8vAJAIJAARMAAAAAgEAAAAgoVJa1UnWcbrDrx+GyZJ/6g+KWhwfmKQrcwaOzJr+1WcFAAAAA25pbAUAAAAJeGZlZUFzc2V0BQAAAAlmbW10QXNzZXQAAAAABWFkbWluCQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXyvBTGJ3PniBi4dPVWqjby+gPf9AH2sQ1AAAAAAVmdGVhbQkBAAAAB0FkZHJlc3MAAAABAQAAABoBVxC7GUc6JOl3erhvhB+nL92RfEkunZJulwAAAAAFZmRhcHAJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVeUGM4qgYZsQxeQti8+oFzAKUNnZKGyBg0AAAAACmhlZGdlRnVuZHMJAABlAAAAAggJAQAAAAV2YWx1ZQAAAAEJAAPsAAAAAQUAAAAJZm1tdEFzc2V0AAAACHF1YW50aXR5CQAAZAAAAAIJAABkAAAAAgkAA/AAAAACBQAAAAR0aGlzBQAAAAlmbW10QXNzZXQJAAPwAAAAAgUAAAAFZnRlYW0FAAAACWZtbXRBc3NldAkAA/AAAAACBQAAAAVmZGFwcAUAAAAJZm1tdEFzc2V0AAAAABJ0ZWFtUGF5b3V0c0RhdGFLZXkCAAAAC3RlYW1QYXlvdXRzAAAAABRzY3JpcHRWZXJzaW9uRGF0YUtleQIAAAANc2NyaXB0VmVyc2lvbgAAAAAQdGltZXN0YW1wRGF0YUtleQIAAAAJdGltZXN0YW1wAAAAABFsYXN0QWN0aW9uRGF0YUtleQIAAAAKbGFzdEFjdGlvbgAAAAALZGFwcERhdGFLZXkJAAJYAAAAAQgFAAAABHRoaXMAAAAFYnl0ZXMAAAAAE2lzQ29udHJhY3RTdXNwZW5kZWQJAQAAAAEhAAAAAQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBsAAAACBQAAAAVhZG1pbgUAAAALZGFwcERhdGFLZXkHAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEAAAAFYXNzZXQKAQAAAA9pc0Fzc2V0RGlzYWJsZWQAAAABAAAADGFzc2V0RGF0YUtleQkBAAAAASEAAAABCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGwAAAAIFAAAABWFkbWluBQAAAAxhc3NldERhdGFLZXkHCgEAAAAKZGlmZmVyZW5jZQAAAAIAAAAMZmNvbGRCYWxhbmNlAAAADGZkYXBwQmFsYW5jZQkAAGUAAAACCQAAawAAAAMJAABkAAAAAgUAAAAMZmNvbGRCYWxhbmNlBQAAAAxmZGFwcEJhbGFuY2UFAAAAC3Jpc2tQZXJjZW50BQAAAAdwZXJjZW50BQAAAAxmZGFwcEJhbGFuY2UEAAAABmFtb3VudAQAAAAHJG1hdGNoMAUAAAAFYXNzZXQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAmlkBQAAAAckbWF0Y2gwAwkBAAAAD2lzQXNzZXREaXNhYmxlZAAAAAEJAAJYAAAAAQUAAAACaWQAAAAAAAAAAAAJAQAAAApkaWZmZXJlbmNlAAAAAgkAA/AAAAACBQAAAAR0aGlzBQAAAAJpZAkAA/AAAAACBQAAAAVmZGFwcAUAAAACaWQDCQEAAAAPaXNBc3NldERpc2FibGVkAAAAAQIAAAAFV0FWRVMAAAAAAAAAAAAJAQAAAApkaWZmZXJlbmNlAAAAAggJAAPvAAAAAQUAAAAEdGhpcwAAAAdyZWd1bGFyCAkAA+8AAAABBQAAAAVmZGFwcAAAAAdyZWd1bGFyAwkAAGYAAAACBQAAAAZhbW91bnQAAAAAAAAAAAAJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAFZmRhcHAFAAAABmFtb3VudAUAAAAFYXNzZXQFAAAAA25pbAUAAAADbmlsAAAAAwAAAAFpAQAAAA1hdXRvUmViYWxhbmNlAAAAAAQAAAATbGFzdEFjdGlvbkRhdGFWYWx1ZQIAAAANYXV0b1JlYmFsYW5jZQMFAAAAE2lzQ29udHJhY3RTdXNwZW5kZWQJAAACAAAAAQIAAAAtVGhlIGFkbWluaXN0cmF0b3IgaGFzIHN1c3BlbmRlZCB0aGUgY29udHJhY3QhAwMJAQAAAAIhPQAAAAIIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQUAAAAOYWRtaW5QdWJsaWNLZXkJAQAAAAIhPQAAAAIIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQUAAAAObW1ib3RQdWJsaWNLZXkHCQAAAgAAAAECAAAAMU9ubHkgdGhlIGFkbWluaXN0cmF0b3IgY2FuIHBlcmZvcm0gdGhpcyBmdW5jdGlvbiEDCQAAZgAAAAIJAAGQAAAAAQgFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAJAAACAAAAAQIAAAAyRG9uJ3QgYXR0YWNoIHBheW1lbnQgd2hlbiBjYWxsaW5nIHRoaXMgZnVuY3Rpb24uLi4EAAAAD3NjcmlwdFRyYW5zZmVycwkABE4AAAACCQAETgAAAAIJAAROAAAAAgkABE4AAAACCQAETgAAAAIJAAROAAAAAgkABE4AAAACCQAETgAAAAIJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAAACQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAAAQkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAIJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAADCQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAABAkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAUJAQAAABFnZXRTY3JpcHRUcmFuc2ZlcgAAAAEJAAGRAAAAAgUAAAAJcG9ydGZvbGlvAAAAAAAAAAAGCQEAAAARZ2V0U2NyaXB0VHJhbnNmZXIAAAABCQABkQAAAAIFAAAACXBvcnRmb2xpbwAAAAAAAAAABwkBAAAAEWdldFNjcmlwdFRyYW5zZmVyAAAAAQkAAZEAAAACBQAAAAlwb3J0Zm9saW8AAAAAAAAAAAgDCQAAZgAAAAIJAAGQAAAAAQUAAAAPc2NyaXB0VHJhbnNmZXJzAAAAAAAAAAAACQAETQAAAAIJAARNAAAAAgUAAAAPc2NyaXB0VHJhbnNmZXJzCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAQdGltZXN0YW1wRGF0YUtleQgFAAAACWxhc3RCbG9jawAAAAl0aW1lc3RhbXAJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEWxhc3RBY3Rpb25EYXRhS2V5BQAAABNsYXN0QWN0aW9uRGF0YVZhbHVlCQAAAgAAAAECAAAANU5vIHRyYW5zZmVycyBhdmFpbGFibGUuIFdhaXQgdW50aWwgaW1iYWxhbmNlIGFwcGVhcnMuAAAAAWkBAAAADmdldFRlYW1QYXlvdXRzAAAAAAQAAAATbGFzdEFjdGlvbkRhdGFWYWx1ZQIAAAAOZ2V0VGVhbVBheW91dHMDBQAAABNpc0NvbnRyYWN0U3VzcGVuZGVkCQAAAgAAAAECAAAALVRoZSBhZG1pbmlzdHJhdG9yIGhhcyBzdXNwZW5kZWQgdGhlIGNvbnRyYWN0IQMDCQEAAAACIT0AAAACCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAADmFkbWluUHVibGljS2V5CQEAAAACIT0AAAACCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAADmZ0ZWFtUHVibGljS2V5BwkAAAIAAAABAgAAADFPbmx5IHRoZSBhZG1pbmlzdHJhdG9yIGNhbiBwZXJmb3JtIHRoaXMgZnVuY3Rpb24hAwkAAGYAAAACCQABkAAAAAEIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAACQAAAgAAAAECAAAAMkRvbid0IGF0dGFjaCBwYXltZW50IHdoZW4gY2FsbGluZyB0aGlzIGZ1bmN0aW9uLi4uBAAAAApvbGRQYXlvdXRzCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAEnRlYW1QYXlvdXRzRGF0YUtleQAAAAAAAAAAAAQAAAAGYW1vdW50CQAAZQAAAAIJAABrAAAAAwUAAAAKaGVkZ2VGdW5kcwUAAAALdGVhbVBlcmNlbnQFAAAAB3BlcmNlbnQFAAAACm9sZFBheW91dHMDCQAAZgAAAAIFAAAABmFtb3VudAAAAAAAAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAASdGVhbVBheW91dHNEYXRhS2V5CQAAZAAAAAIFAAAACm9sZFBheW91dHMFAAAABmFtb3VudAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAVmdGVhbQUAAAAGYW1vdW50BQAAAAlmbW10QXNzZXQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEHRpbWVzdGFtcERhdGFLZXkIBQAAAAlsYXN0QmxvY2sAAAAJdGltZXN0YW1wCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEWxhc3RBY3Rpb25EYXRhS2V5BQAAABNsYXN0QWN0aW9uRGF0YVZhbHVlBQAAAANuaWwJAAACAAAAAQIAAAA4Tm8gcGF5bWVudHMgYXZhaWxhYmxlLiBXYWl0IGZvciBuZXcgaW52ZXN0bWVudHMgdG8gY29tZS4AAAABaQEAAAAQc2V0U2NyaXB0VmVyc2lvbgAAAAAEAAAAE2xhc3RBY3Rpb25EYXRhVmFsdWUCAAAAEHNldFNjcmlwdFZlcnNpb24DBQAAABNpc0NvbnRyYWN0U3VzcGVuZGVkCQAAAgAAAAECAAAALVRoZSBhZG1pbmlzdHJhdG9yIGhhcyBzdXNwZW5kZWQgdGhlIGNvbnRyYWN0IQMJAQAAAAIhPQAAAAIIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQUAAAAOYWRtaW5QdWJsaWNLZXkJAAACAAAAAQIAAAAxT25seSB0aGUgYWRtaW5pc3RyYXRvciBjYW4gcGVyZm9ybSB0aGlzIGZ1bmN0aW9uIQMJAABmAAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAkAAAIAAAABAgAAADJEb24ndCBhdHRhY2ggcGF5bWVudCB3aGVuIGNhbGxpbmcgdGhpcyBmdW5jdGlvbi4uLgQAAAAKb2xkVmVyc2lvbgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAABRzY3JpcHRWZXJzaW9uRGF0YUtleQIAAAAAAwkBAAAAAiE9AAAAAgUAAAAKb2xkVmVyc2lvbgUAAAANc2NyaXB0VmVyc2lvbgkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABRzY3JpcHRWZXJzaW9uRGF0YUtleQUAAAANc2NyaXB0VmVyc2lvbgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAQdGltZXN0YW1wRGF0YUtleQgFAAAACWxhc3RCbG9jawAAAAl0aW1lc3RhbXAJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAARbGFzdEFjdGlvbkRhdGFLZXkFAAAAE2xhc3RBY3Rpb25EYXRhVmFsdWUFAAAAA25pbAkAAAIAAAABCQABLAAAAAICAAAALVRoZSBzY3JpcHQgdmVyc2lvbiBoYXMgYWxyZWFkeSBiZWVuIHVwZGF0ZWQ6IAUAAAAKb2xkVmVyc2lvbgAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAEAAAADGlzVmFsaWRPd25lcgkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAAIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXkEAAAADGlzVmFsaWRBZG1pbgMFAAAADGlzVmFsaWRPd25lcgYJAAnFAAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAABBQAAAA5hZG1pblB1YmxpY0tleQQAAAAMaXNWYWxpZE1NQm90AwUAAAAMaXNWYWxpZE93bmVyBgkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAEFAAAADm1tYm90UHVibGljS2V5BAAAABFpc1ZhbGlkR3VhcmFudG9ycwkAAGcAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIDCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQkAAZEAAAACBQAAABNndWFyYW50b3JQdWJsaWNLZXlzAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAwkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAIJAAGRAAAAAgUAAAATZ3VhcmFudG9yUHVibGljS2V5cwAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAAAAAMJAAnFAAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAADCQABkQAAAAIFAAAAE2d1YXJhbnRvclB1YmxpY0tleXMAAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAADCQAJxQAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAABAkAAZEAAAACBQAAABNndWFyYW50b3JQdWJsaWNLZXlzAAAAAAAAAAADAAAAAAAAAAABAAAAAAAAAAAAAwkACcUAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAUJAAGRAAAAAgUAAAATZ3VhcmFudG9yUHVibGljS2V5cwAAAAAAAAAABAAAAAAAAAAAAQAAAAAAAAAAAAUAAAANbWluU2lnbmF0dXJlcwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0J1cm5UcmFuc2FjdGlvbgQAAAABYgUAAAAHJG1hdGNoMAMFAAAADGlzVmFsaWRPd25lcgkBAAAAASEAAAABCQEAAAAPY29udGFpbnNFbGVtZW50AAAAAgUAAAAJcG9ydGZvbGlvCAUAAAABYgAAAAdhc3NldElkBwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAFT3JkZXIEAAAAAW8FAAAAByRtYXRjaDADBQAAAAxpc1ZhbGlkT3duZXIDAwkAAAAAAAACCAUAAAABbwAAAAlvcmRlclR5cGUFAAAAA0J1eQkBAAAAASEAAAABCQEAAAAPY29udGFpbnNFbGVtZW50AAAAAgUAAAAJcG9ydGZvbGlvCAgFAAAAAW8AAAAJYXNzZXRQYWlyAAAACnByaWNlQXNzZXQHBgMJAAAAAAAAAggFAAAAAW8AAAAJb3JkZXJUeXBlBQAAAARTZWxsCQEAAAABIQAAAAEJAQAAAA9jb250YWluc0VsZW1lbnQAAAACBQAAAAlwb3J0Zm9saW8ICAUAAAABbwAAAAlhc3NldFBhaXIAAAALYW1vdW50QXNzZXQHBwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAATVHJhbnNmZXJUcmFuc2FjdGlvbgQAAAABdAUAAAAHJG1hdGNoMAMJAQAAAAEhAAAAAQUAAAATaXNDb250cmFjdFN1c3BlbmRlZAMDAwMFAAAADGlzVmFsaWRPd25lcgkAAAAAAAACCAUAAAABdAAAAApmZWVBc3NldElkBQAAAAl4ZmVlQXNzZXQHCQEAAAABIQAAAAEJAQAAAA9jb250YWluc0VsZW1lbnQAAAACBQAAAAlwb3J0Zm9saW8IBQAAAAF0AAAAB2Fzc2V0SWQHBgMDAwUAAAAMaXNWYWxpZEFkbWluCQAAAAAAAAIIBQAAAAF0AAAAB2Fzc2V0SWQFAAAACWZtbXRBc3NldAcJAAAAAAAAAggFAAAAAXQAAAAKZmVlQXNzZXRJZAUAAAAJeGZlZUFzc2V0BwkAAAAAAAACCQAEJAAAAAEIBQAAAAF0AAAACXJlY2lwaWVudAUAAAAFZmRhcHAHBgMDAwMFAAAAEWlzVmFsaWRHdWFyYW50b3JzCQEAAAACIT0AAAACCAUAAAABdAAAAAdhc3NldElkBQAAAAlmbW10QXNzZXQHCQEAAAACIT0AAAACCAUAAAABdAAAAAdhc3NldElkBQAAAAl4ZmVlQXNzZXQHCQEAAAAPY29udGFpbnNFbGVtZW50AAAAAgUAAAAJcG9ydGZvbGlvCAUAAAABdAAAAAdhc3NldElkBwkAAAAAAAACCQAEJAAAAAEIBQAAAAF0AAAACXJlY2lwaWVudAUAAAAFZmRhcHAHBwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAQTGVhc2VUcmFuc2FjdGlvbgQAAAABbAUAAAAHJG1hdGNoMAUAAAAMaXNWYWxpZE1NQm90AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABZMZWFzZUNhbmNlbFRyYW5zYWN0aW9uAwUAAAAMaXNWYWxpZE1NQm90BgUAAAARaXNWYWxpZEd1YXJhbnRvcnMDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABdJbnZva2VTY3JpcHRUcmFuc2FjdGlvbgYDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAFFNldFNjcmlwdFRyYW5zYWN0aW9uBgkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAA9EYXRhVHJhbnNhY3Rpb24DBQAAAAxpc1ZhbGlkQWRtaW4FAAAAEWlzVmFsaWRHdWFyYW50b3JzBwdbf5So", 1651, 1660, 802}, {`V4: ARHXYD7j7chYAze2gwH4J3h7HLpHpiBxufnJo6YeqTvQ`, "AAIEAAAAAAAAABYIAhIAEgMKAQESBAoCAQgSAwoBCBIAAAAAQgEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkAAAAAAAAAAAABAAAADmdldFN0cmluZ0J5S2V5AAAAAQAAAANrZXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwUAAAADa2V5AgAAAAABAAAAFmdldEJvb2xCeUFkZHJlc3NBbmRLZXkAAAACAAAAB2FkZHJlc3MAAAADa2V5CQEAAAALdmFsdWVPckVsc2UAAAACCQAEGwAAAAIFAAAAB2FkZHJlc3MFAAAAA2tleQcBAAAAGGdldFN0cmluZ0J5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAHYWRkcmVzcwUAAAADa2V5AgAAAAABAAAAGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAHYWRkcmVzcwUAAAADa2V5AAAAAAAAAAAAAAAAAAdXQVZFTEVUAAAAAAAF9eEAAAAAAAVQQVVMSQAAAAAAAA9CQAAAAAAIUFJJQ0VMRVQAAAAAAAAPQkAAAAAABE1VTFQAAAAAAAX14QAAAAAACVNDQUxFTVVMVAAAAAAAAAAACAAAAAANTUlOT1JERVJUT1RBTAkAAGgAAAACAAAAAAAAAAAKBQAAAAdXQVZFTEVUAAAAAAZNQVhST0kAAAAAAAAAAF8AAAAACENBTkNFTEVEAgAAAAhjYW5jZWxlZAAAAAADTkVXAgAAAANuZXcAAAAABkZJTExFRAIAAAAGZmlsbGVkAAAAAAhQcmljZUtleQIAAAAFcHJpY2UAAAAADkJvbmRBc3NldElkS2V5AgAAAA1ib25kX2Fzc2V0X2lkAAAAABJOZXV0cmlub0Fzc2V0SWRLZXkCAAAAEW5ldXRyaW5vX2Fzc2V0X2lkAAAAABFCYWxhbmNlTG9ja2Vka0tleQIAAAANYmFsYW5jZV9sb2NrXwAAAAAVV2F2ZXNMb2NrZWRCYWxhbmNlS2V5CQABLAAAAAIFAAAAEUJhbGFuY2VMb2NrZWRrS2V5AgAAAAV3YXZlcwAAAAAYTmV1dHJpbm9Mb2NrZWRCYWxhbmNlS2V5CQABLAAAAAIFAAAAEUJhbGFuY2VMb2NrZWRrS2V5AgAAAAhuZXV0cmlubwAAAAANRmlyc3RPcmRlcktleQIAAAALb3JkZXJfZmlyc3QBAAAAEmdldFJvaUJ5T3JkZXJJZEtleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAABBkZWJ1Z19vcmRlcl9yb2lfBQAAAAdvcmRlcklkAQAAABBnZXRPcmRlclByaWNlS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAADG9yZGVyX3ByaWNlXwUAAAAHb3JkZXJJZAEAAAAQZ2V0T3JkZXJUb3RhbEtleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAAAxvcmRlcl90b3RhbF8FAAAAB29yZGVySWQBAAAAEGdldE9yZGVyT3duZXJLZXkAAAABAAAAB29yZGVySWQJAAEsAAAAAgIAAAAMb3JkZXJfb3duZXJfBQAAAAdvcmRlcklkAQAAABFnZXRPcmRlckhlaWdodEtleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAAA1vcmRlcl9oZWlnaHRfBQAAAAdvcmRlcklkAQAAABFnZXRPcmRlclN0YXR1c0tleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAAA1vcmRlcl9zdGF0dXNfBQAAAAdvcmRlcklkAQAAABZnZXRPcmRlckZpbGxlZFRvdGFsS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAAE29yZGVyX2ZpbGxlZF90b3RhbF8FAAAAB29yZGVySWQBAAAAD2dldFByZXZPcmRlcktleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAAAtvcmRlcl9wcmV2XwUAAAAHb3JkZXJJZAEAAAAPZ2V0TmV4dE9yZGVyS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAAC29yZGVyX25leHRfBQAAAAdvcmRlcklkAQAAABZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAAAAAgAAAAZhbW91bnQAAAAFcHJpY2UJAABrAAAAAwkAAGsAAAADBQAAAAZhbW91bnQFAAAACFBSSUNFTEVUBQAAAAVwcmljZQUAAAAHV0FWRUxFVAUAAAAFUEFVTEkBAAAAFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8AAAACAAAABmFtb3VudAAAAAVwcmljZQkAAGsAAAADCQAAawAAAAMFAAAABmFtb3VudAUAAAAFcHJpY2UFAAAACFBSSUNFTEVUBQAAAAVQQVVMSQUAAAAHV0FWRUxFVAEAAAASY29udmVydFdhdmVzVG9Cb25kAAAAAgAAAAZhbW91bnQAAAAFcHJpY2UJAQAAABZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAAAAAgUAAAAGYW1vdW50BQAAAAVwcmljZQEAAAASY29udmVydEJvbmRUb1dhdmVzAAAAAgAAAAZhbW91bnQAAAAFcHJpY2UJAQAAABZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAAAAAgUAAAAGYW1vdW50BQAAAAVwcmljZQAAAAAQbmV1dHJpbm9Db250cmFjdAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV3AEYqZHm+mtVmiUy++FjDCCICiaCBSWsgAAAAAPY29udHJvbENvbnRyYWN0CQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXI7OtElyTpMrsOf5PRtbNVk0t+xD7Y5h6AAAAABNsaXF1aWRhdGlvbkNvbnRyYWN0CQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXGupJy/oKfsoIfyjVn5WODHtptak4kR9IAAAAAA9uZXV0cmlub0Fzc2V0SWQBAAAAILYmKcME9c5TkaQOS3UkL2SMUbH6369UKb1I0h0qsqrRAAAAAAtib25kQXNzZXRJZAEAAAAgVe7DvqoL8FDoccgbqm5wnqSxyP5KLrnB8czFaw94l0sAAAAACWlzQmxvY2tlZAkBAAAAFmdldEJvb2xCeUFkZHJlc3NBbmRLZXkAAAACBQAAAA9jb250cm9sQ29udHJhY3QCAAAACmlzX2Jsb2NrZWQAAAAADGN1cnJlbnRQcmljZQkBAAAAGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQAAAAIFAAAAD2NvbnRyb2xDb250cmFjdAUAAAAIUHJpY2VLZXkAAAAAFW5ldXRyaW5vTG9ja2VkQmFsYW5jZQkBAAAAGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQAAAAIFAAAAEG5ldXRyaW5vQ29udHJhY3QFAAAAGE5ldXRyaW5vTG9ja2VkQmFsYW5jZUtleQAAAAAHcmVzZXJ2ZQkAAGUAAAACCAkAA+8AAAABBQAAABBuZXV0cmlub0NvbnRyYWN0AAAAB3JlZ3VsYXIJAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACBQAAABBuZXV0cmlub0NvbnRyYWN0BQAAABVXYXZlc0xvY2tlZEJhbGFuY2VLZXkAAAAADnJlc2VydmVzSW5Vc2RuCQEAAAAWY29udmVydFdhdmVzVG9OZXV0cmlubwAAAAIFAAAAB3Jlc2VydmUFAAAADGN1cnJlbnRQcmljZQAAAAAObmV1dHJpbm9TdXBwbHkJAABlAAAAAgkAAGUAAAACCQAAZAAAAAIFAAAAFW5ldXRyaW5vTG9ja2VkQmFsYW5jZQgJAQAAAAV2YWx1ZQAAAAEJAAPsAAAAAQUAAAAPbmV1dHJpbm9Bc3NldElkAAAACHF1YW50aXR5CQAD8AAAAAIFAAAAEG5ldXRyaW5vQ29udHJhY3QFAAAAD25ldXRyaW5vQXNzZXRJZAkAA/AAAAACBQAAABNsaXF1aWRhdGlvbkNvbnRyYWN0BQAAAA9uZXV0cmlub0Fzc2V0SWQAAAAAB2RlZmljaXQJAABlAAAAAgUAAAAObmV1dHJpbm9TdXBwbHkFAAAADnJlc2VydmVzSW5Vc2RuAAAAAA1jdXJyZW50TWF4Um9pCQAAawAAAAMFAAAAB2RlZmljaXQAAAAAAAAAAGQFAAAADm5ldXRyaW5vU3VwcGx5AAAAAA1jdXJyZW50QnJNdWx0CQAAawAAAAMFAAAADnJlc2VydmVzSW5Vc2RuBQAAAARNVUxUBQAAAA5uZXV0cmlub1N1cHBseQAAAAAKZmlyc3RPcmRlcgkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAANRmlyc3RPcmRlcktleQEAAAANZ2V0T3JkZXJQcmljZQAAAAEAAAACaWQJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABBnZXRPcmRlclByaWNlS2V5AAAAAQUAAAACaWQBAAAADWdldE9yZGVyVG90YWwAAAABAAAAAmlkCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABCQEAAAAQZ2V0T3JkZXJUb3RhbEtleQAAAAEFAAAAAmlkAQAAAA1nZXRPcmRlck93bmVyAAAAAQAAAAJpZAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAAEGdldE9yZGVyT3duZXJLZXkAAAABBQAAAAJpZAEAAAAOZ2V0T3JkZXJTdGF0dXMAAAABAAAAAmlkCQEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABCQEAAAARZ2V0T3JkZXJTdGF0dXNLZXkAAAABBQAAAAJpZAEAAAATZ2V0T3JkZXJGaWxsZWRUb3RhbAAAAAEAAAACaWQJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABZnZXRPcmRlckZpbGxlZFRvdGFsS2V5AAAAAQUAAAACaWQBAAAADGdldFByZXZPcmRlcgAAAAEAAAACaWQJAQAAAA5nZXRTdHJpbmdCeUtleQAAAAEJAQAAAA9nZXRQcmV2T3JkZXJLZXkAAAABBQAAAAJpZAEAAAAMZ2V0TmV4dE9yZGVyAAAAAQAAAAJpZAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAAD2dldE5leHRPcmRlcktleQAAAAEFAAAAAmlkAQAAAA5nZXRQcmljZUZvclJvaQAAAAEAAAALcm9pUGVyY2VudHMJAABrAAAAAwkAAGQAAAACAAAAAAAAAABkBQAAAAtyb2lQZXJjZW50cwUAAAAMY3VycmVudFByaWNlAAAAAAAAAABkAQAAAA9nZXRSZXZlcnNlUHJpY2UAAAABAAAABXByaWNlCQAAaQAAAAIJAABoAAAAAgUAAAAIUFJJQ0VMRVQFAAAACFBSSUNFTEVUBQAAAAVwcmljZQEAAAAWY2FsY05zYnQyV2F2ZXNQcmljZVJhdwAAAAIAAAANc3BlbnRXYXZlc1JhdwAAAA9yZWNlaXZlZE5zYnRSYXcJAABrAAAAAwUAAAANc3BlbnRXYXZlc1JhdwkAAGgAAAACBQAAAAVQQVVMSQUAAAAIUFJJQ0VMRVQFAAAAD3JlY2VpdmVkTnNidFJhdwEAAAAJb3JkZXJEYXRhAAAABwAAAAdvcmRlcklkAAAADXRvdGFsV2F2ZWxldHMAAAAOZmlsbGVkV2F2ZWxldHMAAAAFb3duZXIAAAAGc3RhdHVzAAAAA3JvaQAAAAVwcmljZQkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEGdldE9yZGVyUHJpY2VLZXkAAAABBQAAAAdvcmRlcklkBQAAAAVwcmljZQkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEGdldE9yZGVyVG90YWxLZXkAAAABBQAAAAdvcmRlcklkBQAAAA10b3RhbFdhdmVsZXRzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAWZ2V0T3JkZXJGaWxsZWRUb3RhbEtleQAAAAEFAAAAB29yZGVySWQFAAAADmZpbGxlZFdhdmVsZXRzCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABBnZXRPcmRlck93bmVyS2V5AAAAAQUAAAAHb3JkZXJJZAUAAAAFb3duZXIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABFnZXRPcmRlckhlaWdodEtleQAAAAEFAAAAB29yZGVySWQFAAAABmhlaWdodAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAARZ2V0T3JkZXJTdGF0dXNLZXkAAAABBQAAAAdvcmRlcklkBQAAAAZzdGF0dXMJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAAEsAAAAAgIAAAAZZGVidWdfb3JkZXJfY3VycmVudFByaWNlXwUAAAAHb3JkZXJJZAUAAAAMY3VycmVudFByaWNlCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAASZ2V0Um9pQnlPcmRlcklkS2V5AAAAAQUAAAAHb3JkZXJJZAUAAAADcm9pBQAAAANuaWwBAAAAEGludGVybmFsU2VsbEJvbmQAAAAIAAAAC3BGaXJzdE9yZGVyAAAACnBOZXh0T3JkZXIAAAAMcEZpbGxlZFRvdGFsAAAABHBSb2kAAAAGcFByaWNlAAAAEHBQYXltZW50V2F2ZWxldHMAAAARb3JkZXJPd25lckFkZHJlc3MAAAAMaW5zdGFudE9yZGVyBAAAABVwcmljZVdhdmVzQnlCb25kQ2VudHMJAQAAAA5nZXRQcmljZUZvclJvaQAAAAEFAAAABHBSb2kEAAAADXJlbWFpbmVkVG90YWwJAABlAAAAAgUAAAAQcFBheW1lbnRXYXZlbGV0cwUAAAAMcEZpbGxlZFRvdGFsBAAAABNmaWxsYWJsZU9yZGVyQW1vdW50CQEAAAASY29udmVydFdhdmVzVG9Cb25kAAAAAgUAAAANcmVtYWluZWRUb3RhbAUAAAAVcHJpY2VXYXZlc0J5Qm9uZENlbnRzBAAAABt0b3RhbE9yZGVyV2F2ZWxldGVzUmVxdWlyZWQJAQAAABJjb252ZXJ0Qm9uZFRvV2F2ZXMAAAACBQAAABNmaWxsYWJsZU9yZGVyQW1vdW50BQAAABVwcmljZVdhdmVzQnlCb25kQ2VudHMEAAAAFW5iVG9rZW5zU2VsbENvbmRpdGlvbgkAAGcAAAACBQAAAA1jdXJyZW50TWF4Um9pBQAAAARwUm9pAwkBAAAAASEAAAABBQAAABVuYlRva2Vuc1NlbGxDb25kaXRpb24JAAACAAAAAQkAASwAAAACAgAAABNpbm5hcHJvcHJpYXRlIHJvaTogCQABpAAAAAEFAAAABHBSb2kDCQAAAAAAAAIFAAAAG3RvdGFsT3JkZXJXYXZlbGV0ZXNSZXF1aXJlZAAAAAAAAAAAAAkAAAIAAAABAgAAAB9jYW5ub3QgZmlsbCBvcmRlciBhdCB0aGUgbW9tZW50BAAAAA5jaGFuZ2VXYXZlbGV0cwkAAGUAAAACBQAAAA1yZW1haW5lZFRvdGFsBQAAABt0b3RhbE9yZGVyV2F2ZWxldGVzUmVxdWlyZWQEAAAADHdyaXRlU2V0RGF0YQMFAAAADGluc3RhbnRPcmRlcgkBAAAACW9yZGVyRGF0YQAAAAcFAAAAC3BGaXJzdE9yZGVyBQAAABBwUGF5bWVudFdhdmVsZXRzCQAAZAAAAAIFAAAADHBGaWxsZWRUb3RhbAUAAAAbdG90YWxPcmRlcldhdmVsZXRlc1JlcXVpcmVkCQACWAAAAAEIBQAAABFvcmRlck93bmVyQWRkcmVzcwAAAAVieXRlcwUAAAAGRklMTEVEBQAAAARwUm9pBQAAAAxjdXJyZW50UHJpY2UJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABZnZXRPcmRlckZpbGxlZFRvdGFsS2V5AAAAAQUAAAALcEZpcnN0T3JkZXIJAABkAAAAAgUAAAAMcEZpbGxlZFRvdGFsBQAAABt0b3RhbE9yZGVyV2F2ZWxldGVzUmVxdWlyZWQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAEWdldE9yZGVyU3RhdHVzS2V5AAAAAQUAAAALcEZpcnN0T3JkZXIFAAAABkZJTExFRAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAPZ2V0UHJldk9yZGVyS2V5AAAAAQUAAAAKcE5leHRPcmRlcgIAAAAACQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADUZpcnN0T3JkZXJLZXkFAAAACnBOZXh0T3JkZXIFAAAAA25pbAkABE4AAAACBQAAAAx3cml0ZVNldERhdGEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAARb3JkZXJPd25lckFkZHJlc3MFAAAAE2ZpbGxhYmxlT3JkZXJBbW91bnQFAAAAC2JvbmRBc3NldElkCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMFAAAAEG5ldXRyaW5vQ29udHJhY3QFAAAAG3RvdGFsT3JkZXJXYXZlbGV0ZXNSZXF1aXJlZAUAAAAEdW5pdAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAABFvcmRlck93bmVyQWRkcmVzcwUAAAAOY2hhbmdlV2F2ZWxldHMFAAAABHVuaXQFAAAAA25pbAEAAAAXaW50ZXJuYWxBZGRCdXlCb25kT3JkZXIAAAAFAAAAA3JvaQAAAAVwcmljZQAAAAlwcmV2T3JkZXIAAAADaW52AAAADGluc3RhbnRPcmRlcgQAAAADcG10CQEAAAAFdmFsdWUAAAABCQABkQAAAAIIBQAAAANpbnYAAAAIcGF5bWVudHMAAAAAAAAAAAAEAAAACm5ld09yZGVySWQJAAJYAAAAAQgFAAAAA2ludgAAAA10cmFuc2FjdGlvbklkAwUAAAAJaXNCbG9ja2VkCQAAAgAAAAECAAAAWWNvbnRyYWN0IGlzIGJsb2NrZWQgYnkgRU1FUkdFTkNZIFNIVVRET1dOIGFjdGlvbnMgdW50aWwgcmVhY3RpdmF0aW9uIGJ5IGVtZXJnZW5jeSBvcmFjbGVzAwkAAGYAAAACBQAAAA1NSU5PUkRFUlRPVEFMCAUAAAADcG10AAAABmFtb3VudAkAAAIAAAABCQABLAAAAAICAAAAF21pbiBvcmRlciB0b3RhbCBlcXVhbHMgCQABpAAAAAEFAAAADU1JTk9SREVSVE9UQUwDCQAAZgAAAAIFAAAAA3JvaQUAAAAGTUFYUk9JCQAAAgAAAAECAAAAF21heCBzZXRPcmRlciBST0kgaXMgOTUlAwkAAGYAAAACAAAAAAAAAAAABQAAAANyb2kJAAACAAAAAQIAAAAjY2FuJ3QgcGxhY2Ugb3JkZXIgd2l0aCBuZWdhdGl2ZSByb2kDCQAAAAAAAAIFAAAAA3JvaQAAAAAAAAAAAAkAAAIAAAABAgAAABxyb2kgc2hvdWxkIG5vdCBiZSBlcXVhbCB0byAwAwkBAAAACWlzRGVmaW5lZAAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAkAAAIAAAABAgAAABJjYW4gdXNlIHdhdmVzIG9ubHkDCQEAAAACIT0AAAACCQEAAAANZ2V0T3JkZXJPd25lcgAAAAEFAAAACm5ld09yZGVySWQCAAAAAAkAAAIAAAABAgAAAAxvcmRlciBleGlzdHMDAwkBAAAAAiE9AAAAAgUAAAAJcHJldk9yZGVyAgAAAAAJAQAAAAIhPQAAAAIJAQAAAA5nZXRPcmRlclN0YXR1cwAAAAEFAAAACXByZXZPcmRlcgUAAAADTkVXBwkAAAIAAAABAgAAABxwcmV2IG9yZGVyIHN0YXR1cyBpcyBub3QgbmV3BAAAABlpc05ld09yZGVyQXRGaXJzdFBvc2l0aW9uCQAAAAAAAAIFAAAACXByZXZPcmRlcgIAAAAABAAAAAVvd25lcgkABCUAAAABCAUAAAADaW52AAAABmNhbGxlcgQAAAAJbmV4dE9yZGVyAwUAAAAZaXNOZXdPcmRlckF0Rmlyc3RQb3NpdGlvbgUAAAAKZmlyc3RPcmRlcgkBAAAADGdldE5leHRPcmRlcgAAAAEFAAAACXByZXZPcmRlcgQAAAAMbmV4dE9yZGVyUm9pCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABCQEAAAASZ2V0Um9pQnlPcmRlcklkS2V5AAAAAQUAAAAJbmV4dE9yZGVyBAAAABBpc05leHRPcmRlckVycm9yAwMJAQAAAAIhPQAAAAIFAAAACW5leHRPcmRlcgIAAAAACQAAZwAAAAIFAAAAA3JvaQUAAAAMbmV4dE9yZGVyUm9pBwYHBAAAAAxwcmV2T3JkZXJSb2kJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABJnZXRSb2lCeU9yZGVySWRLZXkAAAABBQAAAAlwcmV2T3JkZXIEAAAAEGlzUHJldk9yZGVyRXJyb3IDAwkBAAAAAiE9AAAAAgUAAAAJcHJldk9yZGVyAgAAAAAJAABmAAAAAgUAAAAMcHJldk9yZGVyUm9pBQAAAANyb2kHBgcDAwUAAAAQaXNOZXh0T3JkZXJFcnJvcgYFAAAAEGlzUHJldk9yZGVyRXJyb3IJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAAfaW52YWxpZCBvcmRlciBpc1ByZXZPcmRlckVycm9yOgkAAaUAAAABBQAAABBpc1ByZXZPcmRlckVycm9yAgAAABIgaXNOZXh0T3JkZXJFcnJvcjoJAAGlAAAAAQUAAAAQaXNOZXh0T3JkZXJFcnJvcgMDBQAAABlpc05ld09yZGVyQXRGaXJzdFBvc2l0aW9uCQAAZwAAAAIFAAAADWN1cnJlbnRNYXhSb2kFAAAAA3JvaQcJAQAAABBpbnRlcm5hbFNlbGxCb25kAAAACAUAAAAKbmV3T3JkZXJJZAUAAAAJbmV4dE9yZGVyAAAAAAAAAAAABQAAAANyb2kFAAAABXByaWNlCAUAAAADcG10AAAABmFtb3VudAgFAAAAA2ludgAAAAZjYWxsZXIGAwUAAAAMaW5zdGFudE9yZGVyCQAAAgAAAAECAAAAMkluc3RhbnQgb3JkZXIgY291bGRuJ3QgYmUgYWRkZWQgaW50byB3YWl0aW5nIHF1ZXVlCQAETgAAAAIJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAD2dldFByZXZPcmRlcktleQAAAAEFAAAACm5ld09yZGVySWQFAAAACXByZXZPcmRlcgkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAPZ2V0TmV4dE9yZGVyS2V5AAAAAQUAAAAKbmV3T3JkZXJJZAUAAAAJbmV4dE9yZGVyCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAAA9nZXROZXh0T3JkZXJLZXkAAAABBQAAAAlwcmV2T3JkZXIDCQAAAAAAAAIFAAAACXByZXZPcmRlcgIAAAAAAgAAAAAFAAAACm5ld09yZGVySWQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAD2dldFByZXZPcmRlcktleQAAAAEFAAAACW5leHRPcmRlcgMJAAAAAAAAAgUAAAAJbmV4dE9yZGVyAgAAAAACAAAAAAUAAAAKbmV3T3JkZXJJZAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAAA1GaXJzdE9yZGVyS2V5AwMJAAAAAAAAAgUAAAAKZmlyc3RPcmRlcgIAAAAABgkAAAAAAAACBQAAAApmaXJzdE9yZGVyBQAAAAluZXh0T3JkZXIFAAAACm5ld09yZGVySWQFAAAACmZpcnN0T3JkZXIFAAAAA25pbAkBAAAACW9yZGVyRGF0YQAAAAcFAAAACm5ld09yZGVySWQIBQAAAANwbXQAAAAGYW1vdW50AAAAAAAAAAAABQAAAAVvd25lcgUAAAADTkVXBQAAAANyb2kFAAAABXByaWNlAQAAAA1jdXJ2ZUZ1bmN0aW9uAAAAAwAAAAR3UmF3AAAABHVSYXcAAAAFcHJpY2UEAAAAA0VYUAAAAAAAEDPEhAQAAAAPbnNidEN1cnZlUGFyYW1BCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMCAAAAEG5zYnRDdXJ2ZVBhcmFtX2EAAAAAAAAAAAMEAAAAD3dSZXNlcnZlc0luVXNkbgkBAAAAFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8AAAACBQAAAAR3UmF3BQAAAAVwcmljZQQAAAAGYnJNdWx0CQAAawAAAAMFAAAAD3dSZXNlcnZlc0luVXNkbgUAAAAETVVMVAUAAAAEdVJhdwQAAAAJcG93ZXJNdWx0CQAAaAAAAAIFAAAAD25zYnRDdXJ2ZVBhcmFtQQkAAGUAAAACBQAAAAZick11bHQJAABoAAAAAgAAAAAAAAAAAQUAAAAETVVMVAQAAAAOZXhwSW5Qb3dlck11bHQJAABsAAAABgUAAAADRVhQBQAAAAlTQ0FMRU1VTFQFAAAACXBvd2VyTXVsdAUAAAAJU0NBTEVNVUxUBQAAAAlTQ0FMRU1VTFQFAAAABERPV04EAAAACmNvbnN0Q29lZmYJAABrAAAAAwUAAAAEdVJhdwUAAAAIUFJJQ0VMRVQJAABoAAAAAgUAAAAPbnNidEN1cnZlUGFyYW1BBQAAAAVwcmljZQQAAAAYZmluYWxSZXN1bHRJZlByaWNlSW5Vc2RuCQAAawAAAAMFAAAACmNvbnN0Q29lZmYFAAAABE1VTFQFAAAADmV4cEluUG93ZXJNdWx0BAAAAAtmaW5hbFJlc3VsdAkAAGsAAAADBQAAABhmaW5hbFJlc3VsdElmUHJpY2VJblVzZG4FAAAABXByaWNlBQAAAAhQUklDRUxFVAkABRgAAAAGBQAAAAtmaW5hbFJlc3VsdAUAAAAPd1Jlc2VydmVzSW5Vc2RuBQAAAAZick11bHQFAAAACXBvd2VyTXVsdAUAAAAOZXhwSW5Qb3dlck11bHQFAAAACmNvbnN0Q29lZmYBAAAABXRvU3RyAAAAAgAAAARuYW1lAAAAAWwJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgUAAAAEbmFtZQIAAAANW2ZpbmFsUmVzdWx0PQkAAaQAAAABCAUAAAABbAAAAAJfMQIAAAAQd1Jlc2VydmVzSW5Vc2RuPQkAAaQAAAABCAUAAAABbAAAAAJfMgIAAAAIIGJyTXVsdD0JAAGkAAAAAQgFAAAAAWwAAAACXzMCAAAACyBwb3dlck11bHQ9CQABpAAAAAEIBQAAAAFsAAAAAl80AgAAABAgZXhwSW5Qb3dlck11bHQ9CQABpAAAAAEIBQAAAAFsAAAAAl81AgAAAAwgY29uc3RDb2VmZj0JAAGkAAAAAQgFAAAAAWwAAAACXzYCAAAAAV0BAAAADWJpZ0NvbXBsZXhpdHkAAAABAAAAAWkDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDCQEAAAABIQAAAAEJAQAAAAlpc0RlZmluZWQAAAABCQAD7gAAAAEJAAJZAAAAAQIAAAAsUGRMdzVKSzVwcGZTRXF2bUZKdmNoZWpvckFremQ0QnJXTHZvRnd2TUd1NWsJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxhZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxzZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxkZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxmZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxnZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxoZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxqZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxrZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACxyZEx3NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACx0ZExxNUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACx0ZEx5NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACx0ZEx1NUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACx0ZExoNUpLZHBxZlNFcXZtRkp2Y2hlam9yQWt6ZDRCcldMdm9Gd3ZNR3U1awcJAQAAAAEhAAAAAQkBAAAACWlzRGVmaW5lZAAAAAEJAAPuAAAAAQkAAlkAAAABAgAAACsxZEw0SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDJkTDI1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDNkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDRkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDVkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDZkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDdkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDhkTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDkxTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDkyTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDkzTDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkAA+4AAAABCQACWQAAAAECAAAALDk0TDk1SktkcHFmU0Vxdm1GSnZjaGVqb3JBa3pkNEJyV0x2b0Z3dk1HdTVrBwAAAAUAAAABaQEAAAAQYnV5TnNidEluU3VycGx1cwAAAAAEAAAAA3BtdAkBAAAABXZhbHVlAAAAAQkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAAJcG10QW1vdW50CAUAAAADcG10AAAABmFtb3VudAQAAAAMb3duZXJBZGRyZXNzCAUAAAABaQAAAAZjYWxsZXIDBQAAAAlpc0Jsb2NrZWQJAAACAAAAAQIAAABZY29udHJhY3QgaXMgYmxvY2tlZCBieSBFTUVSR0VOQ1kgU0hVVERPV04gYWN0aW9ucyB1bnRpbCByZWFjdGl2YXRpb24gYnkgZW1lcmdlbmN5IG9yYWNsZXMDCQAAZgAAAAIJAABoAAAAAgAAAAAAAAAAAQUAAAAETVVMVAUAAAANY3VycmVudEJyTXVsdAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAFd1c2UgaW5zdGFudEJ1eU5zYnRPckZhaWwgb3IgYWRkQnV5Qm9uZE9yZGVyIG1ldGhvZHMgdG8gYnV5IG5zYnQgd2hlbiBCUiA8IDE6IGN1cnJlbnRCUj0JAAGkAAAAAQUAAAANY3VycmVudEJyTXVsdAIAAAABLwkAAaQAAAABBQAAAARNVUxUAwkBAAAACWlzRGVmaW5lZAAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAkAAAIAAAABAgAAABJjYW4gdXNlIHdhdmVzIG9ubHkEAAAADW1pbkFtb3VudEZhaWwDCQAAZgAAAAIJAABoAAAAAgAAAAAAAAAAAQUAAAAHV0FWRUxFVAUAAAAJcG10QW1vdW50AwkAAAAAAAACCQEAAAANYmlnQ29tcGxleGl0eQAAAAEFAAAAAWkGBgcHAwUAAAANbWluQW1vdW50RmFpbAkAAAIAAAABAgAAACViaWcgY29tcGxleGl0eSArIG1pbiAxIHdhdmVzIGV4cGVjdGVkAwkAAGYAAAACCQAAaAAAAAIAAAAAAAAAAAEFAAAAB1dBVkVMRVQFAAAACXBtdEFtb3VudAkAAAIAAAABAgAAABRtaW4gMSB3YXZlcyBleHBlY3RlZAQAAAACZjAJAQAAAA1jdXJ2ZUZ1bmN0aW9uAAAAAwUAAAAHcmVzZXJ2ZQUAAAAObmV1dHJpbm9TdXBwbHkFAAAADGN1cnJlbnRQcmljZQQAAAACZjEJAQAAAA1jdXJ2ZUZ1bmN0aW9uAAAAAwkAAGQAAAACBQAAAAdyZXNlcnZlBQAAAAlwbXRBbW91bnQFAAAADm5ldXRyaW5vU3VwcGx5BQAAAAxjdXJyZW50UHJpY2UEAAAACm5zYnRBbW91bnQJAABlAAAAAggFAAAAAmYwAAAAAl8xCAUAAAACZjEAAAACXzEEAAAAEm5zYnQyV2F2ZXNQcmljZVJhdwkBAAAAFmNhbGNOc2J0MldhdmVzUHJpY2VSYXcAAAACBQAAAAlwbXRBbW91bnQFAAAACm5zYnRBbW91bnQEAAAAA3JvaQkAAGUAAAACCQAAawAAAAMJAQAAAA9nZXRSZXZlcnNlUHJpY2UAAAABBQAAABJuc2J0MldhdmVzUHJpY2VSYXcAAAAAAAAAAGQFAAAADGN1cnJlbnRQcmljZQAAAAAAAAAAZAkABE4AAAACCQEAAAAJb3JkZXJEYXRhAAAABwkAAlgAAAABCAUAAAABaQAAAA10cmFuc2FjdGlvbklkBQAAAAlwbXRBbW91bnQFAAAACXBtdEFtb3VudAkABCUAAAABBQAAAAxvd25lckFkZHJlc3MFAAAABkZJTExFRAUAAAADcm9pBQAAABJuc2J0MldhdmVzUHJpY2VSYXcJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAMb3duZXJBZGRyZXNzBQAAAApuc2J0QW1vdW50BQAAAAtib25kQXNzZXRJZAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAABBuZXV0cmlub0NvbnRyYWN0BQAAAAlwbXRBbW91bnQFAAAABHVuaXQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgIAAAAIZGVidWdfZjAJAQAAAAV0b1N0cgAAAAICAAAAAmYwBQAAAAJmMAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACAgAAAAhkZWJ1Z19mMQkBAAAABXRvU3RyAAAAAgIAAAACZjEFAAAAAmYxBQAAAANuaWwAAAABaQEAAAAUaW5zdGFudEJ1eU5zYnRPckZhaWwAAAABAAAADW5vTGVzc1RoZW5Sb2kEAAAAA3BtdAkBAAAABXZhbHVlAAAAAQkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAADcm9pBQAAAA1jdXJyZW50TWF4Um9pAwkAAGYAAAACBQAAAA1ub0xlc3NUaGVuUm9pBQAAAANyb2kJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAAPQ3VycmVudCBtYXhSb2k9CQABpAAAAAEFAAAAA3JvaQIAAAAtIGlzIGxlc3MgdGhlbiBwYXNzZWQgcGFyYW1ldGVyIG5vTGVzc1RoZW5Sb2k9CQABpAAAAAEFAAAADW5vTGVzc1RoZW5Sb2kEAAAAFXByaWNlV2F2ZXNCeUJvbmRDZW50cwkBAAAADmdldFByaWNlRm9yUm9pAAAAAQUAAAADcm9pCQEAAAAXaW50ZXJuYWxBZGRCdXlCb25kT3JkZXIAAAAFBQAAAANyb2kJAQAAAA9nZXRSZXZlcnNlUHJpY2UAAAABBQAAABVwcmljZVdhdmVzQnlCb25kQ2VudHMCAAAAAAUAAAABaQYAAAABaQEAAAAPYWRkQnV5Qm9uZE9yZGVyAAAAAgAAAAVwcmljZQAAAAlwcmV2T3JkZXIEAAAAA3BtdAkBAAAABXZhbHVlAAAAAQkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAAVcHJpY2VXYXZlc0J5Qm9uZENlbnRzCQEAAAAPZ2V0UmV2ZXJzZVByaWNlAAAAAQUAAAAFcHJpY2UDCQAAZwAAAAIAAAAAAAAAAAAFAAAABXByaWNlCQAAAgAAAAECAAAAD3ByaWNlIGxlc3MgemVybwkBAAAAF2ludGVybmFsQWRkQnV5Qm9uZE9yZGVyAAAABQkAAGsAAAADCQAAZQAAAAIFAAAAFXByaWNlV2F2ZXNCeUJvbmRDZW50cwUAAAAMY3VycmVudFByaWNlAAAAAAAAAABkBQAAAAxjdXJyZW50UHJpY2UFAAAABXByaWNlBQAAAAlwcmV2T3JkZXIFAAAAAWkHAAAAAWkBAAAAC2NhbmNlbE9yZGVyAAAAAQAAAAdvcmRlcklkBAAAAAVvd25lcgkBAAAADWdldE9yZGVyT3duZXIAAAABBQAAAAdvcmRlcklkBAAAAAZhbW91bnQJAABlAAAAAgkBAAAADWdldE9yZGVyVG90YWwAAAABBQAAAAdvcmRlcklkCQEAAAATZ2V0T3JkZXJGaWxsZWRUb3RhbAAAAAEFAAAAB29yZGVySWQEAAAABmNhbGxlcgkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIEAAAACW5leHRPcmRlcgkBAAAADGdldE5leHRPcmRlcgAAAAEFAAAAB29yZGVySWQEAAAACXByZXZPcmRlcgkBAAAADGdldFByZXZPcmRlcgAAAAEFAAAAB29yZGVySWQDBQAAAAlpc0Jsb2NrZWQJAAACAAAAAQIAAABZY29udHJhY3QgaXMgYmxvY2tlZCBieSBFTUVSR0VOQ1kgU0hVVERPV04gYWN0aW9ucyB1bnRpbCByZWFjdGl2YXRpb24gYnkgZW1lcmdlbmN5IG9yYWNsZXMDCQEAAAACIT0AAAACBQAAAAVvd25lcgUAAAAGY2FsbGVyCQAAAgAAAAECAAAAEXBlcm1pc3Npb24gZGVuaWVkAwkBAAAAAiE9AAAAAgkBAAAADmdldE9yZGVyU3RhdHVzAAAAAQUAAAAHb3JkZXJJZAUAAAADTkVXCQAAAgAAAAECAAAAFGludmFsaWQgb3JkZXIgc3RhdHVzCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADUZpcnN0T3JkZXJLZXkDCQAAAAAAAAIFAAAACmZpcnN0T3JkZXIFAAAAB29yZGVySWQFAAAACW5leHRPcmRlcgUAAAAKZmlyc3RPcmRlcgkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAPZ2V0TmV4dE9yZGVyS2V5AAAAAQUAAAAJcHJldk9yZGVyBQAAAAluZXh0T3JkZXIJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAD2dldFByZXZPcmRlcktleQAAAAEFAAAACW5leHRPcmRlcgUAAAAJcHJldk9yZGVyCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABFnZXRPcmRlclN0YXR1c0tleQAAAAEFAAAAB29yZGVySWQFAAAACENBTkNFTEVECQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMIBQAAAAFpAAAABmNhbGxlcgUAAAAGYW1vdW50BQAAAAR1bml0BQAAAANuaWwAAAABaQEAAAAIc2VsbEJvbmQAAAAAAwUAAAAJaXNCbG9ja2VkCQAAAgAAAAECAAAAWWNvbnRyYWN0IGlzIGJsb2NrZWQgYnkgRU1FUkdFTkNZIFNIVVRET1dOIGFjdGlvbnMgdW50aWwgcmVhY3RpdmF0aW9uIGJ5IGVtZXJnZW5jeSBvcmFjbGVzAwkAAAAAAAACBQAAAApmaXJzdE9yZGVyAgAAAAAJAAACAAAAAQIAAAAPZW1wdHkgb3JkZXJib29rBAAAAAluZXh0T3JkZXIJAQAAAAxnZXROZXh0T3JkZXIAAAABBQAAAApmaXJzdE9yZGVyBAAAAAtmaWxsZWRUb3RhbAkBAAAAE2dldE9yZGVyRmlsbGVkVG90YWwAAAABBQAAAApmaXJzdE9yZGVyBAAAAApvcmRlclByaWNlCQEAAAANZ2V0T3JkZXJQcmljZQAAAAEFAAAACmZpcnN0T3JkZXIEAAAAA3JvaQkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAEmdldFJvaUJ5T3JkZXJJZEtleQAAAAEFAAAACmZpcnN0T3JkZXIEAAAAD3BheW1lbnRXYXZlbGV0cwkBAAAADWdldE9yZGVyVG90YWwAAAABBQAAAApmaXJzdE9yZGVyBAAAABFvcmRlck93bmVyQWRkcmVzcwkBAAAAB0FkZHJlc3MAAAABCQACWQAAAAEJAQAAAA1nZXRPcmRlck93bmVyAAAAAQUAAAAKZmlyc3RPcmRlcgkBAAAAEGludGVybmFsU2VsbEJvbmQAAAAIBQAAAApmaXJzdE9yZGVyBQAAAAluZXh0T3JkZXIFAAAAC2ZpbGxlZFRvdGFsBQAAAANyb2kFAAAACm9yZGVyUHJpY2UFAAAAD3BheW1lbnRXYXZlbGV0cwUAAAARb3JkZXJPd25lckFkZHJlc3MHAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAQAAAAQcHViS2V5QWRtaW5zTGlzdAkABEwAAAACAgAAACxHSmRMU2FMaXY1Szd4dWVqYWM4bWNSY0hveW8zZFByRVNydmt0RzNhNk1BUgkABEwAAAACAgAAACxGV1ZmZllyMkFMbUhNZWpabTNXcWVMejZTZHltM2dMRkd0Sm40S1R3eVU1eAkABEwAAAACAgAAACwzV2gyTGFXY2I1Z2c3SzJwUGNXM0VwNkVBdVJCellrQWdyZHB0NDNqVERGYQkABEwAAAACAgAAACw1V1JYRlNqd2NUYk5mS2NKczhacVhtU1NXWXNTVkpVdE12TXFaajVoSDROYwUAAAADbmlsBAAAAAVjb3VudAkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAABCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAACCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAADCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAwAAAAAAAAAAAgAAAAAAAAAAAAkAAGcAAAACBQAAAAVjb3VudAAAAAAAAAAAAzcijko=", 4122, 4071, 3131}, + {`V5: 4tb8uA1TUQBzQ62WjzA75ryDK8Uh2mEXhKAp48qWw3X4`, "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAARjYWxsAAAAAAQAAAAFbGVhc2UJAAREAAAAAgkBAAAAEUBleHRyTmF0aXZlKDEwNjIpAAAAAQIAAAAjM01lOEpGOGZodWdTU2EyS3g0dzd2MnRYMzc3c1RWdEtTVTUAAAAAAAX14QAEAAAAAmlkCQAEOQAAAAEFAAAABWxlYXNlCQAFFAAAAAIJAARMAAAAAgUAAAAFbGVhc2UJAARMAAAAAgkBAAAAC0JpbmFyeUVudHJ5AAAAAgIAAAAFbGVhc2UFAAAAAmlkBQAAAANuaWwFAAAAA25pbAAAAAFpAQAAABRDcmVhdGVBbmRDYW5jZWxMZWFzZQAAAAAEAAAABWxlYXNlCQAERAAAAAIJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAECAAAAIzNNZThKRjhmaHVnU1NhMkt4NHc3djJ0WDM3N3NUVnRLU1U1AAAAAAAF9eEABAAAAAJpZAkABDkAAAABBQAAAAVsZWFzZQQAAAAMY2FuY2VsUGFydGx5CQEAAAALTGVhc2VDYW5jZWwAAAABBQAAAAJpZAQAAAAGbGVhc2UyCQAERAAAAAIJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAECAAAAIzNNZThKRjhmaHVnU1NhMkt4NHc3djJ0WDM3N3NUVnRLU1U1AAAAAAAC+vCABAAAAANpZDIJAAQ5AAAAAQUAAAAGbGVhc2UyCQAFFAAAAAIJAARMAAAAAgUAAAAFbGVhc2UJAARMAAAAAgUAAAAMY2FuY2VsUGFydGx5CQAETAAAAAIFAAAABmxlYXNlMgkABEwAAAACCQEAAAALQmluYXJ5RW50cnkAAAACAgAAAAVsZWFzZQUAAAADaWQyBQAAAANuaWwFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V55bVbiA==", 226, 226, 210}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) @@ -231,3 +232,34 @@ func TestStackOverflowOnV2(t *testing.T) { fmt.Println(test.comment, ":", time.Since(start)) } } + +func TestFailOnInvocationInExpression(t *testing.T) { + /* + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let dapp = Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna') + + match tx { + case t: InvokeScriptTransaction => { + let result = match invoke(dapp, "foo", [5], [AttachedPayment(unit, 10)]) { + case i: Int => i + case _ => throw("Wrong result type") + } + if result == 5 then true else throw("Wrong result '" + result.toString() + "'") + } + case _ => throw("Wrong tx type") + } + */ + source := "BQQAAAAEZGFwcAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAF0ludm9rZVNjcmlwdFRyYW5zYWN0aW9uBAAAAAF0BQAAAAckbWF0Y2gwBAAAAAZyZXN1bHQEAAAAByRtYXRjaDEJAAP8AAAABAUAAAAEZGFwcAIAAAADZm9vCQAETAAAAAIAAAAAAAAAAAUFAAAAA25pbAkABEwAAAACCQEAAAAPQXR0YWNoZWRQYXltZW50AAAAAgUAAAAEdW5pdAAAAAAAAAAACgUAAAADbmlsAwkAAAEAAAACBQAAAAckbWF0Y2gxAgAAAANJbnQEAAAAAWkFAAAAByRtYXRjaDEFAAAAAWkJAAACAAAAAQIAAAARV3JvbmcgcmVzdWx0IHR5cGUDCQAAAAAAAAIFAAAABnJlc3VsdAAAAAAAAAAABQYJAAACAAAAAQkAASwAAAACCQABLAAAAAICAAAADldyb25nIHJlc3VsdCAnCQABpAAAAAEFAAAABnJlc3VsdAIAAAABJwkAAAIAAAABAgAAAA1Xcm9uZyB0eCB0eXBlUP0hpw==" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + _, err = EstimateTree(tree, 3) + require.Error(t, err) +} diff --git a/pkg/ride/tree_estimatorV1.go b/pkg/ride/tree_estimatorV1.go index 65367d65a..77a7bf1af 100644 --- a/pkg/ride/tree_estimatorV1.go +++ b/pkg/ride/tree_estimatorV1.go @@ -85,6 +85,8 @@ func newTreeEstimatorV1(tree *Tree) (*treeEstimatorV1, error) { r.scope = newEstimationScopeV1(ConstantsV3, CatalogueV3) case 4: r.scope = newEstimationScopeV1(ConstantsV4, CatalogueV4) + case 5: + r.scope = newEstimationScopeV1(ConstantsV4, CatalogueV5) default: return nil, errors.Errorf("unsupported library version %d", tree.LibVersion) } diff --git a/pkg/ride/tree_estimatorV2.go b/pkg/ride/tree_estimatorV2.go index 9ec7cf5fe..e54d4d40a 100644 --- a/pkg/ride/tree_estimatorV2.go +++ b/pkg/ride/tree_estimatorV2.go @@ -100,6 +100,8 @@ func newTreeEstimatorV2(tree *Tree) (*treeEstimatorV2, error) { r.scope = newEstimationScopeV2(ConstantsV3, CatalogueV3) case 4: r.scope = newEstimationScopeV2(ConstantsV4, CatalogueV4) + case 5: + r.scope = newEstimationScopeV2(ConstantsV4, CatalogueV5) default: return nil, errors.Errorf("unsupported library version %d", tree.LibVersion) } diff --git a/pkg/ride/tree_estimatorV3.go b/pkg/ride/tree_estimatorV3.go index de4a443e7..f842cd2e6 100644 --- a/pkg/ride/tree_estimatorV3.go +++ b/pkg/ride/tree_estimatorV3.go @@ -67,8 +67,11 @@ func (s *estimationScopeV3) setFunction(id string, cost int, usages []string) { s.functions.set(id, cost, usages) } -func (s *estimationScopeV3) function(id string) (int, []string, error) { +func (s *estimationScopeV3) function(id string, enableInvocation bool) (int, []string, error) { if c, ok := s.builtin[id]; ok { + if (id == "1020" || id == "1021") && !enableInvocation { + return 0, nil, errors.Errorf("function '%s' not found", id) + } return c, nil, nil } return s.functions.get(id) @@ -128,6 +131,8 @@ func newTreeEstimatorV3(tree *Tree) (*treeEstimatorV3, error) { r.scope = newEstimationScopeV3(CatalogueV3) case 4: r.scope = newEstimationScopeV3(CatalogueV4) + case 5: + r.scope = newEstimationScopeV3(CatalogueV5) default: return nil, errors.Errorf("unsupported library version %d", tree.LibVersion) } @@ -137,7 +142,7 @@ func newTreeEstimatorV3(tree *Tree) (*treeEstimatorV3, error) { func (e *treeEstimatorV3) estimate() (int, int, map[string]int, error) { if !e.tree.IsDApp() { e.scope.submerge() - c, err := e.walk(e.tree.Verifier) + c, err := e.walk(e.tree.Verifier, false) if err != nil { return 0, 0, nil, err } @@ -152,7 +157,7 @@ func (e *treeEstimatorV3) estimate() (int, int, map[string]int, error) { return 0, 0, nil, errors.New("invalid callable declaration") } e.scope.submerge() - c, err := e.walk(e.wrapFunction(function)) + c, err := e.walk(e.wrapFunction(function), true) if err != nil { return 0, 0, nil, err } @@ -169,7 +174,7 @@ func (e *treeEstimatorV3) estimate() (int, int, map[string]int, error) { return 0, 0, nil, errors.New("invalid verifier declaration") } e.scope.submerge() - c, err := e.walk(e.wrapFunction(verifier)) + c, err := e.walk(e.wrapFunction(verifier), false) if err != nil { return 0, 0, nil, err } @@ -197,24 +202,24 @@ func (e *treeEstimatorV3) wrapFunction(node *FunctionDeclarationNode) Node { return block } -func (e *treeEstimatorV3) walk(node Node) (int, error) { +func (e *treeEstimatorV3) walk(node Node, enableInvocation bool) (int, error) { switch n := node.(type) { case *LongNode, *BytesNode, *BooleanNode, *StringNode: return 1, nil case *ConditionalNode: - ce, err := e.walk(n.Condition) + ce, err := e.walk(n.Condition, enableInvocation) if err != nil { return 0, errors.Wrap(err, "failed to estimate the condition of if") } cs := e.scope.save() - le, err := e.walk(n.TrueExpression) + le, err := e.walk(n.TrueExpression, enableInvocation) if err != nil { return 0, errors.Wrap(err, "failed to estimate the true branch of if") } ls := e.scope.save() e.scope.restore(cs) - re, err := e.walk(n.FalseExpression) + re, err := e.walk(n.FalseExpression, enableInvocation) if err != nil { return 0, errors.Wrap(err, "failed to estimate the false branch of if") } @@ -228,13 +233,13 @@ func (e *treeEstimatorV3) walk(node Node) (int, error) { id := n.Name overlapped := e.scope.used(id) e.scope.remove(id) - c, err := e.walk(n.Block) + c, err := e.walk(n.Block, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate block after declaration of variable '%s'", id) } if e.scope.used(id) { tmp := e.scope.save() - le, err := e.walk(n.Expression) + le, err := e.walk(n.Expression, enableInvocation) if err != nil { return 0, errors.Wrap(err, "failed to estimate let expression") } @@ -256,14 +261,14 @@ func (e *treeEstimatorV3) walk(node Node) (int, error) { id := n.Name tmp := e.scope.save() e.scope.submerge() - fc, err := e.walk(n.Body) + fc, err := e.walk(n.Body, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate cost of function '%s'", id) } bodyUsages := e.scope.emerge() e.scope.restore(tmp) e.scope.setFunction(id, fc, bodyUsages) - bc, err := e.walk(n.Block) + bc, err := e.walk(n.Block, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate block after declaration of function '%s'", id) } @@ -271,7 +276,7 @@ func (e *treeEstimatorV3) walk(node Node) (int, error) { case *FunctionCallNode: id := n.Name - fc, bu, err := e.scope.function(id) + fc, bu, err := e.scope.function(id, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate the call of function '%s'", id) } @@ -281,7 +286,7 @@ func (e *treeEstimatorV3) walk(node Node) (int, error) { ac := 0 for i, a := range n.Arguments { tmp := e.scope.save() - c, err := e.walk(a) + c, err := e.walk(a, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate parameter %d of function call '%s'", i, id) } @@ -291,7 +296,7 @@ func (e *treeEstimatorV3) walk(node Node) (int, error) { return fc + ac, nil case *PropertyNode: - c, err := e.walk(n.Object) + c, err := e.walk(n.Object, enableInvocation) if err != nil { return 0, errors.Wrapf(err, "failed to estimate getter '%s'", n.Name) } diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 8112b46e5..8219579d0 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -5,7 +5,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/proto" ) -func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { +func CallVerifier(env Environment, tree *Tree) (Result, error) { e, err := treeVerifierEvaluator(env, tree) if err != nil { return nil, errors.Wrap(err, "failed to call verifier") @@ -13,7 +13,28 @@ func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } -func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { +func invokeFunctionFromDApp(env Environment, recipient proto.Recipient, fnName rideString, listArgs rideList) (Result, error) { + newScript, err := env.state().GetByteTree(recipient) + if err != nil { + return nil, errors.Wrap(err, "failed to get script by recipient") + } + + tree, err := Parse(newScript) + if err != nil { + return nil, errors.Wrap(err, "failed to get tree by script") + } + if tree.LibVersion < 5 { + return nil, errors.Errorf("failed to call 'invoke' for script with version %d. Scripts with version 5 are only allowed to be used in 'invoke'", tree.LibVersion) + } + + e, err := treeFunctionEvaluatorForInvokeDAppFromDApp(env, tree, string(fnName), listArgs) + if err != nil { + return nil, errors.Wrapf(err, "failed to call function '%s'", fnName) + } + return e.evaluate() +} + +func CallFunction(env Environment, tree *Tree, name string, args proto.Arguments) (Result, error) { if name == "" { name = "default" } @@ -21,5 +42,32 @@ func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Argum if err != nil { return nil, errors.Wrapf(err, "failed to call function '%s'", name) } - return e.evaluate() + rideResult, err := e.evaluate() + + DAppResult, ok := rideResult.(DAppResult) + if !ok { + return rideResult, err + } + if tree.LibVersion < 5 { + return rideResult, err + } + + ws, ok := env.state().(*WrappedState) + if !ok { + return nil, errors.New("wrong state") + } + + complexity, ok := ws.checkTotalComplexity() + if !ok { + return nil, errors.Errorf("complexity of invocation chain %d exceeds maximum allowed complexity of %d", complexity, MaxChainInvokeComplexity) + } + + if ws.act == nil { + return rideResult, err + } + + fullActions := ws.act + fullActions = append(fullActions, DAppResult.actions...) + DAppResult.actions = fullActions + return DAppResult, err } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index e8965cb93..20948b113 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -33,7 +33,7 @@ func TestSimpleScriptEvaluation(t *testing.T) { for _, test := range []struct { comment string source string - env RideEnvironment + env Environment res bool }{ {`V1: true`, "AQa3b8tH", nil, true}, @@ -50,6 +50,7 @@ func TestSimpleScriptEvaluation(t *testing.T) { {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + {`V4: let ref = 999; func f(ref: Int) = {let a = ref; ref }; f(1) == 999`, "BAQAAAADcmVmAAAAAAAAAAPnCgEAAAABZgAAAAEAAAADcmVmBAAAAAFhBQAAAANyZWYFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+eeAF6w", nil, false}, {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, @@ -113,6 +114,7 @@ func TestFunctionsEvaluation(t *testing.T) { } return obj }, + takeStringFunc: v5takeString, stateFunc: func() types.SmartState { return &MockSmartState{ RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { @@ -160,6 +162,9 @@ func TestFunctionsEvaluation(t *testing.T) { }, } }, + libVersionFunc: func() int { + return 3 + }, } envWithDataTX := &MockRideEnvironment{ transactionFunc: func() rideObject { @@ -169,6 +174,10 @@ func TestFunctionsEvaluation(t *testing.T) { } return obj }, + takeStringFunc: v5takeString, + libVersionFunc: func() int { + return 3 + }, } envWithExchangeTX := &MockRideEnvironment{ transactionFunc: func() rideObject { @@ -178,12 +187,16 @@ func TestFunctionsEvaluation(t *testing.T) { } return obj }, + takeStringFunc: v5takeString, + libVersionFunc: func() int { + return 3 + }, } for _, test := range []struct { name string text string script string - env RideEnvironment + env Environment result bool error bool }{ @@ -322,6 +335,8 @@ func TestFunctionsEvaluation(t *testing.T) { {`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "bebe", 10) == 5`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAKAAAAAAAAAAAFrGUCxA==`, env, true, false}, {`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "dead", 13) == 10`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAANAAAAAAAAAAAKepNV2A==`, env, true, false}, {`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "dead", 11) == 10`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAALAAAAAAAAAAAKcxKwfA==`, env, true, false}, + {`CONTAINS on incorrect UTF-8 character`, `"x冬x".contains("\ud87e")`, `BAkBAAAACGNvbnRhaW5zAAAAAgIAAAAGePCvoJp4AgAAAAE/5/PEZA==`, env, false, false}, + {`SPLIT on incorrect UTF-8 character`, `"冬x🤦冬".split("\ud87e") == ["冬x🤦冬"]`, `BAkAAAAAAAACCQAEtQAAAAICAAAADfCvoJp48J+kpvCvoJoCAAAAAT8JAARMAAAAAgIAAAAN8K+gmnjwn6Sm8K+gmgUAAAADbmlsLyxljg==`, env, true, false}, } { src, err := base64.StdEncoding.DecodeString(test.script) require.NoError(t, err, test.name) @@ -343,6 +358,56 @@ func TestFunctionsEvaluation(t *testing.T) { } } +func TestComplexity(t *testing.T) { + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return testTransferWithProofs(), nil + }} + }, + schemeFunc: func() byte { + return 'T' + }, + } + for _, test := range []struct { + comment string + source string + complexity int + }{ + {`V4: let a = 1 + 10 + 100; let b = 1000 + a + 10000; let c = a + b + 100000; c + a == 111333`, "BAQAAAABYQkAAGQAAAACCQAAZAAAAAIAAAAAAAAAAAEAAAAAAAAAAAoAAAAAAAAAAGQEAAAAAWIJAABkAAAAAgkAAGQAAAACAAAAAAAAAAPoBQAAAAFhAAAAAAAAACcQBAAAAAFjCQAAZAAAAAIJAABkAAAAAgUAAAABYQUAAAABYgAAAAAAAAGGoAkAAAAAAAACCQAAZAAAAAIFAAAAAWMFAAAAAWEAAAAAAAABsuVAqr8m", 13}, + {`V4: func f(a: Int, b: Int) = {let c = a + b; let d = a - b; c * d - 1}; f(1, 2) == -4`, "BAoBAAAAAWYAAAACAAAAAWEAAAABYgQAAAABYwkAAGQAAAACBQAAAAFhBQAAAAFiBAAAAAFkCQAAZQAAAAIFAAAAAWEFAAAAAWIJAABlAAAAAgkAAGgAAAACBQAAAAFjBQAAAAFkAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFmAAAAAgAAAAAAAAAAAQAAAAAAAAAAAgD//////////Pwcs2o=", 11}, + {`V4: let x = 1 + 1 + 1; let a = 1 + 1; func f(a: Int, b: Int) = a - b + x; let b = 4; func g(a: Int, b: Int) = a * b; let expected = (a - b + x) * (b - a + x); let actual = g(f(a, b), f(b, a)); actual == expected && actual == expected && x == 3 && a == 2 && b == 4`, "BAQAAAABeAkAAGQAAAACCQAAZAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAEEAAAAAWEJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQoBAAAAAWYAAAACAAAAAWEAAAABYgkAAGQAAAACCQAAZQAAAAIFAAAAAWEFAAAAAWIFAAAAAXgEAAAAAWIAAAAAAAAAAAQKAQAAAAFnAAAAAgAAAAFhAAAAAWIJAABoAAAAAgUAAAABYQUAAAABYgQAAAAIZXhwZWN0ZWQJAABoAAAAAgkAAGQAAAACCQAAZQAAAAIFAAAAAWEFAAAAAWIFAAAAAXgJAABkAAAAAgkAAGUAAAACBQAAAAFiBQAAAAFhBQAAAAF4BAAAAAZhY3R1YWwJAQAAAAFnAAAAAgkBAAAAAWYAAAACBQAAAAFhBQAAAAFiCQEAAAABZgAAAAIFAAAAAWIFAAAAAWEDAwMDCQAAAAAAAAIFAAAABmFjdHVhbAUAAAAIZXhwZWN0ZWQJAAAAAAAAAgUAAAAGYWN0dWFsBQAAAAhleHBlY3RlZAcJAAAAAAAAAgUAAAABeAAAAAAAAAAAAwcJAAAAAAAAAgUAAAABYQAAAAAAAAAAAgcJAAAAAAAAAgUAAAABYgAAAAAAAAAABAd/cU2j", 47}, + {`V4: let x = 1 + 1 + 1 + 1 + 1; let y = x + 1; func f(x: Int) = x + 1; func g(x: Int) = x + 1 + 1; func h(x: Int) = x + 1 + 1 + 1; f(g(h(y))) == x + x + 2`, "BAQAAAABeAkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAABBAAAAAF5CQAAZAAAAAIFAAAAAXgAAAAAAAAAAAEKAQAAAAFmAAAAAQAAAAF4CQAAZAAAAAIFAAAAAXgAAAAAAAAAAAEKAQAAAAFnAAAAAQAAAAF4CQAAZAAAAAIJAABkAAAAAgUAAAABeAAAAAAAAAAAAQAAAAAAAAAAAQoBAAAAAWgAAAABAAAAAXgJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAXgAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgkBAAAAAWYAAAABCQEAAAABZwAAAAEJAQAAAAFoAAAAAQUAAAABeQkAAGQAAAACCQAAZAAAAAIFAAAAAXgFAAAAAXgAAAAAAAAAAAJBsCoy", 21}, + {`V4: let x = 1 + 1 + 1; let y = {let z = 1; z}; y + x == 4`, "BAQAAAABeAkAAGQAAAACCQAAZAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAEEAAAAAXkEAAAAAXoAAAAAAAAAAAEFAAAAAXoJAAAAAAAAAgkAAGQAAAACBQAAAAF5BQAAAAF4AAAAAAAAAAAECwZAYA==", 7}, + {`V4: let address = Address(base58'aaaa'); address.bytes == base58'aaaa'`, "BAQAAAAHYWRkcmVzcwkBAAAAB0FkZHJlc3MAAAABAQAAAANj+GcJAAAAAAAAAggFAAAAB2FkZHJlc3MAAAAFYnl0ZXMBAAAAA2P4Z/7QEyM=", 3}, + {`V4: let x = (1, 2, 3); x._2 == 2`, "BAQAAAABeAkABRUAAAADAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAADCQAAAAAAAAIIBQAAAAF4AAAAAl8yAAAAAAAAAAACXAdyJg==", 4}, + {`V4: let a = 1 + 1; let b = a; func g() = {let a1 = 2 + 2 + 2; let c = a1; c + b + a1}; g() + a == 16`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZwAAAAAEAAAAAmExCQAAZAAAAAIJAABkAAAAAgAAAAAAAAAAAgAAAAAAAAAAAgAAAAAAAAAAAgQAAAABYwUAAAACYTEJAABkAAAAAgkAAGQAAAACBQAAAAFjBQAAAAFiBQAAAAJhMQkAAAAAAAACCQAAZAAAAAIJAQAAAAFnAAAAAAUAAAABYQAAAAAAAAAAEGbAh7s=", 13}, + {`V4: let a = 1 + 1; let b = a; func g() = {let c = 2 + 2; let d = c; d + b + c}; g() + a == 12`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZwAAAAAEAAAAAWMJAABkAAAAAgAAAAAAAAAAAgAAAAAAAAAAAgQAAAABZAUAAAABYwkAAGQAAAACCQAAZAAAAAIFAAAAAWQFAAAAAWIFAAAAAWMJAAAAAAAAAgkAAGQAAAACCQEAAAABZwAAAAAFAAAAAWEAAAAAAAAAAAxjZ1Td", 12}, + {`V4: let a = 1 + 1; let b = a; func f() = {let c = 1 + 1; c + b}; a + f() == 6`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZgAAAAAEAAAAAWMJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQkAAGQAAAACBQAAAAFjBQAAAAFiCQAAAAAAAAIJAABkAAAAAgUAAAABYQkBAAAAAWYAAAAAAAAAAAAAAAAGZR1Q1A==", 9}, + {`V4: let a = 1 + 1; let b = a; func f() = {let c = 1 + 1; c + b}; f() + a == 6`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZgAAAAAEAAAAAWMJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQkAAGQAAAACBQAAAAFjBQAAAAFiCQAAAAAAAAIJAABkAAAAAgkBAAAAAWYAAAAABQAAAAFhAAAAAAAAAAAGeznbzA==", 9}, + {`V4: let a = 1 + 1; let b = a; a + b == 4`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCQAAAAAAAAIJAABkAAAAAgUAAAABYQUAAAABYgAAAAAAAAAABClbyII=", 6}, + {`V4: let a = 1 + 1; let b = a; b + a == 4`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCQAAAAAAAAIJAABkAAAAAgUAAAABYgUAAAABYQAAAAAAAAAABApVv5E=", 6}, + {`V4: let a = 1 + 1; let b = a; func f() = b; a + f() == 4`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZgAAAAAFAAAAAWIJAAAAAAAAAgkAAGQAAAACBQAAAAFhCQEAAAABZgAAAAAAAAAAAAAAAASZ9mVe", 6}, + {`V4: let a = 1 + 1; let b = a; func f() = b; f() + a == 4`, "BAQAAAABYQkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABBAAAAAFiBQAAAAFhCgEAAAABZgAAAAAFAAAAAWIJAAAAAAAAAgkAAGQAAAACCQEAAAABZgAAAAAFAAAAAWEAAAAAAAAAAASvoK6u", 6}, + } { + src, err := base64.StdEncoding.DecodeString(test.source) + require.NoError(t, err, test.comment) + + tree, err := Parse(src) + require.NoError(t, err, test.comment) + assert.NotNil(t, tree, test.comment) + + res, err := CallVerifier(env, tree) + require.NoError(t, err, test.comment) + require.NotNil(t, res, test.comment) + + r, ok := res.(ScriptResult) + assert.True(t, ok, test.comment) + assert.Equal(t, test.complexity, r.Complexity(), test.comment) + } +} + func TestOverlapping(t *testing.T) { /*{-# STDLIB_VERSION 3 #-} {-# CONTENT_TYPE EXPRESSION #-} @@ -452,7 +517,7 @@ func TestDataFunctions(t *testing.T) { } } -func testInvokeEnv(verifier bool) (RideEnvironment, *proto.InvokeScriptWithProofs) { +func testInvokeEnv(verifier bool) (Environment, *proto.InvokeScriptWithProofs) { tx := byte_helpers.InvokeScriptWithProofs.Transaction.Clone() txo, err := transactionToObject(proto.MainNetScheme, tx) if err != nil { @@ -535,6 +600,8 @@ func TestDappCallable(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), }, sr, ) @@ -602,6 +669,8 @@ func TestDappDefaultFunc(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), }, sr, ) @@ -633,134 +702,3517 @@ func TestDappVerify(t *testing.T) { WriteSet([DataEntry("a", "b"), DataEntry("sender", sender0)]) } - @Verifier(tx) - func verify() = { - getPreviousAnswer(toString(tx.sender)) == "1" - } - */ - env, _ := testInvokeEnv(true) - code := "AAIDAAAAAAAAAAAAAAABAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAEAAAAHYWRkcmVzcwUAAAAHYWRkcmVzcwAAAAIAAAABaQEAAAAGdGVsbG1lAAAAAQAAAAhxdWVzdGlvbgQAAAAGYW5zd2VyCQEAAAARZ2V0UHJldmlvdXNBbnN3ZXIAAAABBQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkAASwAAAACBQAAAAZhbnN3ZXICAAAAAl9xBQAAAAhxdWVzdGlvbgkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkAASwAAAACBQAAAAZhbnN3ZXICAAAAAl9hBQAAAAZhbnN3ZXIFAAAAA25pbAAAAAppbnZvY2F0aW9uAQAAAAdkZWZhdWx0AAAAAAQAAAAHc2VuZGVyMAgIBQAAAAppbnZvY2F0aW9uAAAABmNhbGxlcgAAAAVieXRlcwkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQIAAAABYgkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAGc2VuZGVyBQAAAAdzZW5kZXIwBQAAAANuaWwAAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAACQAAAAAAAAIJAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAEJAAQlAAAAAQgFAAAAAnR4AAAABnNlbmRlcgIAAAABMcP91gY=" - src, err := base64.StdEncoding.DecodeString(code) - require.NoError(t, err) + @Verifier(tx) + func verify() = { + getPreviousAnswer(toString(tx.sender)) == "1" + } + */ + env, _ := testInvokeEnv(true) + code := "AAIDAAAAAAAAAAAAAAABAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAEAAAAHYWRkcmVzcwUAAAAHYWRkcmVzcwAAAAIAAAABaQEAAAAGdGVsbG1lAAAAAQAAAAhxdWVzdGlvbgQAAAAGYW5zd2VyCQEAAAARZ2V0UHJldmlvdXNBbnN3ZXIAAAABBQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkAASwAAAACBQAAAAZhbnN3ZXICAAAAAl9xBQAAAAhxdWVzdGlvbgkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkAASwAAAACBQAAAAZhbnN3ZXICAAAAAl9hBQAAAAZhbnN3ZXIFAAAAA25pbAAAAAppbnZvY2F0aW9uAQAAAAdkZWZhdWx0AAAAAAQAAAAHc2VuZGVyMAgIBQAAAAppbnZvY2F0aW9uAAAABmNhbGxlcgAAAAVieXRlcwkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQIAAAABYgkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAGc2VuZGVyBQAAAAdzZW5kZXIwBQAAAANuaWwAAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAACQAAAAAAAAIJAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAEJAAQlAAAAAQgFAAAAAnR4AAAABnNlbmRlcgIAAAABMcP91gY=" + src, err := base64.StdEncoding.DecodeString(code) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallVerifier(env, tree) + require.NoError(t, err) + r, ok := res.(ScriptResult) + require.True(t, ok) + assert.False(t, r.Result()) +} + +func TestDappVerifySuccessful(t *testing.T) { + /*{-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let x = 100500 + + func getPreviousAnswer() = { + x + } + + @Verifier(tx) + func verify() = { + getPreviousAnswer() == 100500 + } + */ + env, _ := testInvokeEnv(true) + code := "AAIDAAAAAAAAAAAAAAACAAAAAAF4AAAAAAAAAYiUAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAAFAAAAAXgAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACCQEAAAARZ2V0UHJldmlvdXNBbnN3ZXIAAAAAAAAAAAAAAYiUa4pU5Q==" + src, err := base64.StdEncoding.DecodeString(code) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallVerifier(env, tree) + require.NoError(t, err) + r, ok := res.(ScriptResult) + require.True(t, ok) + assert.True(t, r.Result()) +} + +func TestTransferSet(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func tellme(question: String) = { + TransferSet([ScriptTransfer(i.caller, 100, unit)]) + } + */ + env, tx := testInvokeEnv(false) + addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, tx.SenderPK) + require.NoError(t, err) + code := "AAIDAAAAAAAAAAAAAAAAAAAAAQAAAAFpAQAAAAZ0ZWxsbWUAAAABAAAACHF1ZXN0aW9uCQEAAAALVHJhbnNmZXJTZXQAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMIBQAAAAFpAAAABmNhbGxlcgAAAAAAAAAAZAUAAAAEdW5pdAUAAAADbmlsAAAAAH5a2L0=" + src, err := base64.StdEncoding.DecodeString(code) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + scriptTransfer := proto.TransferScriptAction{ + Recipient: proto.NewRecipientFromAddress(addr), + Amount: 100, + Asset: proto.OptionalAsset{Present: false}, + } + require.NoError(t, err) + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + require.EqualValues(t, + &proto.ScriptResult{ + DataEntries: make([]*proto.DataEntryScriptAction, 0), + Transfers: []*proto.TransferScriptAction{&scriptTransfer}, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + }, + sr, + ) +} + +func TestScriptResult(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func tellme(question: String) = { + ScriptResult( + WriteSet([DataEntry("key", 100)]), + TransferSet([ScriptTransfer(i.caller, 100500, unit)]) + ) + } + */ + env, tx := testInvokeEnv(false) + addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, tx.SenderPK) + require.NoError(t, err) + code := "AAIDAAAAAAAAAAAAAAAAAAAAAQAAAAFpAQAAAAZ0ZWxsbWUAAAABAAAACHF1ZXN0aW9uCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAABkBQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyAAAAAAAAAYiUBQAAAAR1bml0BQAAAANuaWwAAAAARKRntw==" + src, err := base64.StdEncoding.DecodeString(code) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + scriptTransfer := proto.TransferScriptAction{ + Recipient: proto.NewRecipientFromAddress(addr), + Amount: 100500, + Asset: proto.OptionalAsset{Present: false}, + } + require.Equal(t, + &proto.ScriptResult{ + DataEntries: []*proto.DataEntryScriptAction{{Entry: &proto.IntegerDataEntry{Key: "key", Value: 100}}}, + Transfers: []*proto.TransferScriptAction{&scriptTransfer}, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + }, + sr, + ) +} + +func initWrappedState(state types.SmartState, env *MockRideEnvironment) *WrappedState { + var dataEntries diffDataEntries + + dataEntries.diffInteger = map[string]proto.IntegerDataEntry{} + dataEntries.diffBool = map[string]proto.BooleanDataEntry{} + dataEntries.diffString = map[string]proto.StringDataEntry{} + dataEntries.diffBinary = map[string]proto.BinaryDataEntry{} + dataEntries.diffDDelete = map[string]proto.DeleteDataEntry{} + + balances := map[string]diffBalance{} + sponsorships := map[string]diffSponsorship{} + newAssetInfo := map[string]diffNewAssetInfo{} + oldAssetInfo := map[string]diffOldAssetInfo{} + leases := map[string]lease{} + + diffSt := &diffState{state: state, dataEntries: dataEntries, balances: balances, sponsorships: sponsorships, newAssetsInfo: newAssetInfo, oldAssetsInfo: oldAssetInfo, leases: leases} + + return &WrappedState{diff: *diffSt, cle: env.this().(rideAddress), scheme: env.scheme()} +} + +var wrappedSt WrappedState +var firstScript string +var secondScript string +var assetIDIssue crypto.Digest +var addr proto.Address +var addrPK crypto.PublicKey +var addressCallable proto.Address +var addressCallablePK crypto.PublicKey + +func smartStateDappFromDapp() types.SmartState { + return &MockSmartState{ + NewestLeasingInfoFunc: func(id crypto.Digest) (*proto.LeaseInfo, error) { + return nil, nil + }, + GetByteTreeFunc: func(recipient proto.Recipient) (proto.Script, error) { + var script proto.Script + var err error + if recipient.Address.String() == addr.String() { + script, err = base64.StdEncoding.DecodeString(firstScript) + } + if recipient.Address.String() == addressCallable.String() { + script, err = base64.StdEncoding.DecodeString(secondScript) + } + if err != nil { + return proto.Script{}, err + } + return script, nil + }, + NewestScriptByAssetFunc: func(asset proto.OptionalAsset) (proto.Script, error) { + if asset.ID.String() == "13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ" { + script := "BQQAAAALZEFwcEFkZHJlc3MJAAQmAAAAAQIAAAAjM1A4ZVpWS1M3YTR0cm9HY2t5dHhhZWZMQWk5dzdQNWFNbmEEAAAAByRtYXRjaDAFAAAAAnR4AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAA9CdXJuVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABJSZWlzc3VlVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABlTZXRBc3NldFNjcmlwdFRyYW5zYWN0aW9uBAAAAAJ0eAUAAAAHJG1hdGNoMAkAAAAAAAACCAUAAAACdHgAAAAGc2VuZGVyBQAAAAtkQXBwQWRkcmVzcwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNUcmFuc2ZlclRyYW5zYWN0aW9uBAAAAAJ0eAUAAAAHJG1hdGNoMAkAAAAAAAACCAUAAAACdHgAAAAGc2VuZGVyBQAAAAtkQXBwQWRkcmVzcwf56Ssf" + + src, err := base64.StdEncoding.DecodeString(script) + if err != nil { + return nil, err + } + return src, nil + } + return nil, nil + }, + NewestRecipientToAddressFunc: func(recipient proto.Recipient) (*proto.Address, error) { + if recipient.Alias != nil { + if recipient.Alias.Alias == "alias" { + addr, err := proto.NewAddressFromString("3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV") + return &addr, err + } + } + return recipient.Address, nil + }, + AddingBlockHeightFunc: func() (uint64, error) { + return 10, nil + }, + NewestScriptPKByAddrFunc: func(address proto.Address) (crypto.PublicKey, error) { + // payments test + if address.String() == "3P8eZVKS7a4troGckytxaefLAi9w7P5aMna" { + return crypto.NewPublicKeyFromBase58("FztxsodUc9V7iVzodkGumnZFtHnNTxYSETZfxBFAw9R3") + } + if address.String() == "3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv" { + return crypto.NewPublicKeyFromBase58("pmDSxpnULiroUAerTDFBajffTpqgwVJjtMipQq6DQM5") + } + // original caller test + if address.String() == "3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV" { + return crypto.NewPublicKeyFromBase58("AQj4MhySztn4FB3PxXc1ZcHPknLmGFYEKuSBz2vXeJPY") + } + // + if address == addr { + return crypto.NewPublicKeyFromBase58("JBjPD1xkTTcYUVhbLp1bLJLcjDKLT3c32RVk9Rue87ZD") + } + if address == addressCallable { + return crypto.NewPublicKeyFromBase58("8TLsCqkkroVot9dVR1WcWUN9Qx96HDfzG3hnx7NpSJA9") + } + + return crypto.PublicKey{}, errors.Errorf("No pk from address") + }, + NewestTransactionByIDFunc: func(id []byte) (proto.Transaction, error) { + return nil, nil + }, + NewestAccountBalanceFunc: func(account proto.Recipient, assetID []byte) (uint64, error) { + balance := 0 + return uint64(balance), nil + }, + NewestAddrByAliasFunc: func(alias proto.Alias) (proto.Address, error) { + if alias.Alias == "alias" { + return proto.NewAddressFromString("3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV") + } + return proto.Address{}, errors.New("unexpected alias") + }, + NewestFullWavesBalanceFunc: func(account proto.Recipient) (*proto.FullWavesBalance, error) { + + return &proto.FullWavesBalance{ + Regular: 0, + Generating: 0, + Available: 0, + Effective: 0, + LeaseIn: 0, + LeaseOut: 0}, nil + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + return nil, nil + }, + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + return nil, nil + }, + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + + return nil, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + + return nil, nil + }, + NewestAssetIsSponsoredFunc: func(assetID crypto.Digest) (bool, error) { + return false, nil + }, + NewestAssetInfoFunc: func(assetID crypto.Digest) (*proto.AssetInfo, error) { + if assetID.String() == "13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ" { + + return &proto.AssetInfo{ + ID: assetID, + Quantity: 1000, + Decimals: '8', + Issuer: addressCallable, + IssuerPublicKey: addressCallablePK, + Reissuable: true, + Scripted: true, + Sponsored: false, + }, nil + } + + return nil, nil + }, + NewestFullAssetInfoFunc: func(assetID crypto.Digest) (*proto.FullAssetInfo, error) { + if assetID.String() == "13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ" { + assetInfo := proto.AssetInfo{ + ID: assetID, + Quantity: 1000, + Decimals: '8', + Issuer: addressCallable, + IssuerPublicKey: addressCallablePK, + Reissuable: true, + Scripted: true, + Sponsored: false, + } + + scriptB := "BQQAAAALZEFwcEFkZHJlc3MJAAQmAAAAAQIAAAAjM1A4ZVpWS1M3YTR0cm9HY2t5dHhhZWZMQWk5dzdQNWFNbmEEAAAAByRtYXRjaDAFAAAAAnR4AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAA9CdXJuVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABJSZWlzc3VlVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABlTZXRBc3NldFNjcmlwdFRyYW5zYWN0aW9uBAAAAAJ0eAUAAAAHJG1hdGNoMAkAAAAAAAACCAUAAAACdHgAAAAGc2VuZGVyBQAAAAtkQXBwQWRkcmVzcwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR4BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIFAAAAC2RBcHBBZGRyZXNzAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNUcmFuc2ZlclRyYW5zYWN0aW9uBAAAAAJ0eAUAAAAHJG1hdGNoMAkAAAAAAAACCAUAAAACdHgAAAAGc2VuZGVyBQAAAAtkQXBwQWRkcmVzcwf56Ssf" + + src, err := base64.StdEncoding.DecodeString(scriptB) + if err != nil { + return nil, err + } + + scriptInfo := proto.ScriptInfo{ + Version: 5, + Bytes: src, + Base64: "", + Complexity: 0, + } + + return &proto.FullAssetInfo{ + AssetInfo: assetInfo, + Name: "CatCoin", + Description: "", + ScriptInfo: scriptInfo, + SponsorshipCost: uint64(0), + }, nil + } + return nil, nil + }, + } +} + +var thisAddress proto.Address +var tx *proto.InvokeScriptWithProofs +var inv rideObject +var id []byte + +func WrappedStateFunc() types.SmartState { + return &wrappedSt +} + +var envDappFromDapp = &MockRideEnvironment{ + setInvocationFunc: func(invocation rideObject) { + inv = invocation + }, + schemeFunc: func() byte { + return proto.MainNetScheme + }, + stateFunc: WrappedStateFunc, + txIDFunc: func() rideType { + return rideBytes(id) + }, + thisFunc: func() rideType { + return rideAddress(thisAddress) + }, + setNewDAppAddressFunc: func(address proto.Address) { + thisAddress = address + wrappedSt.cle = rideAddress(address) + }, + transactionFunc: func() rideObject { + obj, _ := transactionToObject(proto.MainNetScheme, tx) + return obj + }, + invocationFunc: func() rideObject { + return inv + }, + timestampFunc: func() uint64 { + return 1564703444249 + }, +} + +func tearDownDappFromDapp() { + wrappedSt = WrappedState{} + firstScript = "" + secondScript = "" + assetIDIssue = crypto.Digest{} + addr = proto.Address{} + addressCallable = proto.Address{} + addrPK = crypto.PublicKey{} + addressCallablePK = crypto.PublicKey{} + + thisAddress = proto.Address{} + tx = nil + id = nil +} + +func AddExternalPayments(externalPayments proto.ScriptPayments, callerPK crypto.PublicKey) error { + caller, err := proto.NewAddressFromPublicKey(envDappFromDapp.scheme(), callerPK) + if err != nil { + return err + } + recipient := proto.NewRecipientFromAddress(wrappedSt.callee()) + + for _, payment := range externalPayments { + senderBalance, err := wrappedSt.NewestAccountBalance(proto.NewRecipientFromAddress(caller), payment.Asset.ID.Bytes()) + if err != nil { + return err + } + if senderBalance < payment.Amount { + return errors.New("not enough money for tx attached payments") + } + + searchBalance, searchAddr, err := wrappedSt.diff.findBalance(recipient, payment.Asset) + if err != nil { + return err + } + err = wrappedSt.diff.changeBalance(searchBalance, searchAddr, int64(payment.Amount), payment.Asset.ID, recipient) + if err != nil { + return err + } + + callerRcp := proto.NewRecipientFromAddress(caller) + senderSearchBalance, senderSearchAddr, err := wrappedSt.diff.findBalance(callerRcp, payment.Asset) + if err != nil { + return err + } + + err = wrappedSt.diff.changeBalance(senderSearchBalance, senderSearchAddr, -int64(payment.Amount), payment.Asset.ID, callerRcp) + if err != nil { + return err + } + } + return nil +} + +func AddWavesToSender(senderAddress proto.Address, amount int64, asset proto.OptionalAsset) error { + senderRecipient := proto.NewRecipientFromAddress(senderAddress) + + searchBalance, searchAddr, err := wrappedSt.diff.findBalance(senderRecipient, asset) + if err != nil { + return err + } + err = wrappedSt.diff.changeBalance(searchBalance, searchAddr, amount, asset.ID, senderRecipient) + if err != nil { + return err + } + + return nil +} + +func TestInvokeDAppFromDAppAllActions(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func test() = { + let res = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "testActions",[], [AttachedPayment(base58'', 1234), AttachedPayment(base58'', 1234)]) + if res == 17 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Bad returned value") + } + */ + + /* script 2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func testActions() = { + let asset = Issue("CatCoin", "", 1, 0, true, unit, 0) + let assetId = asset.calculateAssetId() + + ([ + ScriptTransfer(Address(base58'3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv'), 1, unit), + Lease(Address(base58'3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv'), 10), + BinaryEntry("bin", base58''), + BooleanEntry("bool", true), + IntegerEntry("int", 1), + StringEntry("str", ""), + DeleteEntry("str"), + asset, + Reissue(assetId, 10, false), + Burn(assetId, 5) + ], 17) + } + */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAAEdGVzdAAAAAAEAAAAA3JlcwkAA/wAAAAECQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXSbIqC+dSm+dDCCL8KamODy9oLyPQygrLAgAAAAt0ZXN0QWN0aW9ucwUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACAQAAAAAAAAAAAAAABNIJAARMAAAAAgkBAAAAD0F0dGFjaGVkUGF5bWVudAAAAAIBAAAAAAAAAAAAAAAE0gUAAAADbmlsAwkAAAAAAAACBQAAAANyZXMAAAAAAAAAABEJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2tleQAAAAAAAAAAAQUAAAADbmlsCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQAAAABtSYQY" + secondScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAALdGVzdEFjdGlvbnMAAAAABAAAAAVhc3NldAkABEMAAAAHAgAAAAdDYXRDb2luAgAAAAAAAAAAAAAAAAEAAAAAAAAAAAAGBQAAAAR1bml0AAAAAAAAAAAABAAAAAdhc3NldElkCQAEOAAAAAEFAAAABWFzc2V0CQAFFAAAAAIJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwkBAAAAB0FkZHJlc3MAAAABAQAAABoBV5hs3CAFUz6eTef/H4C7v1yCbCqvykvRuQAAAAAAAAAAAQUAAAAEdW5pdAkABEwAAAACCQAERAAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVeYbNwgBVM+nk3n/x+Au79cgmwqr8pL0bkAAAAAAAAAAAoJAARMAAAAAgkBAAAAC0JpbmFyeUVudHJ5AAAAAgIAAAADYmluAQAAAAAJAARMAAAAAgkBAAAADEJvb2xlYW5FbnRyeQAAAAICAAAABGJvb2wGCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACAgAAAANpbnQAAAAAAAAAAAEJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgIAAAADc3RyAgAAAAAJAARMAAAAAgkBAAAAC0RlbGV0ZUVudHJ5AAAAAQIAAAADc3RyCQAETAAAAAIFAAAABWFzc2V0CQAETAAAAAIJAQAAAAdSZWlzc3VlAAAAAwUAAAAHYXNzZXRJZAAAAAAAAAAACgcJAARMAAAAAgkBAAAABEJ1cm4AAAACBQAAAAdhc3NldElkAAAAAAAAAAAFBQAAAANuaWwAAAAAAAAAABEAAAAAeF27eQ==" + + id = bytes.Repeat([]byte{0}, 32) + + expectedIssueWrites := []*proto.IssueScriptAction{ + {Sender: &addressCallablePK, Name: "CatCoin", Description: "", Quantity: 1, Decimals: 0, Reissuable: true, Script: nil, Nonce: 0}, + } + expectedReissueWrites := []*proto.ReissueScriptAction{ + {Sender: &addressCallablePK, Quantity: 10, Reissuable: false}, + } + expectedBurnWrites := []*proto.BurnScriptAction{ + {Sender: &addressCallablePK, Quantity: 5}, + } + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.BinaryDataEntry{Key: "bin", Value: []byte("")}, Sender: &addressCallablePK}, + {Entry: &proto.BooleanDataEntry{Key: "bool", Value: true}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "int", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.StringDataEntry{Key: "str", Value: ""}, Sender: &addressCallablePK}, + {Entry: &proto.DeleteDataEntry{Key: "str"}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Sender: &addrPK, Recipient: recipientCallable, Amount: 1234, Asset: proto.OptionalAsset{}}, + {Sender: &addrPK, Recipient: recipientCallable, Amount: 1234, Asset: proto.OptionalAsset{}}, + {Sender: &addressCallablePK, Recipient: recipient, Amount: 1, Asset: proto.OptionalAsset{}}, + } + + expectedLeaseWrites := []*proto.LeaseScriptAction{ + {Sender: &addressCallablePK, Recipient: recipient, Amount: 10, Nonce: 0}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + pid, ok := env.txID().(rideBytes) + require.True(t, ok) + d, err := crypto.NewDigestFromBytes(pid) + require.NoError(t, err) + expectedIssueWrites[0].ID = proto.GenerateIssueScriptActionID(expectedIssueWrites[0].Name, expectedIssueWrites[0].Description, int64(expectedIssueWrites[0].Decimals), expectedIssueWrites[0].Quantity, expectedIssueWrites[0].Reissuable, expectedIssueWrites[0].Nonce, d) + expectedReissueWrites[0].AssetID = expectedIssueWrites[0].ID + expectedBurnWrites[0].AssetID = expectedIssueWrites[0].ID + assetIDIssue = expectedIssueWrites[0].ID + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedLeaseWrites[0].ID = sr.Leases[0].ID + assetExp := proto.OptionalAsset{} + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: expectedIssueWrites, + Reissues: expectedReissueWrites, + Burns: expectedBurnWrites, + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: expectedLeaseWrites, + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) + + fullBalanceExpected := &proto.FullWavesBalance{ + Regular: 7533, + Generating: 0, + Available: 7533, + Effective: 7543, + LeaseIn: 10, + LeaseOut: 0, + } + fullBalance, err := wrappedSt.NewestFullWavesBalance(recipient) + + require.NoError(t, err) + assert.Equal(t, fullBalance, fullBalanceExpected) + + fullBalanceCallableExpected := &proto.FullWavesBalance{ + Regular: 2467, + Generating: 0, + Available: 2457, + Effective: 2457, + LeaseIn: 0, + LeaseOut: 10, + } + fullBalanceCallable, err := wrappedSt.NewestFullWavesBalance(recipientCallable) + require.NoError(t, err) + assert.Equal(t, fullBalanceCallable, fullBalanceCallableExpected) + + expectedDiffResult := initWrappedState(smartState(), env).diff + balance := diffBalance{regular: 7533, leaseIn: 10, asset: assetExp, effectiveHistory: []int64{7543}} + expectedDiffResult.balances[addr.String()+assetExp.String()] = balance + + balanceSender := diffBalance{regular: 0, leaseOut: 0, asset: assetExp} + expectedDiffResult.balances[senderAddress.String()+assetExp.String()] = balanceSender + + balanceCallable := diffBalance{regular: 2467, leaseOut: 10, asset: assetExp, effectiveHistory: []int64{2467, 2457}} + expectedDiffResult.balances[addressCallable.String()+assetExp.String()] = balanceCallable + + assetFromIssue := *proto.NewOptionalAssetFromDigest(sr.Issues[0].ID) + balanceCallableAsset := diffBalance{regular: 1, leaseOut: 0, asset: assetFromIssue} + expectedDiffResult.balances[addressCallable.String()+assetFromIssue.String()] = balanceCallableAsset + + intEntry1 := proto.IntegerDataEntry{Key: "int", Value: 1} + expectedDiffResult.dataEntries.diffInteger["int"+addressCallable.String()] = intEntry1 + + boolEntry := proto.BooleanDataEntry{Key: "bool", Value: true} + expectedDiffResult.dataEntries.diffBool["bool"+addressCallable.String()] = boolEntry + + stringEntry := proto.StringDataEntry{Key: "str", Value: ""} + expectedDiffResult.dataEntries.diffString["str"+addressCallable.String()] = stringEntry + + binaryEntry := proto.BinaryDataEntry{Key: "bin", Value: []byte("")} + expectedDiffResult.dataEntries.diffBinary["bin"+addressCallable.String()] = binaryEntry + + deleteEntry := proto.DeleteDataEntry{Key: "str"} + expectedDiffResult.dataEntries.diffDDelete["str"+addressCallable.String()] = deleteEntry + + newAsset := diffNewAssetInfo{dAppIssuer: addressCallable, name: "CatCoin", description: "", quantity: 6, decimals: 0, reissuable: false, script: nil, nonce: 0} + expectedDiffResult.newAssetsInfo[assetIDIssue.String()] = newAsset + + lease := lease{Recipient: recipient, Sender: recipientCallable, leasedAmount: 10} + expectedDiffResult.leases[expectedLeaseWrites[0].ID.String()] = lease + + assert.Equal(t, expectedDiffResult.newAssetsInfo, wrappedSt.diff.newAssetsInfo) + assert.Equal(t, expectedDiffResult.oldAssetsInfo, wrappedSt.diff.oldAssetsInfo) + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + assert.Equal(t, expectedDiffResult.sponsorships, wrappedSt.diff.sponsorships) + assert.Equal(t, expectedDiffResult.leases, wrappedSt.diff.leases) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppScript1(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5#-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar() = { + ([IntegerEntry("bar", 1)], "return") + } + + @Callable(i) + func foo() = { + let r = Invoke(this, "bar", [], []) + if r == "return" + then + let data = getIntegerValue(this, "bar") + if data == 1 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Bad state") + else + throw("Bad returned value") + } + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAANiYXIAAAAACQAFFAAAAAIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2JhcgAAAAAAAAAAAQUAAAADbmlsAgAAAAZyZXR1cm4AAAABaQEAAAADZm9vAAAAAAQAAAABcgkAA/wAAAAEBQAAAAR0aGlzAgAAAANiYXIFAAAAA25pbAUAAAADbmlsAwkAAAAAAAACBQAAAAFyAgAAAAZyZXR1cm4EAAAABGRhdGEJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAA2JhcgMJAAAAAAAAAgUAAAAEZGF0YQAAAAAAAAAAAQkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAABBQAAAANuaWwJAAACAAAAAQIAAAAJQmFkIHN0YXRlCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQAAAADz23Fz" + + id = bytes.Repeat([]byte{0}, 32) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addrPK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: make([]*proto.TransferScriptAction, 0), + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + intEntry1 := proto.IntegerDataEntry{Key: "bar", Value: 1} + expectedDiffResult.dataEntries.diffInteger["bar"+addr.String()] = intEntry1 + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppScript2(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let b1 = wavesBalance(this) + let ob1 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if b1 == b1 && ob1 == ob1 + then + let r = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) + if r == 17 + then + let data = getIntegerValue(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar") + let b2 = wavesBalance(this) + let ob2 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if data == 1 + then + if ob1.regular+14 == ob2.regular && b1.regular == b2.regular+14 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Balance check failed") + else + throw("Bad state") + else + throw("Bad returned value") + else + throw("Imposible") + } + */ + + /* + script2 + + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar(a: ByteVector) = { + ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) + } + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAACYjEJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IxCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDAwkAAAAAAAACBQAAAAJiMQUAAAACYjEJAAAAAAAAAgUAAAADb2IxBQAAAANvYjEHBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgkABEwAAAACCAUAAAAEdGhpcwAAAAVieXRlcwUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACBQAAAAR1bml0AAAAAAAAAAARBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIAAAAAAAAAABEEAAAABGRhdGEJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgQAAAACYjIJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IyCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEDAwkAAAAAAAACCQAAZAAAAAIIBQAAAANvYjEAAAAHcmVndWxhcgAAAAAAAAAADggFAAAAA29iMgAAAAdyZWd1bGFyCQAAAAAAAAIIBQAAAAJiMQAAAAdyZWd1bGFyCQAAZAAAAAIIBQAAAAJiMgAAAAdyZWd1bGFyAAAAAAAAAAAOBwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAABBQAAAANuaWwJAAACAAAAAQIAAAAUQmFsYW5jZSBjaGVjayBmYWlsZWQJAAACAAAAAQIAAAAJQmFkIHN0YXRlCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQkAAAIAAAABAgAAAAlJbXBvc2libGUAAAAAjMpPSg==" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhCQAFFAAAAAIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2JhcgAAAAAAAAAAAQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAAHQWRkcmVzcwAAAAEFAAAAAWEAAAAAAAAAAAMFAAAABHVuaXQFAAAAA25pbAAAAAAAAAAAEQAAAAAyrXjp" + + id = bytes.Repeat([]byte{0}, 32) + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Sender: &addrPK, Recipient: recipientCallable, Amount: 17, Asset: proto.OptionalAsset{}}, + {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, + } + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9986, effectiveHistory: []int64{10000, 9986}} + balanceSender := diffBalance{regular: 0, leaseOut: 0, asset: proto.OptionalAsset{}} + balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 14, effectiveHistory: []int64{0, 14}} + intEntry := proto.IntegerDataEntry{Key: "bar", Value: 1} + expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry + expectedDiffResult.balances[addressCallable.String()+proto.NewOptionalAssetWaves().String()] = balanceCallable + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + expectedDiffResult.balances[addr.String()+proto.NewOptionalAssetWaves().String()] = balanceMain + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppScript3(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let b1 = wavesBalance(this) + let ob1 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if b1 == b1 && ob1 == ob1 + then + let r = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) + if r == 17 + then + let data = getIntegerValue(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar") + let b2 = wavesBalance(this) + let ob2 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if data == 1 + then + if ob1.regular+14 == ob2.regular && b1.regular == b2.regular+14 + then + let r1 = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 18)]) + if r1 == r1 + then + let b3 = wavesBalance(this) + let ob3 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if ob2.regular+15 == ob3.regular && b2.regular == b3.regular+15 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Bad balance after second invoke") + else + throw("Imposible") + else + throw("Balance check failed") + else + throw("Bad state") + else + throw("Bad returned value") + else + throw("Imposible") + } + */ + + /* + script2 + + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar(a: ByteVector) = { + ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) + } + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAACYjEJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IxCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDAwkAAAAAAAACBQAAAAJiMQUAAAACYjEJAAAAAAAAAgUAAAADb2IxBQAAAANvYjEHBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgkABEwAAAACCAUAAAAEdGhpcwAAAAVieXRlcwUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACBQAAAAR1bml0AAAAAAAAAAARBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIAAAAAAAAAABEEAAAABGRhdGEJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgQAAAACYjIJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IyCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEDAwkAAAAAAAACCQAAZAAAAAIIBQAAAANvYjEAAAAHcmVndWxhcgAAAAAAAAAADggFAAAAA29iMgAAAAdyZWd1bGFyCQAAAAAAAAIIBQAAAAJiMQAAAAdyZWd1bGFyCQAAZAAAAAIIBQAAAAJiMgAAAAdyZWd1bGFyAAAAAAAAAAAOBwQAAAACcjEJAAP8AAAABAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAADYmFyCQAETAAAAAIIBQAAAAR0aGlzAAAABWJ5dGVzBQAAAANuaWwJAARMAAAAAgkBAAAAD0F0dGFjaGVkUGF5bWVudAAAAAIFAAAABHVuaXQAAAAAAAAAABIFAAAAA25pbAMJAAAAAAAAAgUAAAACcjEFAAAAAnIxBAAAAAJiMwkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjMJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywMDCQAAAAAAAAIJAABkAAAAAggFAAAAA29iMgAAAAdyZWd1bGFyAAAAAAAAAAAPCAUAAAADb2IzAAAAB3JlZ3VsYXIJAAAAAAAAAggFAAAAAmIyAAAAB3JlZ3VsYXIJAABkAAAAAggFAAAAAmIzAAAAB3JlZ3VsYXIAAAAAAAAAAA8HCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACAgAAAANrZXkAAAAAAAAAAAEFAAAAA25pbAkAAAIAAAABAgAAAB9CYWQgYmFsYW5jZSBhZnRlciBzZWNvbmQgaW52b2tlCQAAAgAAAAECAAAACUltcG9zaWJsZQkAAAIAAAABAgAAABRCYWxhbmNlIGNoZWNrIGZhaWxlZAkAAAIAAAABAgAAAAlCYWQgc3RhdGUJAAACAAAAAQIAAAASQmFkIHJldHVybmVkIHZhbHVlCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAABDUPNk" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhCQAFFAAAAAIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2JhcgAAAAAAAAAAAQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAAHQWRkcmVzcwAAAAEFAAAAAWEAAAAAAAAAAAMFAAAABHVuaXQFAAAAA25pbAAAAAAAAAAAEQAAAAAyrXjp" + + id = bytes.Repeat([]byte{0}, 32) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Sender: &addrPK, Recipient: recipientCallable, Amount: 17, Asset: proto.OptionalAsset{}}, + {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, + {Sender: &addrPK, Recipient: recipientCallable, Amount: 18, Asset: proto.OptionalAsset{}}, + {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9971, effectiveHistory: []int64{10000, 9986, 9971}} + balanceSender := diffBalance{regular: 0, leaseOut: 0, asset: proto.OptionalAsset{}} + balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 29, effectiveHistory: []int64{0, 14, 29}} + intEntry := proto.IntegerDataEntry{Key: "bar", Value: 1} + expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry + expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallable + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + + tearDownDappFromDapp() +} + +//TODO change this test from Invoke to ReentrantInvoke +//func TestInvokeDAppFromDAppScript4(t *testing.T) { +// +// /* script 1 +// {-# STDLIB_VERSION 5 #-} +// {-# CONTENT_TYPE DAPP #-} +// {-#SCRIPT_TYPE ACCOUNT#-} +// +// @Callable(i) +// func back() = { +// [IntegerEntry("key", 0), ScriptTransfer(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), 2, unit)] +// } +// +// @Callable(i) +// func foo() = { +// let b1 = wavesBalance(this) +// let ob1 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) +// if b1 == b1 && ob1 == ob1 +// then +// let r = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) +// if r == 17 +// then +// let data = getIntegerValue(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar") +// let tdata = getIntegerValue(this, "key") +// let b2 = wavesBalance(this) +// let ob2 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) +// if data == 1 && tdata == 0 +// then +// if ob1.regular+16 == ob2.regular && b1.regular == b2.regular+16 +// then +// [ +// IntegerEntry("key", 1) +// ] +// else +// throw("Balance check failed") +// else +// throw("Bad state") +// else +// throw("Bad returned value") +// else +// throw("Imposible") +// } +// */ +// +// /* +// script2 +// {-# STDLIB_VERSION 5 #-} +// {-# CONTENT_TYPE DAPP #-} +// {-#SCRIPT_TYPE ACCOUNT#-} +// +// @Callable(i) +// func bar(a: ByteVector) = { +// let r = Invoke(Address(a), "back", [], []) +// if r == r +// then +// ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) +// else +// throw("Imposible") +// } +// +// */ +// txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") +// require.NoError(t, err) +// proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") +// require.NoError(t, err) +// proofs := proto.NewProofs() +// proofs.Proofs = []proto.B58Bytes{proof[:]} +// sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") +// require.NoError(t, err) +// senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) +// require.NoError(t, err) +// +// addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") +// require.NoError(t, err) +// recipient := proto.NewRecipientFromAddress(addr) +// addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr, false) +// require.NoError(t, err) +// +// addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") +// require.NoError(t, err) +// recipientCallable := proto.NewRecipientFromAddress(addressCallable) +// addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable, false) +// require.NoError(t, err) +// +// arguments := proto.Arguments{} +// arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) +// +// call := proto.FunctionCall{ +// Default: false, +// Name: "cancel", +// Arguments: arguments, +// } +// tx = &proto.InvokeScriptWithProofs{ +// Type: proto.InvokeScriptTransaction, +// Version: 1, +// ID: &txID, +// Proofs: proofs, +// ChainID: proto.MainNetScheme, +// SenderPK: sender, +// ScriptRecipient: recipient, +// FunctionCall: call, +// Payments: proto.ScriptPayments{proto.ScriptPayment{ +// Amount: 10000, +// Asset: proto.OptionalAsset{}, +// }}, +// FeeAsset: proto.OptionalAsset{}, +// Fee: 900000, +// Timestamp: 1564703444249, +// } +// inv, _ = invocationToObject(4, proto.MainNetScheme, tx) +// +// firstScript = "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAARiYWNrAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAAACQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssAAAAAAAAAAAIFAAAABHVuaXQFAAAAA25pbAAAAAFpAQAAAANmb28AAAAABAAAAAJiMQkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjEJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywMDCQAAAAAAAAIFAAAAAmIxBQAAAAJiMQkAAAAAAAACBQAAAANvYjEFAAAAA29iMQcEAAAAAXIJAAP8AAAABAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAADYmFyCQAETAAAAAIIBQAAAAR0aGlzAAAABWJ5dGVzBQAAAANuaWwJAARMAAAAAgkBAAAAD0F0dGFjaGVkUGF5bWVudAAAAAIFAAAABHVuaXQAAAAAAAAAABEFAAAAA25pbAMJAAAAAAAAAgUAAAABcgAAAAAAAAAAEQQAAAAEZGF0YQkBAAAAEUBleHRyTmF0aXZlKDEwNTApAAAAAgkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAADYmFyBAAAAAV0ZGF0YQkBAAAAEUBleHRyTmF0aXZlKDEwNTApAAAAAgUAAAAEdGhpcwIAAAADa2V5BAAAAAJiMgkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjIJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywMDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEJAAAAAAAAAgUAAAAFdGRhdGEAAAAAAAAAAAAHAwMJAAAAAAAAAgkAAGQAAAACCAUAAAADb2IxAAAAB3JlZ3VsYXIAAAAAAAAAABAIBQAAAANvYjIAAAAHcmVndWxhcgkAAAAAAAACCAUAAAACYjEAAAAHcmVndWxhcgkAAGQAAAACCAUAAAACYjIAAAAHcmVndWxhcgAAAAAAAAAAEAcJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2tleQAAAAAAAAAAAQUAAAADbmlsCQAAAgAAAAECAAAAFEJhbGFuY2UgY2hlY2sgZmFpbGVkCQAAAgAAAAECAAAACUJhZCBzdGF0ZQkAAAIAAAABAgAAABJCYWQgcmV0dXJuZWQgdmFsdWUJAAACAAAAAQIAAAAJSW1wb3NpYmxlAAAAAOgXYAY=" +// secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQIAAAAEYmFjawUAAAADbmlsBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIFAAAAAXIJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADYmFyAAAAAAAAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQAAAAAAAAAAAwUAAAAEdW5pdAUAAAADbmlsAAAAAAAAAAARCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAACf+Ofn" +// +// id = bytes.Repeat([]byte{0}, 32) +// +// expectedDataEntryWrites := []*proto.DataEntryScriptAction{ +// {Entry: &proto.IntegerDataEntry{Key: "key", Value: 0}, Sender: &addrPK}, +// {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, +// {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, +// } +// +// expectedTransferWrites := []*proto.TransferScriptAction{ +// {Sender: &addrPK, Recipient: recipientCallable, Amount: 17, Asset: proto.OptionalAsset{}}, +// {Sender: &addrPK, Recipient: recipientCallable, Amount: 2, Asset: proto.OptionalAsset{}}, +// {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, +// } +// +// smartState := smartStateDappFromDapp +// +// thisAddress = addr +// +// env := envDappFromDapp +// +// NewWrappedSt := initWrappedState(smartState(), env) +// wrappedSt = *NewWrappedSt +// +// err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) +// require.NoError(t, err) +// err = AddExternalPayments(tx.Payments, tx.SenderPK) +// require.NoError(t, err) +// +// src, err := base64.StdEncoding.DecodeString(firstScript) +// require.NoError(t, err) +// +// tree, err := Parse(src) +// require.NoError(t, err) +// assert.NotNil(t, tree) +// +// res, err := CallFunction(env, tree, "foo", proto.Arguments{}) +// +// require.NoError(t, err) +// r, ok := res.(DAppResult) +// require.True(t, ok) +// require.True(t, r.res) +// +// sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) +// require.NoError(t, err) +// +// expectedActionsResult := &proto.ScriptResult{ +// DataEntries: expectedDataEntryWrites, +// Transfers: expectedTransferWrites, +// Issues: make([]*proto.IssueScriptAction, 0), +// Reissues: make([]*proto.ReissueScriptAction, 0), +// Burns: make([]*proto.BurnScriptAction, 0), +// Sponsorships: make([]*proto.SponsorshipScriptAction, 0), +// Leases: make([]*proto.LeaseScriptAction, 0), +// LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), +// } +// assert.Equal(t, expectedActionsResult, sr) +// +// expectedDiffResult := initWrappedState(smartState(), env).diff +// +// balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9984, effectiveHistory: []int64{10000, 9984}} +// balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} +// balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 16, effectiveHistory: []int64{0, 16}} +// intEntry1 := proto.IntegerDataEntry{Key: "key", Value: 0} +// intEntry2 := proto.IntegerDataEntry{Key: "bar", Value: 1} +// expectedDiffResult.dataEntries.diffInteger["key"+addr.String()] = intEntry1 +// expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry2 +// expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain +// expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender +// expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallable +// +// assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) +// assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) +// +// tearDownDappFromDapp() +//} + +func TestNegativeCycleNewInvokeDAppFromDAppScript4(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func back() = { + [IntegerEntry("key", 0), ScriptTransfer(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), 2, unit)] + } + + @Callable(i) + func foo() = { + let b1 = wavesBalance(this) + let ob1 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if b1 == b1 && ob1 == ob1 + then + let r = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) + if r == 17 + then + let data = getIntegerValue(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar") + let tdata = getIntegerValue(this, "key") + let b2 = wavesBalance(this) + let ob2 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) + if data == 1 && tdata == 0 + then + if ob1.regular+16 == ob2.regular && b1.regular == b2.regular+16 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Balance check failed") + else + throw("Bad state") + else + throw("Bad returned value") + else + throw("Imposible") + } + */ + + /* + script2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar(a: ByteVector) = { + let r = Invoke(Address(a), "back", [], []) + if r == r + then + ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) + else + throw("Imposible") + } + + + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAARiYWNrAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAAACQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssAAAAAAAAAAAIFAAAABHVuaXQFAAAAA25pbAAAAAFpAQAAAANmb28AAAAABAAAAAJiMQkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjEJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywMDCQAAAAAAAAIFAAAAAmIxBQAAAAJiMQkAAAAAAAACBQAAAANvYjEFAAAAA29iMQcEAAAAAXIJAAP8AAAABAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAADYmFyCQAETAAAAAIIBQAAAAR0aGlzAAAABWJ5dGVzBQAAAANuaWwJAARMAAAAAgkBAAAAD0F0dGFjaGVkUGF5bWVudAAAAAIFAAAABHVuaXQAAAAAAAAAABEFAAAAA25pbAMJAAAAAAAAAgUAAAABcgAAAAAAAAAAEQQAAAAEZGF0YQkBAAAAEUBleHRyTmF0aXZlKDEwNTApAAAAAgkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAADYmFyBAAAAAV0ZGF0YQkBAAAAEUBleHRyTmF0aXZlKDEwNTApAAAAAgUAAAAEdGhpcwIAAAADa2V5BAAAAAJiMgkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjIJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywMDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEJAAAAAAAAAgUAAAAFdGRhdGEAAAAAAAAAAAAHAwMJAAAAAAAAAgkAAGQAAAACCAUAAAADb2IxAAAAB3JlZ3VsYXIAAAAAAAAAABAIBQAAAANvYjIAAAAHcmVndWxhcgkAAAAAAAACCAUAAAACYjEAAAAHcmVndWxhcgkAAGQAAAACCAUAAAACYjIAAAAHcmVndWxhcgAAAAAAAAAAEAcJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2tleQAAAAAAAAAAAQUAAAADbmlsCQAAAgAAAAECAAAAFEJhbGFuY2UgY2hlY2sgZmFpbGVkCQAAAgAAAAECAAAACUJhZCBzdGF0ZQkAAAIAAAABAgAAABJCYWQgcmV0dXJuZWQgdmFsdWUJAAACAAAAAQIAAAAJSW1wb3NpYmxlAAAAAOgXYAY=" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQIAAAAEYmFjawUAAAADbmlsBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIFAAAAAXIJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADYmFyAAAAAAAAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQAAAAAAAAAAAwUAAAAEdW5pdAUAAAADbmlsAAAAAAAAAAARCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAACf+Ofn" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.Error(t, err) + r, ok := res.(DAppResult) + require.False(t, ok) + require.False(t, r.res) + + tearDownDappFromDapp() +} + +//TODO change this test from Invoke to ReentrantInvoke +//func TestInvokeDAppFromDAppScript5(t *testing.T) { +// +// /* script 1 +// {-# STDLIB_VERSION 5 #-} +// {-# CONTENT_TYPE DAPP #-} +// {-#SCRIPT_TYPE ACCOUNT#-} +// +// @Callable(i) +// func back() = { +// [ScriptTransfer(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), 2, unit)] +// } +// +// @Callable(i) +// func foo() = { +// let b1 = wavesBalance(this) +// let ob1 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) +// if b1 == b1 && ob1 == ob1 +// then +// let r = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) +// if r == 17 +// then +// let data = getIntegerValue(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar") +// let b2 = wavesBalance(this) +// let ob2 = wavesBalance(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna')) +// if data == 1 +// then +// if ob1.regular+13 == ob2.regular && b1.regular == b2.regular+13 +// then +// [ +// IntegerEntry("key", 1) +// ] +// else +// throw("Balance check failed") +// else +// throw("Bad state") +// else +// throw("Bad returned value") +// else +// throw("Imposible") +// } +// */ +// +// /* +// script2 +// {-# STDLIB_VERSION 5 #-} +// {-# CONTENT_TYPE DAPP #-} +// {-#SCRIPT_TYPE ACCOUNT#-} +// +// @Callable(i) +// func bar(a: ByteVector) = { +// let r = Invoke(Address(a), "back", [], [AttachedPayment(unit, 3)]) +// if r == r +// then +// ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) +// else +// throw("Imposible") +// } + +// */ +// txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") +// require.NoError(t, err) +// proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") +// require.NoError(t, err) +// proofs := proto.NewProofs() +// proofs.Proofs = []proto.B58Bytes{proof[:]} +// sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") +// require.NoError(t, err) +// senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) +// require.NoError(t, err) +// +// addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") +// require.NoError(t, err) +// recipient := proto.NewRecipientFromAddress(addr) +// addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr, false) +// require.NoError(t, err) +// +// addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") +// require.NoError(t, err) +// recipientCallable := proto.NewRecipientFromAddress(addressCallable) +// addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable, false) +// require.NoError(t, err) +// +// arguments := proto.Arguments{} +// arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) +// +// call := proto.FunctionCall{ +// Default: false, +// Name: "cancel", +// Arguments: arguments, +// } +// tx = &proto.InvokeScriptWithProofs{ +// Type: proto.InvokeScriptTransaction, +// Version: 1, +// ID: &txID, +// Proofs: proofs, +// ChainID: proto.MainNetScheme, +// SenderPK: sender, +// ScriptRecipient: recipient, +// FunctionCall: call, +// Payments: proto.ScriptPayments{proto.ScriptPayment{ +// Amount: 10000, +// Asset: proto.OptionalAsset{}, +// }}, +// FeeAsset: proto.OptionalAsset{}, +// Fee: 900000, +// Timestamp: 1564703444249, +// } +// inv, _ = invocationToObject(4, proto.MainNetScheme, tx) +// +// firstScript = "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAARiYWNrAAAAAAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXSbIqC+dSm+dDCCL8KamODy9oLyPQygrLAAAAAAAAAAACBQAAAAR1bml0BQAAAANuaWwAAAABaQEAAAADZm9vAAAAAAQAAAACYjEJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IxCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDAwkAAAAAAAACBQAAAAJiMQUAAAACYjEJAAAAAAAAAgUAAAADb2IxBQAAAANvYjEHBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgkABEwAAAACCAUAAAAEdGhpcwAAAAVieXRlcwUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACBQAAAAR1bml0AAAAAAAAAAARBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIAAAAAAAAAABEEAAAABGRhdGEJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgQAAAACYjIJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IyCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEDAwkAAAAAAAACCQAAZAAAAAIIBQAAAANvYjEAAAAHcmVndWxhcgAAAAAAAAAADQgFAAAAA29iMgAAAAdyZWd1bGFyCQAAAAAAAAIIBQAAAAJiMQAAAAdyZWd1bGFyCQAAZAAAAAIIBQAAAAJiMgAAAAdyZWd1bGFyAAAAAAAAAAANBwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAABBQAAAANuaWwJAAACAAAAAQIAAAAUQmFsYW5jZSBjaGVjayBmYWlsZWQJAAACAAAAAQIAAAAJQmFkIHN0YXRlCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQkAAAIAAAABAgAAAAlJbXBvc2libGUAAAAA0WFyhQ==" +// secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQIAAAAEYmFjawUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACBQAAAAR1bml0AAAAAAAAAAADBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIFAAAAAXIJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADYmFyAAAAAAAAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQAAAAAAAAAAAwUAAAAEdW5pdAUAAAADbmlsAAAAAAAAAAARCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAACzZnMp" +// +// id = bytes.Repeat([]byte{0}, 32) +// +// expectedDataEntryWrites := []*proto.DataEntryScriptAction{ +// {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, +// {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, +// } +// +// expectedTransferWrites := []*proto.TransferScriptAction{ +// {Sender: &addrPK, Recipient: recipientCallable, Amount: 17, Asset: proto.OptionalAsset{}}, +// {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, +// {Sender: &addrPK, Recipient: recipientCallable, Amount: 2, Asset: proto.OptionalAsset{}}, +// {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, +// } +// +// smartState := smartStateDappFromDapp +// +// thisAddress = addr +// env := envDappFromDapp +// +// NewWrappedSt := initWrappedState(smartState(), env) +// wrappedSt = *NewWrappedSt +// +// err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) +// require.NoError(t, err) +// err = AddExternalPayments(tx.Payments, tx.SenderPK) +// require.NoError(t, err) +// +// src, err := base64.StdEncoding.DecodeString(firstScript) +// require.NoError(t, err) +// +// tree, err := Parse(src) +// require.NoError(t, err) +// assert.NotNil(t, tree) +// +// res, err := CallFunction(env, tree, "foo", proto.Arguments{}) +// +// require.NoError(t, err) +// r, ok := res.(DAppResult) +// require.True(t, ok) +// require.True(t, r.res) +// +// sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) +// require.NoError(t, err) +// +// expectedActionsResult := &proto.ScriptResult{ +// DataEntries: expectedDataEntryWrites, +// Transfers: expectedTransferWrites, +// Issues: make([]*proto.IssueScriptAction, 0), +// Reissues: make([]*proto.ReissueScriptAction, 0), +// Burns: make([]*proto.BurnScriptAction, 0), +// Sponsorships: make([]*proto.SponsorshipScriptAction, 0), +// Leases: make([]*proto.LeaseScriptAction, 0), +// LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), +// } +// assert.Equal(t, expectedActionsResult, sr) +// +// expectedDiffResult := initWrappedState(smartState(), env).diff +// +// balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9987, effectiveHistory: []int64{10000, 9987}} +// balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} +// balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 13, effectiveHistory: []int64{0, 13}} +// intEntry := proto.IntegerDataEntry{Key: "bar", Value: 1} +// expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry +// expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain +// expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender +// expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallable +// +// assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) +// assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) +// +// tearDownDappFromDapp() +// +//} + +func TestInvokeDAppFromDAppScript6(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let r = Invoke(this, "foo", [], []) + if r == r + then + [ + ] + else + throw("Imposible") + } + + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAABcgkAA/wAAAAEBQAAAAR0aGlzAgAAAANmb28FAAAAA25pbAUAAAADbmlsAwkAAAAAAAACBQAAAAFyBQAAAAFyBQAAAANuaWwJAAACAAAAAQIAAAAJSW1wb3NpYmxlAAAAAAWzLtA=" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: make([]*proto.DataEntryScriptAction, 0), + Transfers: make([]*proto.TransferScriptAction, 0), + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + + tearDownDappFromDapp() +} + +func BenchmarkInvokeDAppFromDAppScript6(b *testing.B) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let r = Invoke(this, "foo", [], []) + if r == r + then + [ + ] + else + throw("Imposible") + } + + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + recipient := proto.NewRecipientFromAddress(addr) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAABcgkAA/wAAAAEBQAAAAR0aGlzAgAAAANmb28FAAAAA25pbAUAAAADbmlsAwkAAAAAAAACBQAAAAFyBQAAAAFyBQAAAANuaWwJAAACAAAAAQIAAAAJSW1wb3NpYmxlAAAAAAWzLtA=" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + src, err := base64.StdEncoding.DecodeString(firstScript) + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + + tree, err := Parse(src) + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := CallFunction(env, tree, "foo", proto.Arguments{}) + if err != nil { + b.Fatal("Expected no errors, got error ", err) + } + } + tearDownDappFromDapp() +} + +func TestReentrantInvokeDAppFromDAppScript6(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let r = reentrantInvoke(this, "foo", [], []) + if r == r + then + [ + ] + else + throw("Imposible") + } + + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAABcgkAA/0AAAAEBQAAAAR0aGlzAgAAAANmb28FAAAAA25pbAUAAAADbmlsAwkAAAAAAAACBQAAAAFyBQAAAAFyBQAAAANuaWwJAAACAAAAAQIAAAAJSW1wb3NpYmxlAAAAALQe43c=\n" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: make([]*proto.DataEntryScriptAction, 0), + Transfers: make([]*proto.TransferScriptAction, 0), + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppPayments(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let exchangeRate = 5 + + @Callable(i) + func test() = if ((i.payments[0].assetId != unit)) + then throw("unexpected asset") + else { + let res = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "testActions",[(i.payments[0].amount * exchangeRate)], nil) + if res == 17 + then + [ + ScriptTransfer(i.caller, (i.payments[0].amount * exchangeRate), unit) + ] + else + throw("Bad returned value") + } */ + + /* script 2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func testActions(a: Int) = { + ([ + IntegerEntry("int", 1) + ], 17) + } */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + senderRecipient := proto.NewRecipientFromAddress(senderAddress) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAMZXhjaGFuZ2VSYXRlAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAR0ZXN0AAAAAAMJAQAAAAIhPQAAAAIICQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAAAAAAB2Fzc2V0SWQFAAAABHVuaXQJAAACAAAAAQIAAAAQdW5leHBlY3RlZCBhc3NldAQAAAADcmVzCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAC3Rlc3RBY3Rpb25zCQAETAAAAAIJAABoAAAAAggJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAAAAAGYW1vdW50BQAAAAxleGNoYW5nZVJhdGUFAAAAA25pbAUAAAADbmlsAwkAAAAAAAACBQAAAANyZXMAAAAAAAAAABEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyCQAAaAAAAAIICQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAAAAAABmFtb3VudAUAAAAMZXhjaGFuZ2VSYXRlBQAAAAR1bml0BQAAAANuaWwJAAACAAAAAQIAAAASQmFkIHJldHVybmVkIHZhbHVlAAAAANOWG8w=" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgEBAAAAAAAAAAEAAAABaQEAAAALdGVzdEFjdGlvbnMAAAABAAAAAWEJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADaW50AAAAAAAAAAABBQAAAANuaWwAAAAAAAAAABEAAAAAPWJMug==" + + id = bytes.Repeat([]byte{0}, 32) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "int", Value: 1}, Sender: &addressCallablePK}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Recipient: senderRecipient, Amount: 50000, Asset: proto.OptionalAsset{}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + intEntry := proto.IntegerDataEntry{Key: "int", Value: 1} + expectedDiffResult.dataEntries.diffInteger["int"+addressCallable.String()] = intEntry + + balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 10000} + balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} + expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppOriginalCallerAndAlias(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let b1 = wavesBalance(this) + let ob1 = wavesBalance(Address(base58'$otherAcc')) + if b1 == b1 && ob1 == ob1 && i.caller == i.originalCaller && i.callerPublicKey == i.originalCallerPublicKey + then + let r = Invoke(Alias("alias"), "bar", [this.bytes, i.caller.bytes], [AttachedPayment(unit, 17)]) + if r == 17 + then + let data = getIntegerValue(Address(base58'3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV'), "bar") + let b2 = wavesBalance(this) + let ob2 = wavesBalance(Address(base58'3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV')) + let ab = assetBalance(this, getBinaryValue(Address(base58'3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV'), "asset")) + if data == 1 + then + if ob1.regular+14 == ob2.regular && b1.regular == b2.regular+14 && ab == 1 + then + let l = Lease(Address(base58'3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV'), 23) + [ + IntegerEntry("key", 1), + Lease(Address(base58'3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV'), 13), + l, + LeaseCancel(l.calculateLeaseId()) + ] + else + throw("Balance check failed") + else + throw("Bad state") + else + throw("Bad returned value") + else + throw("Imposible") + }*/ + + /* script 2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar(a: ByteVector, o: ByteVector) = { + if i.caller.bytes == a && addressFromPublicKey(i.callerPublicKey).bytes == a && i.originalCaller.bytes == o && addressFromPublicKey(i.originalCallerPublicKey).bytes == o + then + let n = Issue("barAsset", "bar asset", 1, 0, false, unit, 0) + ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit), BinaryEntry("asset", n.calculateAssetId()), n, ScriptTransfer(Address(a), 1, n.calculateAssetId())], 17) + else + throw("Bad caller") + } */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3MsCoDnBbgzjQ7BgGk9xcruM6JVZ5jF8YCV") // new + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + inv["originalCaller"] = rideAddress(senderAddress) + inv["originalCallerPublicKey"] = rideBytes(sender.Bytes()) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAACYjEJAAPvAAAAAQUAAAAEdGhpcwQAAAADb2IxCQAD7wAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVQkEaFHOY5/wEUlgg1k/cPu/P+Gr9BUxy4DAwMDCQAAAAAAAAIFAAAAAmIxBQAAAAJiMQkAAAAAAAACBQAAAANvYjEFAAAAA29iMQcJAAAAAAAAAggFAAAAAWkAAAAGY2FsbGVyCAUAAAABaQAAAA5vcmlnaW5hbENhbGxlcgcJAAAAAAAAAggFAAAAAWkAAAAPY2FsbGVyUHVibGljS2V5CAUAAAABaQAAABdvcmlnaW5hbENhbGxlclB1YmxpY0tleQcEAAAAAXIJAAP8AAAABAkBAAAABUFsaWFzAAAAAQIAAAAFYWxpYXMCAAAAA2JhcgkABEwAAAACCAUAAAAEdGhpcwAAAAVieXRlcwkABEwAAAACCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBQAAAANuaWwJAARMAAAAAgkBAAAAD0F0dGFjaGVkUGF5bWVudAAAAAIFAAAABHVuaXQAAAAAAAAAABEFAAAAA25pbAMJAAAAAAAAAgUAAAABcgAAAAAAAAAAEQQAAAAEZGF0YQkBAAAAEUBleHRyTmF0aXZlKDEwNTApAAAAAgkBAAAAB0FkZHJlc3MAAAABAQAAABoBVCQRoUc5jn/ARSWCDWT9w+78/4av0FTHLgIAAAADYmFyBAAAAAJiMgkAA+8AAAABBQAAAAR0aGlzBAAAAANvYjIJAAPvAAAAAQkBAAAAB0FkZHJlc3MAAAABAQAAABoBVCQRoUc5jn/ARSWCDWT9w+78/4av0FTHLgQAAAACYWIJAAPwAAAAAgUAAAAEdGhpcwkBAAAAEUBleHRyTmF0aXZlKDEwNTIpAAAAAgkBAAAAB0FkZHJlc3MAAAABAQAAABoBVCQRoUc5jn/ARSWCDWT9w+78/4av0FTHLgIAAAAFYXNzZXQDCQAAAAAAAAIFAAAABGRhdGEAAAAAAAAAAAEDAwMJAAAAAAAAAgkAAGQAAAACCAUAAAADb2IxAAAAB3JlZ3VsYXIAAAAAAAAAAA4IBQAAAANvYjIAAAAHcmVndWxhcgkAAAAAAAACCAUAAAACYjEAAAAHcmVndWxhcgkAAGQAAAACCAUAAAACYjIAAAAHcmVndWxhcgAAAAAAAAAADgcJAAAAAAAAAgUAAAACYWIAAAAAAAAAAAEHBAAAAAFsCQAERAAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVQkEaFHOY5/wEUlgg1k/cPu/P+Gr9BUxy4AAAAAAAAAABcJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2tleQAAAAAAAAAAAQkABEwAAAACCQAERAAAAAIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVQkEaFHOY5/wEUlgg1k/cPu/P+Gr9BUxy4AAAAAAAAAAA0JAARMAAAAAgUAAAABbAkABEwAAAACCQEAAAALTGVhc2VDYW5jZWwAAAABCQAEOQAAAAEFAAAAAWwFAAAAA25pbAkAAAIAAAABAgAAABRCYWxhbmNlIGNoZWNrIGZhaWxlZAkAAAIAAAABAgAAAAlCYWQgc3RhdGUJAAACAAAAAQIAAAASQmFkIHJldHVybmVkIHZhbHVlCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAAA/J7gE" + secondScript = "AAIFAAAAAAAAAAgIAhIECgICAgAAAAAAAAABAAAAAWkBAAAAA2JhcgAAAAIAAAABYQAAAAFvAwMDAwkAAAAAAAACCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBQAAAAFhCQAAAAAAAAIICQEAAAAUYWRkcmVzc0Zyb21QdWJsaWNLZXkAAAABCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkAAAAFYnl0ZXMFAAAAAWEHCQAAAAAAAAIICAUAAAABaQAAAA5vcmlnaW5hbENhbGxlcgAAAAVieXRlcwUAAAABbwcJAAAAAAAAAggJAQAAABRhZGRyZXNzRnJvbVB1YmxpY0tleQAAAAEIBQAAAAFpAAAAF29yaWdpbmFsQ2FsbGVyUHVibGljS2V5AAAABWJ5dGVzBQAAAAFvBwQAAAABbgkABEMAAAAHAgAAAAhiYXJBc3NldAIAAAAJYmFyIGFzc2V0AAAAAAAAAAABAAAAAAAAAAAABwUAAAAEdW5pdAAAAAAAAAAAAAkABRQAAAACCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACAgAAAANiYXIAAAAAAAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwkBAAAAB0FkZHJlc3MAAAABBQAAAAFhAAAAAAAAAAADBQAAAAR1bml0CQAETAAAAAIJAQAAAAtCaW5hcnlFbnRyeQAAAAICAAAABWFzc2V0CQAEOAAAAAEFAAAAAW4JAARMAAAAAgUAAAABbgkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAAHQWRkcmVzcwAAAAEFAAAAAWEAAAAAAAAAAAEJAAQ4AAAAAQUAAAABbgUAAAADbmlsAAAAAAAAAAARCQAAAgAAAAECAAAACkJhZCBjYWxsZXIAAAAA1Tlvgg==" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + assetIDIssue = sr.Issues[0].ID + firstLeaseID := sr.Leases[0].ID + secondLeaseID := sr.Leases[1].ID + + expectedIssuesWrites := []*proto.IssueScriptAction{ + {Sender: &addressCallablePK, ID: assetIDIssue, Name: "barAsset", Description: "bar asset", Quantity: 1, Decimals: 0, Reissuable: false, Script: nil, Nonce: 0}, + } + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.BinaryDataEntry{Key: "asset", Value: assetIDIssue.Bytes()}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + expectedTransferWrites := []*proto.TransferScriptAction{ + {Recipient: recipientCallable, Amount: 17, Asset: proto.NewOptionalAssetWaves(), Sender: &addrPK}, + {Recipient: recipient, Amount: 3, Asset: proto.NewOptionalAssetWaves(), Sender: &addressCallablePK}, + {Recipient: recipient, Amount: 1, Asset: *proto.NewOptionalAssetFromDigest(assetIDIssue), Sender: &addressCallablePK}, + } + + expectedLeasesWrites := []*proto.LeaseScriptAction{ + {Recipient: recipientCallable, Amount: 13, ID: firstLeaseID}, + {Recipient: recipientCallable, Amount: 23, ID: secondLeaseID}, + } + + expectedLeasesCancelWrites := []*proto.LeaseCancelScriptAction{ + {LeaseID: secondLeaseID}, + } + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: expectedIssuesWrites, + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: expectedLeasesWrites, + LeaseCancels: expectedLeasesCancelWrites, + } + + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + intEntry := proto.IntegerDataEntry{Key: "bar", Value: 1} + expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry + + binaryEntry := proto.BinaryDataEntry{Key: "asset", Value: assetIDIssue.Bytes()} + expectedDiffResult.dataEntries.diffBinary["asset"+addressCallable.String()] = binaryEntry + + newAsset := diffNewAssetInfo{dAppIssuer: addressCallable, name: "barAsset", description: "bar asset", quantity: 1, decimals: 0, reissuable: false, script: nil, nonce: 0} + expectedDiffResult.newAssetsInfo[assetIDIssue.String()] = newAsset + + balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + + balanceMainWaves := diffBalance{asset: proto.OptionalAsset{}, regular: 9986, effectiveHistory: []int64{10000, 9986}} + expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMainWaves + + balanceCallableWaves := diffBalance{asset: proto.OptionalAsset{}, regular: 14, effectiveHistory: []int64{0, 14}} + expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallableWaves + + balanceCallableBarAsset := diffBalance{asset: *proto.NewOptionalAssetFromDigest(assetIDIssue), regular: 0} + expectedDiffResult.balances[addressCallable.String()+proto.NewOptionalAssetFromDigest(assetIDIssue).String()] = balanceCallableBarAsset + + balanceMainBarAsset := diffBalance{asset: *proto.NewOptionalAssetFromDigest(assetIDIssue), regular: 1} + expectedDiffResult.balances[addr.String()+proto.NewOptionalAssetFromDigest(assetIDIssue).String()] = balanceMainBarAsset + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + assert.Equal(t, expectedDiffResult.newAssetsInfo, wrappedSt.diff.newAssetsInfo) + + tearDownDappFromDapp() +} + +func TestInvokeDAppFromDAppNilResult(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let exchangeRate = 5 + + @Callable(i) + func test() = if ((i.payments[0].assetId != unit)) + then throw("unexpected asset") + else { + let res = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "testActions",[(i.payments[0].amount * exchangeRate)], [AttachedPayment(unit, 1)]) + if res == 17 + then + nil + else + throw("Bad returned value") + } + */ + + /* script 2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func testActions(a: Int) = { + ([ + IntegerEntry("int", 1) + ], 17) + } + */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAMZXhjaGFuZ2VSYXRlAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAR0ZXN0AAAAAAMJAQAAAAIhPQAAAAIICQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAAAAAAB2Fzc2V0SWQFAAAABHVuaXQJAAACAAAAAQIAAAAQdW5leHBlY3RlZCBhc3NldAQAAAADcmVzCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAC3Rlc3RBY3Rpb25zCQAETAAAAAIJAABoAAAAAggJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAAAAAGYW1vdW50BQAAAAxleGNoYW5nZVJhdGUFAAAAA25pbAkABEwAAAACCQEAAAAPQXR0YWNoZWRQYXltZW50AAAAAgUAAAAEdW5pdAAAAAAAAAAAAQUAAAADbmlsAwkAAAAAAAACBQAAAANyZXMAAAAAAAAAABEFAAAAA25pbAkAAAIAAAABAgAAABJCYWQgcmV0dXJuZWQgdmFsdWUAAAAAbfvo1Q==" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgEBAAAAAAAAAAEAAAABaQEAAAALdGVzdEFjdGlvbnMAAAABAAAAAWEJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADaW50AAAAAAAAAAABBQAAAANuaWwAAAAAAAAAABEAAAAAPWJMug==" + + id = bytes.Repeat([]byte{0}, 32) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "int", Value: 1}, Sender: &addressCallablePK}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Recipient: recipientCallable, Sender: &addrPK, Amount: 1, Asset: proto.OptionalAsset{}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9999} + balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} + balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 1} + expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallable + intEntry := proto.IntegerDataEntry{Key: "int", Value: 1} + expectedDiffResult.dataEntries.diffInteger["int"+addressCallable.String()] = intEntry + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + + tearDownDappFromDapp() + +} + +func TestInvokeDAppFromDAppSmartAssetValidation(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + let assetId = base58'13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ' + + @Callable(i) + func test() = { + let res = Invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "call",nil, nil) + if res == 17 + then + nil + else + throw("Bad returned value") + } + */ + + /* script 2 + + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let assetId = base58'13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ' + + @Callable(i) + func call() = { + ([ + Reissue(assetId, 100, false), + Burn(assetId, 50), + ScriptTransfer(i.caller, 1, assetId) + ], 17) + } + */ + /* smart asset script + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ASSET #-} + + let dAppAddress = addressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + match tx { + case tx: BurnTransaction => + (tx.sender == dAppAddress) + case tx: ReissueTransaction => + (tx.sender == dAppAddress) + case tx: SetAssetScriptTransaction => + (tx.sender == dAppAddress) + case tx: MassTransferTransaction => + (tx.sender == dAppAddress) + case tx: TransferTransaction => + (tx.sender == dAppAddress) + case _ => + false + } + */ + + assetCat, err := proto.NewOptionalAssetFromString("13YvHUb3bg7sXgExc6kFcCUKm6WYpJX9rLpHVhiyJNGJ") + require.NoError(t, err) + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(5, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAHYXNzZXRJZAEAAAAgAKdAj/iZUd+zAOo6DTO6IvheatMyaLi7as+C+lV4EDMAAAABAAAAAWkBAAAABHRlc3QAAAAABAAAAANyZXMJAAP8AAAABAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywIAAAAEY2FsbAUAAAADbmlsBQAAAANuaWwDCQAAAAAAAAIFAAAAA3JlcwAAAAAAAAAAEQUAAAADbmlsCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQAAAAAnQdRv" + secondScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAHYXNzZXRJZAEAAAAgAKdAj/iZUd+zAOo6DTO6IvheatMyaLi7as+C+lV4EDMAAAABAAAAAWkBAAAABGNhbGwAAAAACQAFFAAAAAIJAARMAAAAAgkBAAAAB1JlaXNzdWUAAAADBQAAAAdhc3NldElkAAAAAAAAAABkBwkABEwAAAACCQEAAAAEQnVybgAAAAIFAAAAB2Fzc2V0SWQAAAAAAAAAADIJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyAAAAAAAAAAABBQAAAAdhc3NldElkBQAAAANuaWwAAAAAAAAAABEAAAAA4X8UHg==" + + id = bytes.Repeat([]byte{0}, 32) + + expectedReissueWrites := []*proto.ReissueScriptAction{ + {Sender: &addressCallablePK, Quantity: 100, Reissuable: false, AssetID: assetCat.ID}, + } + expectedBurnWrites := []*proto.BurnScriptAction{ + {Sender: &addressCallablePK, Quantity: 50, AssetID: assetCat.ID}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Sender: &addressCallablePK, Recipient: recipient, Amount: 1, Asset: *assetCat}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(addressCallable, 10000, *assetCat) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: make([]*proto.DataEntryScriptAction, 0), + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: expectedReissueWrites, + Burns: expectedBurnWrites, + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + balance := diffBalance{regular: 1, leaseIn: 0, asset: *assetCat} + expectedDiffResult.balances[addr.String()+assetCat.String()] = balance + + balanceCallable := diffBalance{regular: 9999, leaseOut: 0, asset: *assetCat} + expectedDiffResult.balances[addressCallable.String()+assetCat.String()] = balanceCallable + + oldAsset := diffOldAssetInfo{diffQuantity: 50} + expectedDiffResult.oldAssetsInfo[assetIDIssue.String()] = oldAsset + + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + assert.Equal(t, expectedDiffResult.sponsorships, wrappedSt.diff.sponsorships) + assert.Equal(t, expectedDiffResult.leases, wrappedSt.diff.leases) + + tearDownDappFromDapp() +} + +func TestMixedReentrantInvokeAndInvoke(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func back() = { + [IntegerEntry("key", 0), ScriptTransfer(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), 2, unit)] + } + + @Callable(i) + func foo() = { + let r = reentrantInvoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "bar", [this.bytes], [AttachedPayment(unit, 17)]) + if r == 17 + then + [ + IntegerEntry("key", 1) + ] + else + throw("Imposible") + } + */ + + /* + script2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func bar(a: ByteVector) = { + let r = Invoke(Address(a), "back", [], []) + if r == r + then + ([IntegerEntry("bar", 1), ScriptTransfer(Address(a), 3, unit)], 17) + else + throw("Imposible") + } + + + */ + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + recipientCallable := proto.NewRecipientFromAddress(addressCallable) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAYIAhIAEgAAAAAAAAAAAgAAAAFpAQAAAARiYWNrAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAAAACQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssAAAAAAAAAAAIFAAAABHVuaXQFAAAAA25pbAAAAAFpAQAAAANmb28AAAAABAAAAAFyCQAD/QAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAA2JhcgkABEwAAAACCAUAAAAEdGhpcwAAAAVieXRlcwUAAAADbmlsCQAETAAAAAIJAQAAAA9BdHRhY2hlZFBheW1lbnQAAAACBQAAAAR1bml0AAAAAAAAAAARBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIAAAAAAAAAABEJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2tleQAAAAAAAAAAAQUAAAADbmlsCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAAB70C6c" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgECAAAAAAAAAAEAAAABaQEAAAADYmFyAAAAAQAAAAFhBAAAAAFyCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQIAAAAEYmFjawUAAAADbmlsBQAAAANuaWwDCQAAAAAAAAIFAAAAAXIFAAAAAXIJAAUUAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgIAAAADYmFyAAAAAAAAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQUAAAABYQAAAAAAAAAAAwUAAAAEdW5pdAUAAAADbmlsAAAAAAAAAAARCQAAAgAAAAECAAAACUltcG9zaWJsZQAAAACf+Ofn" + + id = bytes.Repeat([]byte{0}, 32) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 0}, Sender: &addrPK}, + {Entry: &proto.IntegerDataEntry{Key: "bar", Value: 1}, Sender: &addressCallablePK}, + {Entry: &proto.IntegerDataEntry{Key: "key", Value: 1}}, + } + + expectedTransferWrites := []*proto.TransferScriptAction{ + {Sender: &addrPK, Recipient: recipientCallable, Amount: 17, Asset: proto.OptionalAsset{}}, + {Sender: &addrPK, Recipient: recipientCallable, Amount: 2, Asset: proto.OptionalAsset{}}, + {Sender: &addressCallablePK, Recipient: recipient, Amount: 3, Asset: proto.OptionalAsset{}}, + } + + smartState := smartStateDappFromDapp + + thisAddress = addr + + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) + + require.NoError(t, err) + r, ok := res.(DAppResult) + require.True(t, ok) + require.True(t, r.res) + + sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) + require.NoError(t, err) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: expectedTransferWrites, + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + assert.Equal(t, expectedActionsResult, sr) + + expectedDiffResult := initWrappedState(smartState(), env).diff + + balanceMain := diffBalance{asset: proto.OptionalAsset{}, regular: 9984} + balanceSender := diffBalance{asset: proto.OptionalAsset{}, regular: 0} + balanceCallable := diffBalance{asset: proto.OptionalAsset{}, regular: 16} + intEntry1 := proto.IntegerDataEntry{Key: "key", Value: 0} + intEntry2 := proto.IntegerDataEntry{Key: "bar", Value: 1} + expectedDiffResult.dataEntries.diffInteger["key"+addr.String()] = intEntry1 + expectedDiffResult.dataEntries.diffInteger["bar"+addressCallable.String()] = intEntry2 + expectedDiffResult.balances[addr.String()+proto.OptionalAsset{}.String()] = balanceMain + expectedDiffResult.balances[senderAddress.String()+proto.OptionalAsset{}.String()] = balanceSender + expectedDiffResult.balances[addressCallable.String()+proto.OptionalAsset{}.String()] = balanceCallable + + assert.Equal(t, expectedDiffResult.dataEntries, wrappedSt.diff.dataEntries) + assert.Equal(t, expectedDiffResult.balances, wrappedSt.diff.balances) + + tearDownDappFromDapp() +} + +func TestExpressionScriptFailInvoke(t *testing.T) { + + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let dapp = Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna') + + match tx { + case t: InvokeScriptTransaction => { + let result = match invoke(dapp, "foo", [5], [AttachedPayment(unit, 10)]) { + case i: Int => i + case _ => throw("Wrong result type") + } + if result == 5 then true else throw("Wrong result '" + result.toString() + "'") + } + case _ => throw("Wrong tx type") + } + */ + + /* script 2 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(inv) + func foo(amount: Int) = ([ + IntegerEntry("result", amount), + ScriptTransfer(inv.caller, amount, unit) + ], amount) + */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "BQQAAAAEZGFwcAkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0myKgvnUpvnQwgi/Cmpjg8vaC8j0MoKywQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAF0ludm9rZVNjcmlwdFRyYW5zYWN0aW9uBAAAAAF0BQAAAAckbWF0Y2gwBAAAAAZyZXN1bHQEAAAAByRtYXRjaDEJAAP8AAAABAUAAAAEZGFwcAIAAAADZm9vCQAETAAAAAIAAAAAAAAAAAUFAAAAA25pbAkABEwAAAACCQEAAAAPQXR0YWNoZWRQYXltZW50AAAAAgUAAAAEdW5pdAAAAAAAAAAACgUAAAADbmlsAwkAAAEAAAACBQAAAAckbWF0Y2gxAgAAAANJbnQEAAAAAWkFAAAAByRtYXRjaDEFAAAAAWkJAAACAAAAAQIAAAARV3JvbmcgcmVzdWx0IHR5cGUDCQAAAAAAAAIFAAAABnJlc3VsdAAAAAAAAAAABQYJAAACAAAAAQkAASwAAAACCQABLAAAAAICAAAADldyb25nIHJlc3VsdCAnCQABpAAAAAEFAAAABnJlc3VsdAIAAAABJwkAAAIAAAABAgAAAA1Xcm9uZyB0eCB0eXBlUP0hpw==" + secondScript = "AAIFAAAAAAAAAAcIAhIDCgEBAAAAAAAAAAEAAAADaW52AQAAAANmb28AAAABAAAABmFtb3VudAkABRQAAAACCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACAgAAAAZyZXN1bHQFAAAABmFtb3VudAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCAUAAAADaW52AAAABmNhbGxlcgUAAAAGYW1vdW50BQAAAAR1bml0BQAAAANuaWwFAAAABmFtb3VudAAAAAD070Yd" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + _, err = CallVerifier(env, tree) + require.Error(t, err) + tearDownDappFromDapp() +} + +func TestPaymentsDifferentScriptVersion4(t *testing.T) { + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let exchangeRate = 5 + + @Callable(i) + func test() = if ((i.payments[0].assetId != unit)) + then throw("unexpected asset") + else { + let res = invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "testActions",[(i.payments[0].amount * exchangeRate)], [AttachedPayment(unit, 1)]) + if res == res + then + nil + else + throw("Bad returned value") + } + */ + + /* script 2 + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func testActions(a: Int) = { + [ + IntegerEntry("int", 1) + ] + } + */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) + + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAMZXhjaGFuZ2VSYXRlAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAR0ZXN0AAAAAAMJAQAAAAIhPQAAAAIICQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAAAAAAB2Fzc2V0SWQFAAAABHVuaXQJAAACAAAAAQIAAAAQdW5leHBlY3RlZCBhc3NldAQAAAADcmVzCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAC3Rlc3RBY3Rpb25zCQAETAAAAAIJAABoAAAAAggJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAAAAAGYW1vdW50BQAAAAxleGNoYW5nZVJhdGUFAAAAA25pbAkABEwAAAACCQEAAAAPQXR0YWNoZWRQYXltZW50AAAAAgUAAAAEdW5pdAAAAAAAAAAAAQUAAAADbmlsAwkAAAAAAAACBQAAAANyZXMFAAAAA3JlcwUAAAADbmlsCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQAAAAAdCpXM" + secondScript = "AAIEAAAAAAAAAAcIAhIDCgEBAAAAAAAAAAEAAAABaQEAAAALdGVzdEFjdGlvbnMAAAABAAAAAWEJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAICAAAAA2ludAAAAAAAAAAAAQUAAAADbmlsAAAAAM41XKE=" + + id = bytes.Repeat([]byte{0}, 32) + + smartState := smartStateDappFromDapp + + thisAddress = addr + env := envDappFromDapp + + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.Error(t, err) + r, ok := res.(DAppResult) + require.False(t, ok) + require.False(t, r.res) + + tearDownDappFromDapp() + + tearDownDappFromDapp() + +} + +func TestPaymentsDifferentScriptVersion3(t *testing.T) { + /* script 1 + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let exchangeRate = 5 + + @Callable(i) + func test() = if ((i.payments[0].assetId != unit)) + then throw("unexpected asset") + else { + let res = invoke(Address(base58'3P8eZVKS7a4troGckytxaefLAi9w7P5aMna'), "testActions",[(i.payments[0].amount * exchangeRate)], [AttachedPayment(unit, 1)]) + if res == res + then + nil + else + throw("Bad returned value") + } + */ + + /* script 2 + {-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + @Callable(i) + func testActions(a: Int) = { + + WriteSet( + [DataEntry("int", 1)] + ) + + } + */ + + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") + require.NoError(t, err) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + require.NoError(t, err) + sender, err := crypto.NewPublicKeyFromBase58("APg7QwJSx6naBUPnGYM2vvsJxQcpYabcbzkNJoMUXLai") + require.NoError(t, err) + senderAddress, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, sender) + require.NoError(t, err) + addr, err = proto.NewAddressFromString("3PFpqr7wTCBu68sSqU7vVv9pttYRjQjGFbv") + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + addrPK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addr) + require.NoError(t, err) + + addressCallable, err = proto.NewAddressFromString("3P8eZVKS7a4troGckytxaefLAi9w7P5aMna") + require.NoError(t, err) + addressCallablePK, err = smartStateDappFromDapp().NewestScriptPKByAddr(addressCallable) + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx = &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: sender, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: proto.ScriptPayments{proto.ScriptPayment{ + Amount: 10000, + Asset: proto.OptionalAsset{}, + }}, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + + inv, _ = invocationToObject(4, proto.MainNetScheme, tx) - tree, err := Parse(src) - require.NoError(t, err) - assert.NotNil(t, tree) + firstScript = "AAIFAAAAAAAAAAQIAhIAAAAAAQAAAAAMZXhjaGFuZ2VSYXRlAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAR0ZXN0AAAAAAMJAQAAAAIhPQAAAAIICQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAAAAAAB2Fzc2V0SWQFAAAABHVuaXQJAAACAAAAAQIAAAAQdW5leHBlY3RlZCBhc3NldAQAAAADcmVzCQAD/AAAAAQJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVdJsioL51Kb50MIIvwpqY4PL2gvI9DKCssCAAAAC3Rlc3RBY3Rpb25zCQAETAAAAAIJAABoAAAAAggJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAAAAAGYW1vdW50BQAAAAxleGNoYW5nZVJhdGUFAAAAA25pbAkABEwAAAACCQEAAAAPQXR0YWNoZWRQYXltZW50AAAAAgUAAAAEdW5pdAAAAAAAAAAAAQUAAAADbmlsAwkAAAAAAAACBQAAAANyZXMFAAAAA3JlcwUAAAADbmlsCQAAAgAAAAECAAAAEkJhZCByZXR1cm5lZCB2YWx1ZQAAAAAdCpXM" + secondScript = "AAIDAAAAAAAAAAcIARIDCgEBAAAAAAAAAAEAAAABaQEAAAALdGVzdEFjdGlvbnMAAAABAAAAAWEJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAAA2ludAAAAAAAAAAAAQUAAAADbmlsAAAAAJvCz7w=" - res, err := CallVerifier(env, tree) - require.NoError(t, err) - r, ok := res.(ScriptResult) - require.True(t, ok) - assert.False(t, r.Result()) -} + id = bytes.Repeat([]byte{0}, 32) -func TestDappVerifySuccessful(t *testing.T) { - /*{-# STDLIB_VERSION 3 #-} - {-# CONTENT_TYPE DAPP #-} - {-# SCRIPT_TYPE ACCOUNT #-} + smartState := smartStateDappFromDapp - let x = 100500 + thisAddress = addr + env := envDappFromDapp - func getPreviousAnswer() = { - x - } + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt - @Verifier(tx) - func verify() = { - getPreviousAnswer() == 100500 - } - */ - env, _ := testInvokeEnv(true) - code := "AAIDAAAAAAAAAAAAAAACAAAAAAF4AAAAAAAAAYiUAQAAABFnZXRQcmV2aW91c0Fuc3dlcgAAAAAFAAAAAXgAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACCQEAAAARZ2V0UHJldmlvdXNBbnN3ZXIAAAAAAAAAAAAAAYiUa4pU5Q==" - src, err := base64.StdEncoding.DecodeString(code) + err = AddWavesToSender(senderAddress, 10000, proto.OptionalAsset{}) + require.NoError(t, err) + err = AddExternalPayments(tx.Payments, tx.SenderPK) + require.NoError(t, err) + + src, err := base64.StdEncoding.DecodeString(firstScript) require.NoError(t, err) tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) - require.NoError(t, err) - r, ok := res.(ScriptResult) - require.True(t, ok) - assert.True(t, r.Result()) + res, err := CallFunction(env, tree, "test", proto.Arguments{}) + + require.Error(t, err) + r, ok := res.(DAppResult) + require.False(t, ok) + require.False(t, r.res) + + tearDownDappFromDapp() + } -func TestTransferSet(t *testing.T) { +func TestHashScriptFunc(t *testing.T) { /* - {-# STDLIB_VERSION 3 #-} - {-# CONTENT_TYPE DAPP #-} - {-# SCRIPT_TYPE ACCOUNT #-} - - @Callable(i) - func tellme(question: String) = { - TransferSet([ScriptTransfer(i.caller, 100, unit)]) - } + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + + @Callable(i) + func foo() = { + let h = hashScriptAtAddress(this) + if hashScriptAtAddress(i.caller) == unit + then + [ BinaryEntry("hash", h.value()) ] + else + throw("Unexpected script was found.") + } */ - env, tx := testInvokeEnv(false) - addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, tx.SenderPK) + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") require.NoError(t, err) - code := "AAIDAAAAAAAAAAAAAAAAAAAAAQAAAAFpAQAAAAZ0ZWxsbWUAAAABAAAACHF1ZXN0aW9uCQEAAAALVHJhbnNmZXJTZXQAAAABCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMIBQAAAAFpAAAABmNhbGxlcgAAAAAAAAAAZAUAAAAEdW5pdAUAAAADbmlsAAAAAH5a2L0=" - src, err := base64.StdEncoding.DecodeString(code) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + senderPK, err := crypto.NewPublicKeyFromBase58("2v89gsAztdyVq8aEVdNrxUZKtf1HfTAn5umC41idvykp") + require.NoError(t, err) + senderAddr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, senderPK) + require.NoError(t, err) + addrPK, err := crypto.NewPublicKeyFromBase58("2zb2orX2g58YZgXAvdn5ojTuPP8vAU2rsqYQ5L6KCXqz") + require.NoError(t, err) + addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, addrPK) + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx := &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: senderPK, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + inv, _ := invocationToObject(5, proto.MainNetScheme, tx) + + var script string + var wrappedSt WrappedState + + smartState := func() types.SmartState { + return &MockSmartState{ + GetByteTreeFunc: func(recipient proto.Recipient) (proto.Script, error) { + var resScript proto.Script + var err error + if recipient.Address.String() == addr.String() { + resScript, err = base64.StdEncoding.DecodeString(script) + } + if recipient.Address.String() == senderAddr.String() { + return proto.Script{}, nil + } + if err != nil { + return proto.Script{}, err + } + + return resScript, nil + }, + } + } + env := &MockRideEnvironment{ + schemeFunc: func() byte { + return proto.MainNetScheme + }, + heightFunc: func() rideInt { + return 368430 + }, + thisFunc: func() rideType { + return rideAddress(addr) + }, + invocationFunc: func() rideObject { + return inv + }, + timestampFunc: func() uint64 { + return 1564703444249 + }, + transactionFunc: func() rideObject { + obj, _ := transactionToObject(proto.MainNetScheme, tx) + return obj + }, + stateFunc: func() types.SmartState { + return &wrappedSt + }, + } + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + script = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAABaAkAA/EAAAABBQAAAAR0aGlzAwkAAAAAAAACCQAD8QAAAAEIBQAAAAFpAAAABmNhbGxlcgUAAAAEdW5pdAkABEwAAAACCQEAAAALQmluYXJ5RW50cnkAAAACAgAAAARoYXNoCQEAAAAFdmFsdWUAAAABBQAAAAFoBQAAAANuaWwJAAACAAAAAQIAAAAcVW5leHBlY3RlZCBzY3JpcHQgd2FzIGZvdW5kLgAAAABGhMi8" + src, err := base64.StdEncoding.DecodeString(script) require.NoError(t, err) tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) require.True(t, r.res) - scriptTransfer := proto.TransferScriptAction{ - Recipient: proto.NewRecipientFromAddress(addr), - Amount: 100, - Asset: proto.OptionalAsset{Present: false}, - } - require.NoError(t, err) sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) require.NoError(t, err) - require.EqualValues(t, - &proto.ScriptResult{ - DataEntries: make([]*proto.DataEntryScriptAction, 0), - Transfers: []*proto.TransferScriptAction{&scriptTransfer}, - Issues: make([]*proto.IssueScriptAction, 0), - Reissues: make([]*proto.ReissueScriptAction, 0), - Burns: make([]*proto.BurnScriptAction, 0), - Sponsorships: make([]*proto.SponsorshipScriptAction, 0), - }, - sr, - ) + + decodedScript, err := base64.StdEncoding.DecodeString(script) + require.NoError(t, err) + hash, err := crypto.FastHash(decodedScript) + require.NoError(t, err) + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.BinaryDataEntry{Key: "hash", Value: hash.Bytes()}}, + } + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: make([]*proto.TransferScriptAction, 0), + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) } -func TestScriptResult(t *testing.T) { +func TestDataStorageUntouchedFunc(t *testing.T) { /* - {-# STDLIB_VERSION 3 #-} - {-# CONTENT_TYPE DAPP #-} - {-# SCRIPT_TYPE ACCOUNT #-} - - @Callable(i) - func tellme(question: String) = { - ScriptResult( - WriteSet([DataEntry("key", 100)]), - TransferSet([ScriptTransfer(i.caller, 100500, unit)]) - ) - } + {-# STDLIB_VERSION 5 #-} + {-# CONTENT_TYPE DAPP #-} + {-#SCRIPT_TYPE ACCOUNT#-} + @Callable(i) + func foo() = { + let check = isDataStorageUntouched(this) + [ BooleanEntry("virgin", check) ] + } */ - env, tx := testInvokeEnv(false) - addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, tx.SenderPK) + txID, err := crypto.NewDigestFromBase58("46R51i3ATxvYbrLJVWpAG3hZuznXtgEobRW6XSZ9MP6f") require.NoError(t, err) - code := "AAIDAAAAAAAAAAAAAAAAAAAAAQAAAAFpAQAAAAZ0ZWxsbWUAAAABAAAACHF1ZXN0aW9uCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAADa2V5AAAAAAAAAABkBQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyAAAAAAAAAYiUBQAAAAR1bml0BQAAAANuaWwAAAAARKRntw==" - src, err := base64.StdEncoding.DecodeString(code) + proof, err := crypto.NewSignatureFromBase58("5MriXpPgobRfNHqYx3vSjrZkDdzDrRF6krgvJp1FRvo2qTyk1KB913Nk1H2hWyKPDzL6pV1y8AWREHdQMGStCBuF") + require.NoError(t, err) + proofs := proto.NewProofs() + proofs.Proofs = []proto.B58Bytes{proof[:]} + senderPK, err := crypto.NewPublicKeyFromBase58("2v89gsAztdyVq8aEVdNrxUZKtf1HfTAn5umC41idvykp") + require.NoError(t, err) + + addrPK, err := crypto.NewPublicKeyFromBase58("2zb2orX2g58YZgXAvdn5ojTuPP8vAU2rsqYQ5L6KCXqz") + require.NoError(t, err) + addr, err := proto.NewAddressFromPublicKey(proto.MainNetScheme, addrPK) + require.NoError(t, err) + recipient := proto.NewRecipientFromAddress(addr) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "B9spbWQ1rk7YqJUFjW8mLHw6cRcngyh7G9YgRuyFtLv6"}) + call := proto.FunctionCall{ + Default: false, + Name: "cancel", + Arguments: arguments, + } + tx := &proto.InvokeScriptWithProofs{ + Type: proto.InvokeScriptTransaction, + Version: 1, + ID: &txID, + Proofs: proofs, + ChainID: proto.MainNetScheme, + SenderPK: senderPK, + ScriptRecipient: recipient, + FunctionCall: call, + Payments: nil, + FeeAsset: proto.OptionalAsset{}, + Fee: 900000, + Timestamp: 1564703444249, + } + //inv, _ := invocationToObject(5, proto.MainNetScheme, tx) + + var script string + var wrappedSt WrappedState + + smartState := func() types.SmartState { + return &MockSmartState{ + IsStateUntouchedFunc: func(recipient proto.Recipient) (bool, error) { + if recipient.Address.String() == addr.String() { + return false, nil + } else { + return false, errors.New("unexpected address") + } + }, + } + } + env := &MockRideEnvironment{ + schemeFunc: func() byte { + return proto.MainNetScheme + }, + heightFunc: func() rideInt { + return 368430 + }, + thisFunc: func() rideType { + return rideAddress(addr) + }, + timestampFunc: func() uint64 { + return 1564703444249 + }, + transactionFunc: func() rideObject { + obj, _ := transactionToObject(proto.MainNetScheme, tx) + return obj + }, + stateFunc: func() types.SmartState { + return &wrappedSt + }, + } + NewWrappedSt := initWrappedState(smartState(), env) + wrappedSt = *NewWrappedSt + + script = "AAIFAAAAAAAAAAQIAhIAAAAAAAAAAAEAAAABaQEAAAADZm9vAAAAAAQAAAAFY2hlY2sJAAQeAAAAAQUAAAAEdGhpcwkABEwAAAACCQEAAAAMQm9vbGVhbkVudHJ5AAAAAgIAAAAGdmlyZ2luBQAAAAVjaGVjawUAAAADbmlsAAAAAA8AdTc=" + src, err := base64.StdEncoding.DecodeString(script) require.NoError(t, err) tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) + res, err := CallFunction(env, tree, "foo", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -768,22 +4220,23 @@ func TestScriptResult(t *testing.T) { sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{}) require.NoError(t, err) - scriptTransfer := proto.TransferScriptAction{ - Recipient: proto.NewRecipientFromAddress(addr), - Amount: 100500, - Asset: proto.OptionalAsset{Present: false}, + + expectedDataEntryWrites := []*proto.DataEntryScriptAction{ + {Entry: &proto.BooleanDataEntry{Key: "virgin", Value: false}}, } - require.Equal(t, - &proto.ScriptResult{ - DataEntries: []*proto.DataEntryScriptAction{{Entry: &proto.IntegerDataEntry{Key: "key", Value: 100}}}, - Transfers: []*proto.TransferScriptAction{&scriptTransfer}, - Issues: make([]*proto.IssueScriptAction, 0), - Reissues: make([]*proto.ReissueScriptAction, 0), - Burns: make([]*proto.BurnScriptAction, 0), - Sponsorships: make([]*proto.SponsorshipScriptAction, 0), - }, - sr, - ) + + expectedActionsResult := &proto.ScriptResult{ + DataEntries: expectedDataEntryWrites, + Transfers: make([]*proto.TransferScriptAction, 0), + Issues: make([]*proto.IssueScriptAction, 0), + Reissues: make([]*proto.ReissueScriptAction, 0), + Burns: make([]*proto.BurnScriptAction, 0), + Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + } + + assert.Equal(t, expectedActionsResult, sr) } func TestMatchOverwrite(t *testing.T) { @@ -823,7 +4276,7 @@ func TestMatchOverwrite(t *testing.T) { env := &MockRideEnvironment{ schemeFunc: func() byte { - return proto.TestNetScheme + return proto.MainNetScheme }, heightFunc: func() rideInt { return 368430 @@ -846,6 +4299,7 @@ func TestMatchOverwrite(t *testing.T) { } }, } + code := "AQQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgQAAAACZHQFAAAAByRtYXRjaDAEAAAAAWEJAQAAAAdleHRyYWN0AAAAAQkABBoAAAACCAUAAAACZHQAAAAGc2VuZGVyAgAAAAFhBAAAAAF4AwkAAAAAAAACBQAAAAFhAAAAAAAAAAAABAAAAAckbWF0Y2gxCQAEGgAAAAIIBQAAAAJkdAAAAAZzZW5kZXICAAAAAXgDCQAAAQAAAAIFAAAAByRtYXRjaDECAAAAA0ludAQAAAABaQUAAAAHJG1hdGNoMQUAAAABaQAAAAAAAAAAAAAAAAAAAAAAAAQAAAACeHgEAAAAByRtYXRjaDEJAAQQAAAAAggFAAAAAmR0AAAABGRhdGECAAAAAXgDCQAAAQAAAAIFAAAAByRtYXRjaDECAAAAA0ludAQAAAABaQUAAAAHJG1hdGNoMQUAAAABaQAAAAAAAAAAAAkAAAAAAAACCQAAZAAAAAIFAAAAAXgFAAAAAnh4AAAAAAAAAAADB2NbtyA=" src, err := base64.StdEncoding.DecodeString(code) require.NoError(t, err) @@ -1161,6 +4615,8 @@ func TestWhaleDApp(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -1299,6 +4755,8 @@ func TestExchangeDApp(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -1597,6 +5055,8 @@ func TestLigaDApp1(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) @@ -1783,6 +5243,8 @@ func TestLigaDApp1(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -1909,6 +5371,8 @@ func TestTestingDApp(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -1969,6 +5433,7 @@ func TestDropElementDApp(t *testing.T) { blockFunc: func() rideObject { return blockInfoToObject(blockInfo) }, + takeStringFunc: v5takeString, stateFunc: func() types.SmartState { return &MockSmartState{ AddingBlockHeightFunc: func() (uint64, error) { @@ -2022,6 +5487,8 @@ func TestDropElementDApp(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -2143,6 +5610,8 @@ func TestMathDApp(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -2269,6 +5738,8 @@ func TestDAppWithInvalidAddress(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -2392,6 +5863,8 @@ func Test8Ball(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -2564,15 +6037,18 @@ func TestAssetInfoV3V4(t *testing.T) { } func TestJSONParsing(t *testing.T) { + env := &MockRideEnvironment{ + takeStringFunc: v5takeString, + } + code := "AwoBAAAADmdldFZhbHVlU3RyaW5nAAAAAQAAAARqc29uCQABLwAAAAIJAAEwAAAAAgUAAAAEanNvbgAAAAAAAAAAAQkBAAAABXZhbHVlAAAAAQkABLMAAAACCQABMAAAAAIFAAAABGpzb24AAAAAAAAAAAECAAAAASIKAQAAAAhnZXRWYWx1ZQAAAAIAAAAEanNvbgAAAANrZXkEAAAACGtleUluZGV4CQEAAAAFdmFsdWUAAAABCQAEswAAAAIFAAAABGpzb24JAAEsAAAAAgkAASwAAAACAgAAAAEiBQAAAANrZXkCAAAAAiI6BAAAAARkYXRhCQABMAAAAAIFAAAABGpzb24JAABkAAAAAgkAAGQAAAACBQAAAAhrZXlJbmRleAkAATEAAAABBQAAAANrZXkAAAAAAAAAAAMJAQAAAA5nZXRWYWx1ZVN0cmluZwAAAAEFAAAABGRhdGEEAAAACWFkZHJlc3NlcwIAAAFgeyJ0aXRsZSI6Ikjhu6NwIMSR4buTbmcgbXVhIGLDoW4gxJHhuqV0IChyZWFsLWVzdGF0ZSBjb250cmFjdCkiLCJ0aW1lc3RhbXAiOjE1OTE2MDg5NDQzNTQsImhhc2giOiJkOGYwOWFjYmRlYTIwMTc5MTUyY2Q5N2RiNDNmNmJjZjhjYjYxMTE1YmE3YzNmZWU3NDk4MWU0ZjRiNTBlNGEwIiwiY3JlYXRvciI6IiIsImFkZHJlc3MxIjoiM015Yjg1REd2N3hqNFhaRlpBTDRHSHVHRG1aU0czQ0NVdlciLCJhZGRyZXNzMiI6IiIsImFkZHJlc3MzIjoiIiwiYWRkcmVzczQiOiIiLCJhZGRyZXNzNSI6IiIsImFkZHJlc3M2IjoiIiwiaXBmcyI6IlFtVEtCbUg5aW4yRU50NkFRcnZwUHpvYWFtMnozcWRFZUhRU1k5M3JkOEpqSFkifQkAAAAAAAACCQEAAAAIZ2V0VmFsdWUAAAACBQAAAAlhZGRyZXNzZXMCAAAACGFkZHJlc3MxAgAAACMzTXliODVER3Y3eGo0WFpGWkFMNEdIdUdEbVpTRzNDQ1V2V6k+k0o=" src, err := base64.StdEncoding.DecodeString(code) require.NoError(t, err) - tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(nil, tree) + res, err := CallVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -2746,6 +6222,8 @@ func TestBadType(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -2915,6 +6393,8 @@ func TestNoDeclaration(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -3107,6 +6587,8 @@ func TestZeroReissue(t *testing.T) { Reissues: expectedReissues, Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -3320,6 +6802,8 @@ func TestStageNet2(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), } assert.Equal(t, expectedResult, sr) } @@ -3363,6 +6847,7 @@ func TestRecipientAddressToString(t *testing.T) { Attachment: nil, }, } + env := &MockRideEnvironment{ schemeFunc: func() byte { return proto.TestNetScheme @@ -3512,6 +6997,9 @@ func TestInvalidAssetInTransferScriptAction(t *testing.T) { Reissues: make([]*proto.ReissueScriptAction, 0), Burns: make([]*proto.BurnScriptAction, 0), Sponsorships: make([]*proto.SponsorshipScriptAction, 0), + Leases: make([]*proto.LeaseScriptAction, 0), + LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0), + ErrorMsg: proto.ScriptErrorMessage{}, } assert.Equal(t, expectedResult, sr) } diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 618cb315c..c7d1d5c0a 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -22,12 +22,14 @@ type esFunction struct { } type evaluationScope struct { - env RideEnvironment + env Environment constants map[string]esConstant cs [][]esValue system map[string]rideFunction user []esFunction cl int + costs map[string]int + free map[string]struct{} } func (s *evaluationScope) declare(n Node) error { @@ -51,6 +53,12 @@ func (s *evaluationScope) pushValue(id string, v rideType) { s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, value: v}) } +func (s *evaluationScope) updateValue(frame, pos int, id string, v rideType) { + if ev := s.cs[frame][pos]; ev.id == id && ev.value == nil { + s.cs[frame][pos] = esValue{id: id, value: v} + } +} + func (s *evaluationScope) popValue() { s.cs[len(s.cs)-1] = s.cs[len(s.cs)-1][:len(s.cs[len(s.cs)-1])-1] } @@ -67,29 +75,29 @@ func (s *evaluationScope) constant(id string) (rideType, bool) { return nil, false } -func lookup(s []esValue, id string) (esValue, bool) { +func lookup(s []esValue, id string) (esValue, bool, int) { for i := len(s) - 1; i >= 0; i-- { if v := s[i]; v.id == id { - return v, true + return v, true, i } } - return esValue{}, false + return esValue{}, false, 0 } -func (s *evaluationScope) value(id string) (esValue, bool) { - if p := len(s.cs) - 1; p >= 0 { - v, ok := lookup(s.cs[p], id) +func (s *evaluationScope) value(id string) (esValue, bool, int, int) { + if i := len(s.cs) - 1; i >= 0 { + v, ok, p := lookup(s.cs[i], id) if ok { - return v, true + return v, true, i, p } } for i := s.cl - 1; i >= 0; i-- { - v, ok := lookup(s.cs[i], id) + v, ok, p := lookup(s.cs[i], id) if ok { - return v, true + return v, true, i, p } } - return esValue{}, false + return esValue{}, false, 0, 0 } func (s *evaluationScope) pushUserFunction(uf *FunctionDeclarationNode) { @@ -115,7 +123,7 @@ func (s *evaluationScope) userFunction(id string) (*FunctionDeclarationNode, int return nil, 0, errors.Errorf("user function '%s' is not found", id) } -func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { +func newEvaluationScope(v int, env Environment, enableInvocation bool) (evaluationScope, error) { constants, err := selectConstantNames(v) if err != nil { return evaluationScope{}, err @@ -136,7 +144,7 @@ func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { } cs[n] = esConstant{c: constantProvider(int(id))} } - functions, err := selectFunctionNames(v) + functions, err := selectFunctionNames(v, enableInvocation) if err != nil { return evaluationScope{}, err } @@ -156,11 +164,17 @@ func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { } fs[fn] = functionProvider(int(id)) } + costs, free, err := selectEvaluationCostsProvider(v) + if err != nil { + return evaluationScope{}, err + } return evaluationScope{ constants: cs, system: fs, cs: [][]esValue{make([]esValue, 0)}, env: env, + costs: costs, + free: free, }, nil } @@ -174,80 +188,101 @@ func selectConstantNames(v int) ([]string, error) { return ConstantsV3, nil case 4: return ConstantsV4, nil + case 5: + return ConstantsV5, nil default: return nil, errors.Errorf("unsupported library version %d", v) } } -func keys(m map[string]int) []string { +func keys(m map[string]int, enableInvocation bool) []string { keys := make([]string, 0, len(m)) for k := range m { - keys = append(keys, k) + switch k { + case "1020", "1021": // invoke and reentrantInvoke function are disabled for expression calls + if enableInvocation { + keys = append(keys, k) + } + default: + keys = append(keys, k) + } } return keys } -func selectFunctionNames(v int) ([]string, error) { +func selectFunctionNames(v int, enableInvocation bool) ([]string, error) { switch v { case 1, 2: - return keys(CatalogueV2), nil + return keys(CatalogueV2, false), nil case 3: - return keys(CatalogueV3), nil + return keys(CatalogueV3, false), nil case 4: - return keys(CatalogueV4), nil + return keys(CatalogueV4, false), nil + case 5: + return keys(CatalogueV5, enableInvocation), nil default: return nil, errors.Errorf("unsupported library version %d", v) } } type treeEvaluator struct { - dapp bool - //limit int - //cost int - f Node - s evaluationScope - env RideEnvironment + dapp bool + complexity int + f Node + s evaluationScope + env Environment } -func (e *treeEvaluator) evaluate() (RideResult, error) { +func (e *treeEvaluator) evaluate() (Result, error) { r, err := e.walk(e.f) if err != nil { return nil, err } + switch res := r.(type) { case rideThrow: if e.dapp { - return DAppResult{res: false, msg: string(res)}, nil + return DAppResult{res: false, msg: string(res), complexity: e.complexity}, nil } - return ScriptResult{res: false, msg: string(res)}, nil + return ScriptResult{res: false, msg: string(res), complexity: e.complexity}, nil case rideBoolean: - return ScriptResult{res: bool(res)}, nil + return ScriptResult{res: bool(res), complexity: e.complexity}, nil case rideObject: - actions, err := objectToActions(e.env, res) + a, err := objectToActions(e.env, res) if err != nil { return nil, errors.Wrap(err, "failed to convert evaluation result") } - return DAppResult{true, actions, ""}, nil + return DAppResult{res: true, actions: a, msg: "", complexity: e.complexity}, nil case rideList: - actions := make([]proto.ScriptAction, len(res)) - for i, item := range res { + var actions []proto.ScriptAction + for _, item := range res { a, err := convertToAction(e.env, item) if err != nil { return nil, errors.Wrap(err, "failed to convert evaluation result") } - actions[i] = a + actions = append(actions, a) + } + return DAppResult{res: true, actions: actions, complexity: e.complexity}, nil + case tuple2: + var actions []proto.ScriptAction + switch resAct := res.el1.(type) { + case rideList: + for _, item := range resAct { + a, err := convertToAction(e.env, item) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + actions = append(actions, a) + } + default: + return nil, errors.Errorf("unexpected result type '%T'", r) } - return DAppResult{res: true, actions: actions}, nil + return DAppResult{res: true, actions: actions, msg: "", param: res.el2, complexity: e.complexity}, nil default: return nil, errors.Errorf("unexpected result type '%T'", r) } } -// -//func (e *treeEvaluator) exceeded() bool { -// return e.limit > 0 && e.cost >= e.limit -//} - func isThrow(r rideType) bool { return r.instanceOf() == "Throw" } @@ -278,6 +313,7 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { if !ok { return nil, errors.Errorf("not a boolean") } + e.complexity++ if cr { return e.walk(n.TrueExpression) } else { @@ -299,7 +335,7 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { case *ReferenceNode: id := n.Name - v, ok := e.s.value(id) + v, ok, f, p := e.s.value(id) if !ok { if v, ok := e.s.constant(id); ok { return v, nil @@ -317,9 +353,11 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { if isThrow(r) { return r, nil } - e.s.pushValue(id, r) + e.s.updateValue(f, p, id, r) + e.complexity++ return r, nil } + e.complexity++ return v.value, nil case *FunctionDeclarationNode: @@ -339,14 +377,21 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { return r, nil case *FunctionCallNode: - id := n.Name - f, ok := e.s.system[id] + name := n.Name + f, ok := e.s.system[name] if ok { // System function + cost, ok := e.s.costs[name] + if !ok { + return nil, errors.Errorf("failed to get cost of system function '%s'", name) + } + if _, ok := e.s.free[name]; ok { // + cost = 0 + } args := make([]rideType, len(n.Arguments)) for i, arg := range n.Arguments { a, err := e.walk(arg) // materialize argument if err != nil { - return nil, errors.Wrapf(err, "failed to materialize argument %d of system function '%s'", i+1, id) + return nil, errors.Wrapf(err, "failed to materialize argument %d of system function '%s'", i+1, name) } if isThrow(a) { return a, nil @@ -355,23 +400,25 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } r, err := f(e.env, args...) if err != nil { - return nil, errors.Wrapf(err, "failed to call system function '%s'", id) + return nil, errors.Wrapf(err, "failed to call system function '%s'", name) } + e.complexity += cost return r, nil } - uf, cl, err := e.s.userFunction(id) + uf, cl, err := e.s.userFunction(name) if err != nil { - return nil, errors.Wrapf(err, "failed to call function '%s'", id) + return nil, errors.Wrapf(err, "failed to call function '%s'", name) } if len(n.Arguments) != len(uf.Arguments) { - return nil, errors.Errorf("mismatched arguments number of user function '%s'", id) + return nil, errors.Errorf("mismatched arguments number of user function '%s'", name) } + args := make([]esValue, len(n.Arguments)) for i, arg := range n.Arguments { an := uf.Arguments[i] av, err := e.walk(arg) // materialize argument if err != nil { - return nil, errors.Wrapf(err, "failed to materialize argument '%s' of user function '%s", an, id) + return nil, errors.Wrapf(err, "failed to materialize argument '%s' of user function '%s", an, name) } if isThrow(av) { return av, nil @@ -384,9 +431,10 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } var tmp int tmp, e.s.cl = e.s.cl, cl + r, err := e.walk(uf.Body) if err != nil { - return nil, errors.Wrapf(err, "failed to evaluate function '%s' body", id) + return nil, errors.Wrapf(err, "failed to evaluate function '%s' body", name) } e.s.cs = e.s.cs[:len(e.s.cs)-1] e.s.cl = tmp @@ -398,10 +446,12 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { if err != nil { return nil, errors.Wrapf(err, "failed to evaluate an object to get property '%s' on it", name) } + e.complexity++ if isThrow(obj) { return obj, nil } v, err := obj.get(name) + if err != nil { return nil, errors.Wrapf(err, "failed to get property '%s'", name) } @@ -412,8 +462,8 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } } -func treeVerifierEvaluator(env RideEnvironment, tree *Tree) (*treeEvaluator, error) { - s, err := newEvaluationScope(tree.LibVersion, env) +func treeVerifierEvaluator(env Environment, tree *Tree) (*treeEvaluator, error) { + s, err := newEvaluationScope(tree.LibVersion, env, false) // Invocation is disabled for expression calls if err != nil { return nil, errors.Wrap(err, "failed to create scope") } @@ -447,8 +497,8 @@ func treeVerifierEvaluator(env RideEnvironment, tree *Tree) (*treeEvaluator, err }, nil } -func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (*treeEvaluator, error) { - s, err := newEvaluationScope(tree.LibVersion, env) +func treeFunctionEvaluatorForInvokeDAppFromDApp(env Environment, tree *Tree, name string, args []rideType) (*treeEvaluator, error) { + s, err := newEvaluationScope(tree.LibVersion, env, true) if err != nil { return nil, errors.Wrap(err, "failed to create scope") } @@ -471,6 +521,41 @@ func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args pr if l := len(args); l != len(function.Arguments) { return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) } + // without conversion + for i, arg := range args { + s.pushValue(function.Arguments[i], arg) + } + return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil + } + } + return nil, errors.Errorf("function '%s' not found", name) +} + +func treeFunctionEvaluator(env Environment, tree *Tree, name string, args proto.Arguments) (*treeEvaluator, error) { + s, err := newEvaluationScope(tree.LibVersion, env, true) + if err != nil { + return nil, errors.Wrap(err, "failed to create scope") + } + for _, declaration := range tree.Declarations { + err = s.declare(declaration) + if err != nil { + return nil, errors.Wrap(err, "invalid declaration") + } + } + if !tree.IsDApp() { + return nil, errors.Errorf("unable to call function '%s' on simple script", name) + } + for i := 0; i < len(tree.Functions); i++ { + function, ok := tree.Functions[i].(*FunctionDeclarationNode) + if !ok { + return nil, errors.New("invalid callable declaration") + } + if function.Name == name { + s.constants[function.invocationParameter] = esConstant{c: newInvocation} + if l := len(args); l != len(function.Arguments) { + return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) + } + for i, arg := range args { a, err := convertArgument(arg) if err != nil { diff --git a/pkg/ride/tuples.go b/pkg/ride/tuples.go index 5881bdf62..b0da3ad7e 100644 --- a/pkg/ride/tuples.go +++ b/pkg/ride/tuples.go @@ -14,7 +14,7 @@ type tuple2 struct { el2 rideType } -func newTuple2(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple2(_ Environment, args ...rideType) (rideType, error) { if len(args) != 2 { return nil, errors.New("invalid number of arguments") } @@ -63,7 +63,7 @@ type tuple3 struct { el3 rideType } -func newTuple3(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple3(_ Environment, args ...rideType) (rideType, error) { if len(args) != 3 { return nil, errors.New("invalid number of arguments") } @@ -116,7 +116,7 @@ type tuple4 struct { el4 rideType } -func newTuple4(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple4(_ Environment, args ...rideType) (rideType, error) { if len(args) != 4 { return nil, errors.New("invalid number of arguments") } @@ -173,7 +173,7 @@ type tuple5 struct { el5 rideType } -func newTuple5(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple5(_ Environment, args ...rideType) (rideType, error) { if len(args) != 5 { return nil, errors.New("invalid number of arguments") } @@ -234,7 +234,7 @@ type tuple6 struct { el6 rideType } -func newTuple6(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple6(_ Environment, args ...rideType) (rideType, error) { if len(args) != 6 { return nil, errors.New("invalid number of arguments") } @@ -299,7 +299,7 @@ type tuple7 struct { el7 rideType } -func newTuple7(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple7(_ Environment, args ...rideType) (rideType, error) { if len(args) != 7 { return nil, errors.New("invalid number of arguments") } @@ -368,7 +368,7 @@ type tuple8 struct { el8 rideType } -func newTuple8(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple8(_ Environment, args ...rideType) (rideType, error) { if len(args) != 8 { return nil, errors.New("invalid number of arguments") } @@ -441,7 +441,7 @@ type tuple9 struct { el9 rideType } -func newTuple9(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple9(_ Environment, args ...rideType) (rideType, error) { if len(args) != 9 { return nil, errors.New("invalid number of arguments") } @@ -518,7 +518,7 @@ type tuple10 struct { el10 rideType } -func newTuple10(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple10(_ Environment, args ...rideType) (rideType, error) { if len(args) != 10 { return nil, errors.New("invalid number of arguments") } @@ -599,7 +599,7 @@ type tuple11 struct { el11 rideType } -func newTuple11(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple11(_ Environment, args ...rideType) (rideType, error) { if len(args) != 11 { return nil, errors.New("invalid number of arguments") } @@ -684,7 +684,7 @@ type tuple12 struct { el12 rideType } -func newTuple12(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple12(_ Environment, args ...rideType) (rideType, error) { if len(args) != 12 { return nil, errors.New("invalid number of arguments") } @@ -773,7 +773,7 @@ type tuple13 struct { el13 rideType } -func newTuple13(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple13(_ Environment, args ...rideType) (rideType, error) { if len(args) != 13 { return nil, errors.New("invalid number of arguments") } @@ -866,7 +866,7 @@ type tuple14 struct { el14 rideType } -func newTuple14(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple14(_ Environment, args ...rideType) (rideType, error) { if len(args) != 14 { return nil, errors.New("invalid number of arguments") } @@ -963,7 +963,7 @@ type tuple15 struct { el15 rideType } -func newTuple15(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple15(_ Environment, args ...rideType) (rideType, error) { if len(args) != 15 { return nil, errors.New("invalid number of arguments") } @@ -1064,7 +1064,7 @@ type tuple16 struct { el16 rideType } -func newTuple16(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple16(_ Environment, args ...rideType) (rideType, error) { if len(args) != 16 { return nil, errors.New("invalid number of arguments") } @@ -1169,7 +1169,7 @@ type tuple17 struct { el17 rideType } -func newTuple17(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple17(_ Environment, args ...rideType) (rideType, error) { if len(args) != 17 { return nil, errors.New("invalid number of arguments") } @@ -1278,7 +1278,7 @@ type tuple18 struct { el18 rideType } -func newTuple18(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple18(_ Environment, args ...rideType) (rideType, error) { if len(args) != 18 { return nil, errors.New("invalid number of arguments") } @@ -1391,7 +1391,7 @@ type tuple19 struct { el19 rideType } -func newTuple19(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple19(_ Environment, args ...rideType) (rideType, error) { if len(args) != 19 { return nil, errors.New("invalid number of arguments") } @@ -1508,7 +1508,7 @@ type tuple20 struct { el20 rideType } -func newTuple20(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple20(_ Environment, args ...rideType) (rideType, error) { if len(args) != 20 { return nil, errors.New("invalid number of arguments") } @@ -1629,7 +1629,7 @@ type tuple21 struct { el21 rideType } -func newTuple21(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple21(_ Environment, args ...rideType) (rideType, error) { if len(args) != 21 { return nil, errors.New("invalid number of arguments") } @@ -1754,7 +1754,7 @@ type tuple22 struct { el22 rideType } -func newTuple22(_ RideEnvironment, args ...rideType) (rideType, error) { +func newTuple22(_ Environment, args ...rideType) (rideType, error) { if len(args) != 22 { return nil, errors.New("invalid number of arguments") } diff --git a/pkg/ride/types_moq_test.go b/pkg/ride/types_moq_test.go index e9fc571bc..988e7932f 100644 --- a/pkg/ride/types_moq_test.go +++ b/pkg/ride/types_moq_test.go @@ -29,10 +29,16 @@ var _ types.SmartState = &MockSmartState{} // EstimatorVersionFunc: func() (int, error) { // panic("mock out the EstimatorVersion method") // }, +// GetByteTreeFunc: func(recipient proto.Recipient) (proto.Script, error) { +// panic("mock out the GetByteTree method") +// }, // IsNotFoundFunc: func(err error) bool { // panic("mock out the IsNotFound method") // }, -// NewestAccountBalanceFunc: func(account proto.Recipient, asset []byte) (uint64, error) { +// IsStateUntouchedFunc: func(account proto.Recipient) (bool, error) { +// panic("mock out the IsStateUntouched method") +// }, +// NewestAccountBalanceFunc: func(account proto.Recipient, assetID []byte) (uint64, error) { // panic("mock out the NewestAccountBalance method") // }, // NewestAddrByAliasFunc: func(alias proto.Alias) (proto.Address, error) { @@ -53,6 +59,18 @@ var _ types.SmartState = &MockSmartState{} // NewestHeaderByHeightFunc: func(height uint64) (*proto.BlockHeader, error) { // panic("mock out the NewestHeaderByHeight method") // }, +// NewestLeasingInfoFunc: func(id crypto.Digest) (*proto.LeaseInfo, error) { +// panic("mock out the NewestLeasingInfo method") +// }, +// NewestRecipientToAddressFunc: func(recipient proto.Recipient) (*proto.Address, error) { +// panic("mock out the NewestRecipientToAddress method") +// }, +// NewestScriptByAssetFunc: func(asset proto.OptionalAsset) (proto.Script, error) { +// panic("mock out the NewestScriptByAsset method") +// }, +// NewestScriptPKByAddrFunc: func(addr proto.Address) (crypto.PublicKey, error) { +// panic("mock out the NewestScriptPKByAddr method") +// }, // NewestTransactionByIDFunc: func(in1 []byte) (proto.Transaction, error) { // panic("mock out the NewestTransactionByID method") // }, @@ -87,11 +105,17 @@ type MockSmartState struct { // EstimatorVersionFunc mocks the EstimatorVersion method. EstimatorVersionFunc func() (int, error) + // GetByteTreeFunc mocks the GetByteTree method. + GetByteTreeFunc func(recipient proto.Recipient) (proto.Script, error) + // IsNotFoundFunc mocks the IsNotFound method. IsNotFoundFunc func(err error) bool + // IsStateUntouchedFunc mocks the IsStateUntouched method. + IsStateUntouchedFunc func(account proto.Recipient) (bool, error) + // NewestAccountBalanceFunc mocks the NewestAccountBalance method. - NewestAccountBalanceFunc func(account proto.Recipient, asset []byte) (uint64, error) + NewestAccountBalanceFunc func(account proto.Recipient, assetID []byte) (uint64, error) // NewestAddrByAliasFunc mocks the NewestAddrByAlias method. NewestAddrByAliasFunc func(alias proto.Alias) (proto.Address, error) @@ -111,6 +135,18 @@ type MockSmartState struct { // NewestHeaderByHeightFunc mocks the NewestHeaderByHeight method. NewestHeaderByHeightFunc func(height uint64) (*proto.BlockHeader, error) + // NewestLeasingInfoFunc mocks the NewestLeasingInfo method. + NewestLeasingInfoFunc func(id crypto.Digest) (*proto.LeaseInfo, error) + + // NewestRecipientToAddressFunc mocks the NewestRecipientToAddress method. + NewestRecipientToAddressFunc func(recipient proto.Recipient) (*proto.Address, error) + + // NewestScriptByAssetFunc mocks the NewestScriptByAsset method. + NewestScriptByAssetFunc func(asset proto.OptionalAsset) (proto.Script, error) + + // NewestScriptPKByAddrFunc mocks the NewestScriptPKByAddr method. + NewestScriptPKByAddrFunc func(addr proto.Address) (crypto.PublicKey, error) + // NewestTransactionByIDFunc mocks the NewestTransactionByID method. NewestTransactionByIDFunc func(in1 []byte) (proto.Transaction, error) @@ -144,17 +180,27 @@ type MockSmartState struct { // EstimatorVersion holds details about calls to the EstimatorVersion method. EstimatorVersion []struct { } + // GetByteTree holds details about calls to the GetByteTree method. + GetByteTree []struct { + // Recipient is the recipient argument value. + Recipient proto.Recipient + } // IsNotFound holds details about calls to the IsNotFound method. IsNotFound []struct { // Err is the err argument value. Err error } + // IsStateUntouched holds details about calls to the IsStateUntouched method. + IsStateUntouched []struct { + // Account is the account argument value. + Account proto.Recipient + } // NewestAccountBalance holds details about calls to the NewestAccountBalance method. NewestAccountBalance []struct { // Account is the account argument value. Account proto.Recipient - // Asset is the asset argument value. - Asset []byte + // AssetID is the assetID argument value. + AssetID []byte } // NewestAddrByAlias holds details about calls to the NewestAddrByAlias method. NewestAddrByAlias []struct { @@ -186,6 +232,26 @@ type MockSmartState struct { // Height is the height argument value. Height uint64 } + // NewestLeasingInfo holds details about calls to the NewestLeasingInfo method. + NewestLeasingInfo []struct { + // ID is the id argument value. + ID crypto.Digest + } + // NewestRecipientToAddress holds details about calls to the NewestRecipientToAddress method. + NewestRecipientToAddress []struct { + // Recipient is the recipient argument value. + Recipient proto.Recipient + } + // NewestScriptByAsset holds details about calls to the NewestScriptByAsset method. + NewestScriptByAsset []struct { + // Asset is the asset argument value. + Asset proto.OptionalAsset + } + // NewestScriptPKByAddr holds details about calls to the NewestScriptPKByAddr method. + NewestScriptPKByAddr []struct { + // Addr is the addr argument value. + Addr proto.Address + } // NewestTransactionByID holds details about calls to the NewestTransactionByID method. NewestTransactionByID []struct { // In1 is the in1 argument value. @@ -228,7 +294,9 @@ type MockSmartState struct { lockAddingBlockHeight sync.RWMutex lockBlockVRF sync.RWMutex lockEstimatorVersion sync.RWMutex + lockGetByteTree sync.RWMutex lockIsNotFound sync.RWMutex + lockIsStateUntouched sync.RWMutex lockNewestAccountBalance sync.RWMutex lockNewestAddrByAlias sync.RWMutex lockNewestAssetInfo sync.RWMutex @@ -236,6 +304,10 @@ type MockSmartState struct { lockNewestFullAssetInfo sync.RWMutex lockNewestFullWavesBalance sync.RWMutex lockNewestHeaderByHeight sync.RWMutex + lockNewestLeasingInfo sync.RWMutex + lockNewestRecipientToAddress sync.RWMutex + lockNewestScriptByAsset sync.RWMutex + lockNewestScriptPKByAddr sync.RWMutex lockNewestTransactionByID sync.RWMutex lockNewestTransactionHeightByID sync.RWMutex lockRetrieveNewestBinaryEntry sync.RWMutex @@ -331,6 +403,37 @@ func (mock *MockSmartState) EstimatorVersionCalls() []struct { return calls } +// GetByteTree calls GetByteTreeFunc. +func (mock *MockSmartState) GetByteTree(recipient proto.Recipient) (proto.Script, error) { + if mock.GetByteTreeFunc == nil { + panic("MockSmartState.GetByteTreeFunc: method is nil but SmartState.GetByteTree was just called") + } + callInfo := struct { + Recipient proto.Recipient + }{ + Recipient: recipient, + } + mock.lockGetByteTree.Lock() + mock.calls.GetByteTree = append(mock.calls.GetByteTree, callInfo) + mock.lockGetByteTree.Unlock() + return mock.GetByteTreeFunc(recipient) +} + +// GetByteTreeCalls gets all the calls that were made to GetByteTree. +// Check the length with: +// len(mockedSmartState.GetByteTreeCalls()) +func (mock *MockSmartState) GetByteTreeCalls() []struct { + Recipient proto.Recipient +} { + var calls []struct { + Recipient proto.Recipient + } + mock.lockGetByteTree.RLock() + calls = mock.calls.GetByteTree + mock.lockGetByteTree.RUnlock() + return calls +} + // IsNotFound calls IsNotFoundFunc. func (mock *MockSmartState) IsNotFound(err error) bool { if mock.IsNotFoundFunc == nil { @@ -362,22 +465,53 @@ func (mock *MockSmartState) IsNotFoundCalls() []struct { return calls } +// IsStateUntouched calls IsStateUntouchedFunc. +func (mock *MockSmartState) IsStateUntouched(account proto.Recipient) (bool, error) { + if mock.IsStateUntouchedFunc == nil { + panic("MockSmartState.IsStateUntouchedFunc: method is nil but SmartState.IsStateUntouched was just called") + } + callInfo := struct { + Account proto.Recipient + }{ + Account: account, + } + mock.lockIsStateUntouched.Lock() + mock.calls.IsStateUntouched = append(mock.calls.IsStateUntouched, callInfo) + mock.lockIsStateUntouched.Unlock() + return mock.IsStateUntouchedFunc(account) +} + +// IsStateUntouchedCalls gets all the calls that were made to IsStateUntouched. +// Check the length with: +// len(mockedSmartState.IsStateUntouchedCalls()) +func (mock *MockSmartState) IsStateUntouchedCalls() []struct { + Account proto.Recipient +} { + var calls []struct { + Account proto.Recipient + } + mock.lockIsStateUntouched.RLock() + calls = mock.calls.IsStateUntouched + mock.lockIsStateUntouched.RUnlock() + return calls +} + // NewestAccountBalance calls NewestAccountBalanceFunc. -func (mock *MockSmartState) NewestAccountBalance(account proto.Recipient, asset []byte) (uint64, error) { +func (mock *MockSmartState) NewestAccountBalance(account proto.Recipient, assetID []byte) (uint64, error) { if mock.NewestAccountBalanceFunc == nil { panic("MockSmartState.NewestAccountBalanceFunc: method is nil but SmartState.NewestAccountBalance was just called") } callInfo := struct { Account proto.Recipient - Asset []byte + AssetID []byte }{ Account: account, - Asset: asset, + AssetID: assetID, } mock.lockNewestAccountBalance.Lock() mock.calls.NewestAccountBalance = append(mock.calls.NewestAccountBalance, callInfo) mock.lockNewestAccountBalance.Unlock() - return mock.NewestAccountBalanceFunc(account, asset) + return mock.NewestAccountBalanceFunc(account, assetID) } // NewestAccountBalanceCalls gets all the calls that were made to NewestAccountBalance. @@ -385,11 +519,11 @@ func (mock *MockSmartState) NewestAccountBalance(account proto.Recipient, asset // len(mockedSmartState.NewestAccountBalanceCalls()) func (mock *MockSmartState) NewestAccountBalanceCalls() []struct { Account proto.Recipient - Asset []byte + AssetID []byte } { var calls []struct { Account proto.Recipient - Asset []byte + AssetID []byte } mock.lockNewestAccountBalance.RLock() calls = mock.calls.NewestAccountBalance @@ -583,6 +717,130 @@ func (mock *MockSmartState) NewestHeaderByHeightCalls() []struct { return calls } +// NewestLeasingInfo calls NewestLeasingInfoFunc. +func (mock *MockSmartState) NewestLeasingInfo(id crypto.Digest) (*proto.LeaseInfo, error) { + if mock.NewestLeasingInfoFunc == nil { + panic("MockSmartState.NewestLeasingInfoFunc: method is nil but SmartState.NewestLeasingInfo was just called") + } + callInfo := struct { + ID crypto.Digest + }{ + ID: id, + } + mock.lockNewestLeasingInfo.Lock() + mock.calls.NewestLeasingInfo = append(mock.calls.NewestLeasingInfo, callInfo) + mock.lockNewestLeasingInfo.Unlock() + return mock.NewestLeasingInfoFunc(id) +} + +// NewestLeasingInfoCalls gets all the calls that were made to NewestLeasingInfo. +// Check the length with: +// len(mockedSmartState.NewestLeasingInfoCalls()) +func (mock *MockSmartState) NewestLeasingInfoCalls() []struct { + ID crypto.Digest +} { + var calls []struct { + ID crypto.Digest + } + mock.lockNewestLeasingInfo.RLock() + calls = mock.calls.NewestLeasingInfo + mock.lockNewestLeasingInfo.RUnlock() + return calls +} + +// NewestRecipientToAddress calls NewestRecipientToAddressFunc. +func (mock *MockSmartState) NewestRecipientToAddress(recipient proto.Recipient) (*proto.Address, error) { + if mock.NewestRecipientToAddressFunc == nil { + panic("MockSmartState.NewestRecipientToAddressFunc: method is nil but SmartState.NewestRecipientToAddress was just called") + } + callInfo := struct { + Recipient proto.Recipient + }{ + Recipient: recipient, + } + mock.lockNewestRecipientToAddress.Lock() + mock.calls.NewestRecipientToAddress = append(mock.calls.NewestRecipientToAddress, callInfo) + mock.lockNewestRecipientToAddress.Unlock() + return mock.NewestRecipientToAddressFunc(recipient) +} + +// NewestRecipientToAddressCalls gets all the calls that were made to NewestRecipientToAddress. +// Check the length with: +// len(mockedSmartState.NewestRecipientToAddressCalls()) +func (mock *MockSmartState) NewestRecipientToAddressCalls() []struct { + Recipient proto.Recipient +} { + var calls []struct { + Recipient proto.Recipient + } + mock.lockNewestRecipientToAddress.RLock() + calls = mock.calls.NewestRecipientToAddress + mock.lockNewestRecipientToAddress.RUnlock() + return calls +} + +// NewestScriptByAsset calls NewestScriptByAssetFunc. +func (mock *MockSmartState) NewestScriptByAsset(asset proto.OptionalAsset) (proto.Script, error) { + if mock.NewestScriptByAssetFunc == nil { + panic("MockSmartState.NewestScriptByAssetFunc: method is nil but SmartState.NewestScriptByAsset was just called") + } + callInfo := struct { + Asset proto.OptionalAsset + }{ + Asset: asset, + } + mock.lockNewestScriptByAsset.Lock() + mock.calls.NewestScriptByAsset = append(mock.calls.NewestScriptByAsset, callInfo) + mock.lockNewestScriptByAsset.Unlock() + return mock.NewestScriptByAssetFunc(asset) +} + +// NewestScriptByAssetCalls gets all the calls that were made to NewestScriptByAsset. +// Check the length with: +// len(mockedSmartState.NewestScriptByAssetCalls()) +func (mock *MockSmartState) NewestScriptByAssetCalls() []struct { + Asset proto.OptionalAsset +} { + var calls []struct { + Asset proto.OptionalAsset + } + mock.lockNewestScriptByAsset.RLock() + calls = mock.calls.NewestScriptByAsset + mock.lockNewestScriptByAsset.RUnlock() + return calls +} + +// NewestScriptPKByAddr calls NewestScriptPKByAddrFunc. +func (mock *MockSmartState) NewestScriptPKByAddr(addr proto.Address) (crypto.PublicKey, error) { + if mock.NewestScriptPKByAddrFunc == nil { + panic("MockSmartState.NewestScriptPKByAddrFunc: method is nil but SmartState.NewestScriptPKByAddr was just called") + } + callInfo := struct { + Addr proto.Address + }{ + Addr: addr, + } + mock.lockNewestScriptPKByAddr.Lock() + mock.calls.NewestScriptPKByAddr = append(mock.calls.NewestScriptPKByAddr, callInfo) + mock.lockNewestScriptPKByAddr.Unlock() + return mock.NewestScriptPKByAddrFunc(addr) +} + +// NewestScriptPKByAddrCalls gets all the calls that were made to NewestScriptPKByAddr. +// Check the length with: +// len(mockedSmartState.NewestScriptPKByAddrCalls()) +func (mock *MockSmartState) NewestScriptPKByAddrCalls() []struct { + Addr proto.Address +} { + var calls []struct { + Addr proto.Address + } + mock.lockNewestScriptPKByAddr.RLock() + calls = mock.calls.NewestScriptPKByAddr + mock.lockNewestScriptPKByAddr.RUnlock() + return calls +} + // NewestTransactionByID calls NewestTransactionByIDFunc. func (mock *MockSmartState) NewestTransactionByID(in1 []byte) (proto.Transaction, error) { if mock.NewestTransactionByIDFunc == nil { diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 1cf82c282..d2c7e4c82 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -27,7 +27,7 @@ func newFunctionFrame(pos int, args []rideType) frame { } type vm struct { - env RideEnvironment + env Environment code []byte ip int constants []rideType @@ -38,7 +38,7 @@ type vm struct { functionName func(int) string } -func (m *vm) run() (RideResult, error) { +func (m *vm) run() (Result, error) { if m.stack != nil { m.stack = m.stack[0:0] } diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index 8ffd6ba27..fa6ff54ac 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -34,7 +34,7 @@ func TestExecution(t *testing.T) { for _, test := range []struct { comment string source string - env RideEnvironment + env Environment res bool }{ {`V1: true`, "AQa3b8tH", nil, true}, @@ -218,7 +218,7 @@ func TestFunctions(t *testing.T) { name string text string script string - env RideEnvironment + env Environment result bool error bool }{ diff --git a/pkg/settings/features.go b/pkg/settings/features.go index fcfe72e5d..d31ff9702 100644 --- a/pkg/settings/features.go +++ b/pkg/settings/features.go @@ -18,6 +18,7 @@ const ( ReduceNFTFee BlockReward // 14 BlockV5 // 15 + RideV5 // 16 LeaseExpiration ) @@ -42,5 +43,6 @@ var FeaturesInfo = map[Feature]FeatureInfo{ ReduceNFTFee: {true, "Reduce NFT fee"}, BlockReward: {true, "Block Reward and Community Driven Monetary Policy"}, BlockV5: {true, "Ride V4, VRF, Protobuf, Failed transactions"}, + RideV5: {true, "Ride V5, dApp-to-dApp invocations"}, LeaseExpiration: {false, "Lease Expiration"}, } diff --git a/pkg/state/accounts_data_storage.go b/pkg/state/accounts_data_storage.go index ef2f97ee9..7d09fb962 100644 --- a/pkg/state/accounts_data_storage.go +++ b/pkg/state/accounts_data_storage.go @@ -269,6 +269,29 @@ func (s *accountsDataStorage) retrieveEntries(addr proto.Address, filter bool) ( return entries, nil } +func (s *accountsDataStorage) entryExists(addr proto.Address, filter bool) (bool, error) { + addrNum, err := s.addrToNum(addr) + if err != nil { + return false, err + } + key := accountsDataStorKey{addrNum: addrNum} + iter, err := s.hs.newTopEntryIteratorByPrefix(key.accountPrefix(), filter) + if err != nil { + return false, err + } + defer func() { + iter.Release() + if err := iter.Error(); err != nil { + zap.S().Fatalf("Iterator error: %v", err) + } + }() + + for iter.Next() { + return true, nil + } + return false, nil +} + func (s *accountsDataStorage) retrieveNewestEntry(addr proto.Address, key string, filter bool) (proto.DataEntry, error) { id := entryId{addr, key} if entry, ok := s.uncertainEntries[id]; ok { diff --git a/pkg/state/address_transactions.go b/pkg/state/address_transactions.go index 1ebadcc54..51e73b3aa 100644 --- a/pkg/state/address_transactions.go +++ b/pkg/state/address_transactions.go @@ -26,7 +26,7 @@ const ( ) var ( - fileSizeKeyBytes = []byte{txsByAddrsFileSizeKeyPrefix} + fileSizeKeyBytes = []byte{txsByAddressesFileSizeKeyPrefix} ) type txMeta struct { @@ -297,7 +297,12 @@ func (at *addressTransactions) persist(filter bool) error { if err != nil { return errors.Wrap(err, "failed to create temp file for emsort") } - defer os.Remove(tempFile.Name()) + defer func(name string) { + err := os.Remove(name) + if err != nil { + zap.S().Warnf("Failed to remove temporary file: %v", err) + } + }(tempFile.Name()) sort, err := emsort.NewFixedSize(addrTxRecordSize, maxEmsortMem, tempFile) if err != nil { return errors.Wrap(err, "emsort.NewFixedSize() failed") diff --git a/pkg/state/aliases.go b/pkg/state/aliases.go index 8eeaba9b9..c8a45ba89 100644 --- a/pkg/state/aliases.go +++ b/pkg/state/aliases.go @@ -194,7 +194,12 @@ func (a *aliases) disableStolenAliases() error { if err != nil { return err } - + defer func() { + iter.Release() + if err := iter.Error(); err != nil { + zap.S().Fatalf("Iterator error: %v", err) + } + }() for iter.Next() { keyBytes := iter.Key() recordBytes := iter.Value() @@ -211,9 +216,7 @@ func (a *aliases) disableStolenAliases() error { a.disabled[key.alias] = true } } - - iter.Release() - return iter.Error() + return nil } func (a *aliases) prepareHashes() error { @@ -231,3 +234,27 @@ func (a *aliases) reset() { a.disabled = make(map[string]bool) a.hasher.reset() } + +func (a *aliases) disabledAliases() (map[string]struct{}, error) { + iter, err := a.db.NewKeyIterator([]byte{disabledAliasKeyPrefix}) + if err != nil { + return nil, err + } + defer func() { + iter.Release() + if err := iter.Error(); err != nil { + zap.S().Fatalf("Iterator error: %v", err) + } + }() + als := make(map[string]struct{}) + for iter.Next() { + keyBytes := iter.Key() + var key disabledAliasKey + err := key.unmarshal(keyBytes) + if err != nil { + return nil, err + } + als[key.alias] = struct{}{} + } + return als, nil +} diff --git a/pkg/state/aliases_test.go b/pkg/state/aliases_test.go index ac2ad3ee7..071d48e61 100644 --- a/pkg/state/aliases_test.go +++ b/pkg/state/aliases_test.go @@ -56,7 +56,7 @@ func TestDisableStolenAliases(t *testing.T) { to.flush(t) err = to.entities.aliases.disableStolenAliases() - assert.NoError(t, err, "disableStolenAlises() failed") + assert.NoError(t, err, "disableStolenAliases() failed") to.flush(t) disabled, err := to.entities.aliases.isDisabled(aliasStr) assert.NoError(t, err, "isDisabled() failed") diff --git a/pkg/state/api.go b/pkg/state/api.go index 3cf065327..27a96356e 100644 --- a/pkg/state/api.go +++ b/pkg/state/api.go @@ -59,8 +59,6 @@ type StateInfo interface { // Retrieve current blockchain settings. BlockchainSettings() (*settings.BlockchainSettings, error) - Peers() ([]proto.TCPAddr, error) - // Features. VotesNum(featureID int16) (uint64, error) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) @@ -169,9 +167,6 @@ type StateModifier interface { // Way to call multiple operations under same lock. Map(func(state NonThreadSafeState) error) error - // Create or replace Peers. - SavePeers([]proto.TCPAddr) error - // State will provide extended API data after returning. StartProvidingExtendedApi() error diff --git a/pkg/state/appender.go b/pkg/state/appender.go index 54bb847ac..f255c33d9 100644 --- a/pkg/state/appender.go +++ b/pkg/state/appender.go @@ -210,17 +210,17 @@ func (a *txAppender) checkTxFees(tx proto.Transaction, info *fallibleValidationP } // This function is used for script validation of transaction that can't fail. -func (a *txAppender) checkTransactionScripts(tx proto.Transaction, accountScripted bool, checkerInfo *checkerInfo, blockInfo *proto.BlockInfo) (uint64, error) { +func (a *txAppender) checkTransactionScripts(tx proto.Transaction, accountScripted bool, params *appendTxParams) (uint64, error) { scriptsRuns := uint64(0) if accountScripted { // Check script. - if err := a.sc.callAccountScriptWithTx(tx, blockInfo, checkerInfo.initialisation); err != nil { + if err := a.sc.callAccountScriptWithTx(tx, params); err != nil { return 0, errs.Extend(err, "callAccountScriptWithTx") } scriptsRuns++ } // Check against state. - txSmartAssets, err := a.txHandler.checkTx(tx, checkerInfo) + txSmartAssets, err := a.txHandler.checkTx(tx, params.checkerInfo) if err != nil { return 0, err } @@ -230,7 +230,7 @@ func (a *txAppender) checkTransactionScripts(tx proto.Transaction, accountScript } for _, smartAsset := range txSmartAssets { // Check smart asset's script. - _, err := a.sc.callAssetScript(tx, smartAsset, blockInfo, checkerInfo.initialisation, false) + _, err := a.sc.callAssetScript(tx, smartAsset, params) if err != nil { return 0, errs.Extend(err, "callAssetScript") } @@ -243,7 +243,7 @@ func (a *txAppender) checkTransactionScripts(tx proto.Transaction, accountScript return scriptsRuns, nil } -func (a *txAppender) checkScriptsLimits(scriptsRuns uint64) error { +func (a *txAppender) checkScriptsLimits(scriptsRuns uint64, blockID proto.BlockID) error { smartAccountsActivated, err := a.stor.features.newestIsActivated(int16(settings.SmartAccounts)) if err != nil { return err @@ -253,9 +253,14 @@ func (a *txAppender) checkScriptsLimits(scriptsRuns uint64) error { return err } if ride4DAppsActivated { - // TODO: fix estimator and return error here instead of warning. - if a.sc.getTotalComplexity() > maxScriptsComplexityInBlock { - zap.S().Warn("complexity limit per block is exceeded") + rideV5Activated, err := a.stor.features.newestIsActivated(int16(settings.RideV5)) + if err != nil { + return errors.Wrapf(err, "failed to check if feature %d is activated", settings.RideV5) + } + maxBlockComplexity := NewMaxScriptsComplexityInBlock().GetMaxScriptsComplexityInBlock(rideV5Activated) + if a.sc.getTotalComplexity() > uint64(maxBlockComplexity) { + // TODO this is definitely an error, should return it + zap.S().Warnf("Complexity of scripts (%d) in block '%s' exceeds limit of %d", a.sc.getTotalComplexity(), blockID.String(), maxBlockComplexity) } return nil } else if smartAccountsActivated { @@ -374,6 +379,7 @@ type appendTxParams struct { block *proto.BlockHeader acceptFailed bool blockV5Activated bool + rideV5Activated bool validatingUtx bool initialisation bool } @@ -412,7 +418,7 @@ func (a *txAppender) appendTx(tx proto.Transaction, params *appendTxParams) erro case proto.InvokeScriptTransaction, proto.ExchangeTransaction: // Invoke and Exchange transactions should be handled differently. // They may fail, and will be saved to blockchain anyway. - fallibleInfo := &fallibleValidationParams{*params, accountHasVerifierScript} + fallibleInfo := &fallibleValidationParams{params, accountHasVerifierScript} applicationRes, err = a.handleFallible(tx, fallibleInfo) if err != nil { msg := "fallible validation failed" @@ -426,7 +432,7 @@ func (a *txAppender) appendTx(tx proto.Transaction, params *appendTxParams) erro needToValidateBalanceDiff = params.validatingUtx && !params.acceptFailed default: // Execute transaction's scripts, check against state. - txScriptsRuns, err := a.checkTransactionScripts(tx, accountHasVerifierScript, params.checkerInfo, params.blockInfo) + txScriptsRuns, err := a.checkTransactionScripts(tx, accountHasVerifierScript, params) if err != nil { return err } @@ -447,7 +453,7 @@ func (a *txAppender) appendTx(tx proto.Transaction, params *appendTxParams) erro } } // Check complexity limits and scripts runs limits. - if err := a.checkScriptsLimits(a.totalScriptsRuns + applicationRes.totalScriptsRuns); err != nil { + if err := a.checkScriptsLimits(a.totalScriptsRuns+applicationRes.totalScriptsRuns, blockID); err != nil { return errs.Extend(errors.Errorf("%s: %v", blockID.String(), err), "check scripts limits") } // Perform state changes, save balance changes, write tx to storage. @@ -506,6 +512,10 @@ func (a *txAppender) appendBlock(params *appendBlockParams) error { if err != nil { return err } + rideV5Activated, err := a.stor.features.newestIsActivated(int16(settings.RideV5)) + if err != nil { + return err + } // Check and append transactions. for _, tx := range params.transactions { appendTxArgs := &appendTxParams{ @@ -515,6 +525,7 @@ func (a *txAppender) appendBlock(params *appendBlockParams) error { block: params.block, acceptFailed: blockV5Activated, blockV5Activated: blockV5Activated, + rideV5Activated: rideV5Activated, validatingUtx: false, initialisation: params.initialisation, } @@ -542,7 +553,7 @@ func (a *txAppender) moveChangesToHistoryStorage(initialisation bool) error { } type fallibleValidationParams struct { - appendTxParams + *appendTxParams senderScripted bool } @@ -589,7 +600,7 @@ func (a *txAppender) handleExchange(tx proto.Transaction, info *fallibleValidati // At first, we call accounts and orders scripts which must not fail. if info.senderScripted { // Check script on account. - err := a.sc.callAccountScriptWithTx(tx, info.blockInfo, info.initialisation) + err := a.sc.callAccountScriptWithTx(tx, info.appendTxParams) if err != nil { return nil, err } @@ -613,13 +624,13 @@ func (a *txAppender) handleExchange(tx proto.Transaction, info *fallibleValidati return nil, err } if o1Scripted { - if err := a.sc.callAccountScriptWithOrder(o1, info.blockInfo, info.initialisation); err != nil { + if err := a.sc.callAccountScriptWithOrder(o1, info.blockInfo, info.rideV5Activated, info.initialisation); err != nil { return nil, errors.Wrap(err, "script failure on first order") } scriptsRuns++ } if o2Scripted { - if err := a.sc.callAccountScriptWithOrder(o2, info.blockInfo, info.initialisation); err != nil { + if err := a.sc.callAccountScriptWithOrder(o2, info.blockInfo, info.rideV5Activated, info.initialisation); err != nil { return nil, errors.Wrap(err, "script failure on second order") } scriptsRuns++ @@ -648,7 +659,7 @@ func (a *txAppender) handleExchange(tx proto.Transaction, info *fallibleValidati } // Check smart assets' scripts. for _, smartAsset := range txSmartAssets { - res, err := a.sc.callAssetScript(tx, smartAsset, info.blockInfo, info.initialisation, info.acceptFailed) + res, err := a.sc.callAssetScript(tx, smartAsset, info.appendTxParams) if err != nil && !info.acceptFailed { return nil, err } diff --git a/pkg/state/common_test.go b/pkg/state/common_test.go index c23877b06..88c1cf397 100644 --- a/pkg/state/common_test.go +++ b/pkg/state/common_test.go @@ -79,7 +79,7 @@ func defaultBlockInfo() *proto.BlockInfo { } } -func defaultDifferInfo(t *testing.T) *differInfo { +func defaultDifferInfo() *differInfo { return &differInfo{false, defaultBlockInfo()} } @@ -97,7 +97,7 @@ func defaultAppendTxParams(t *testing.T) *appendTxParams { func defaultFallibleValidationParams(t *testing.T) *fallibleValidationParams { appendTxPrms := defaultAppendTxParams(t) return &fallibleValidationParams{ - appendTxParams: *appendTxPrms, + appendTxParams: appendTxPrms, senderScripted: false, } } diff --git a/pkg/state/constants.go b/pkg/state/constants.go index a5e35f063..5147d0cd9 100644 --- a/pkg/state/constants.go +++ b/pkg/state/constants.go @@ -25,7 +25,7 @@ const ( // StateVersion is current version of state internal storage formats. // It increases when backward compatibility with previous storage version is lost. - StateVersion = 7 + StateVersion = 8 // Memory limit for address transactions. flush() is called when this // limit is exceeded. diff --git a/pkg/state/constraints.go b/pkg/state/constraints.go new file mode 100644 index 000000000..d9308d8e1 --- /dev/null +++ b/pkg/state/constraints.go @@ -0,0 +1,27 @@ +package state + +const ( + FailFreeInvokeComplexity = 1000 + FreeVerifierComplexity = 200 + MaxVerifierScriptComplexityReduced = 2000 + MaxVerifierScriptComplexity = 4000 + MaxCallableScriptComplexityV12 = 2000 + MaxCallableScriptComplexityV34 = 4000 + MaxCallableScriptComplexityV5 = 10000 +) + +type MaxScriptsComplexityInBlock struct { + BeforeActivationRideV5Feature int + AfterActivationRideV5Feature int +} + +func NewMaxScriptsComplexityInBlock() MaxScriptsComplexityInBlock { + return MaxScriptsComplexityInBlock{BeforeActivationRideV5Feature: 1000000, AfterActivationRideV5Feature: 2500000} +} + +func (a MaxScriptsComplexityInBlock) GetMaxScriptsComplexityInBlock(isRideV5Activated bool) int { + if isRideV5Activated { + return a.AfterActivationRideV5Feature + } + return a.BeforeActivationRideV5Feature +} diff --git a/pkg/state/diff_applier_test.go b/pkg/state/diff_applier_test.go index fac8ac454..2c3c63a02 100644 --- a/pkg/state/diff_applier_test.go +++ b/pkg/state/diff_applier_test.go @@ -71,7 +71,7 @@ func TestDiffApplierWithWaves(t *testing.T) { to.stor.flush(t) profile, err = to.stor.entities.balances.wavesBalance(testGlobal.senderInfo.addr, true) assert.NoError(t, err, "wavesBalance() failed") - assert.Equal(t, diff.leaseIn, int64(profile.leaseIn)) + assert.Equal(t, diff.leaseIn, profile.leaseIn) // Test that leasing leased money leads to error. diff = balanceDiff{leaseOut: 101, blockID: blockID0} changes = []balanceChanges{ @@ -133,13 +133,13 @@ func TestTransferOverspend(t *testing.T) { to.stor.addBlock(t, blockID0) // Create overspend transfer to self. tx := createTransferWithSig(t) - info := defaultDifferInfo(t) + info := defaultDifferInfo() info.blockInfo.Timestamp = settings.MainNetSettings.CheckTempNegativeAfterTime - 1 tx.Timestamp = info.blockInfo.Timestamp tx.Recipient = proto.NewRecipientFromAddress(testGlobal.senderInfo.addr) // Set balance equal to tx Fee. err := to.stor.entities.balances.setAssetBalance(testGlobal.senderInfo.addr, testGlobal.asset0.assetID, tx.Fee, blockID0) - assert.NoError(t, err, "setAssetBalacne() failed") + assert.NoError(t, err, "setAssetBalance() failed") to.stor.flush(t) // Sending to self more than possess before settings.MainNetSettings.CheckTempNegativeAfterTime is fine. diff --git a/pkg/state/fee_validation.go b/pkg/state/fee_validation.go index f85f57eff..280990a2b 100644 --- a/pkg/state/fee_validation.go +++ b/pkg/state/fee_validation.go @@ -141,9 +141,17 @@ type txCosts struct { total uint64 } -func newTxCosts(smartAssets, smartAccounts uint64) *txCosts { +func newTxCosts(smartAssets, smartAccounts uint64, isRideV5Activated bool, complexity int, isAccountScripted bool) *txCosts { smartAssetsFee := smartAssets * scriptExtraFee smartAccountsFee := smartAccounts * scriptExtraFee + + if isRideV5Activated { + smartAssetsFee = 0 // since RideV5 we have to erase extra fee for smart asset scripts + } + + if isAccountScripted && isRideV5Activated && complexity <= FreeVerifierComplexity { + smartAccountsFee = 0 + } return &txCosts{ smartAssets: smartAssets, smartAssetsFee: smartAssetsFee, @@ -168,7 +176,7 @@ func (tc *txCosts) toString() string { return str } -func scriptsCost(tx proto.Transaction, params *feeValidationParams) (*txCosts, error) { +func scriptsCost(tx proto.Transaction, params *feeValidationParams, isRideV5Activated bool, estimatorVersion int) (*txCosts, error) { smartAssets := uint64(len(params.txAssets.smartAssets)) senderAddr, err := proto.NewAddressFromPublicKey(params.settings.AddressSchemeCharacter, tx.GetSenderPK()) if err != nil { @@ -178,6 +186,17 @@ func scriptsCost(tx proto.Transaction, params *feeValidationParams) (*txCosts, e if err != nil { return nil, err } + + // check complexity of script for free verifier if complexity <= 200 + complexity := 0 + if accountScripted && isRideV5Activated { + treeEstimation, err := params.stor.scriptsComplexity.newestScriptComplexityByAddr(senderAddr, estimatorVersion, !params.initialisation) + if err != nil { + return nil, errors.Errorf("failed to get complexity by addr from store, %v", err) + } + complexity = treeEstimation.Verifier + } + smartAccounts := uint64(0) if accountScripted { smartAccounts = 1 @@ -193,16 +212,16 @@ func scriptsCost(tx proto.Transaction, params *feeValidationParams) (*txCosts, e smartAssets += 1 } } - return newTxCosts(smartAssets, smartAccounts), nil + return newTxCosts(smartAssets, smartAccounts, isRideV5Activated, complexity, accountScripted), nil } -func minFeeInWaves(tx proto.Transaction, params *feeValidationParams) (*txCosts, error) { +func minFeeInWaves(tx proto.Transaction, params *feeValidationParams, isRideV5Activated bool, estimatorVersion int) (*txCosts, error) { feeInUnits, err := minFeeInUnits(params, tx) if err != nil { return nil, err } minFee := feeInUnits * FeeUnit - cost, err := scriptsCost(tx, params) + cost, err := scriptsCost(tx, params, isRideV5Activated, estimatorVersion) if err != nil { return nil, err } @@ -210,8 +229,8 @@ func minFeeInWaves(tx proto.Transaction, params *feeValidationParams) (*txCosts, return cost, nil } -func checkMinFeeWaves(tx proto.Transaction, params *feeValidationParams) error { - minWaves, err := minFeeInWaves(tx, params) +func checkMinFeeWaves(tx proto.Transaction, params *feeValidationParams, isRideV5Activated bool, estimatorVersion int) error { + minWaves, err := minFeeInWaves(tx, params, isRideV5Activated, estimatorVersion) if err != nil { return errors.Errorf("failed to calculate min fee in Waves: %v\n", err) } @@ -223,7 +242,7 @@ func checkMinFeeWaves(tx proto.Transaction, params *feeValidationParams) error { return nil } -func checkMinFeeAsset(tx proto.Transaction, feeAssetID crypto.Digest, params *feeValidationParams) error { +func checkMinFeeAsset(tx proto.Transaction, feeAssetID crypto.Digest, params *feeValidationParams, isRideV5Activated bool, estimatorVersion int) error { isSponsored, err := params.stor.sponsoredAssets.newestIsSponsored(feeAssetID, !params.initialisation) if err != nil { return errors.Errorf("newestIsSponsored: %v", err) @@ -231,7 +250,7 @@ func checkMinFeeAsset(tx proto.Transaction, feeAssetID crypto.Digest, params *fe if !isSponsored { return errs.NewTxValidationError(fmt.Sprintf("Asset %s is not sponsored, cannot be used to pay fees", feeAssetID.String())) } - minWaves, err := minFeeInWaves(tx, params) + minWaves, err := minFeeInWaves(tx, params, isRideV5Activated, estimatorVersion) if err != nil { return errors.Errorf("failed to calculate min fee in Waves: %v\n", err) } diff --git a/pkg/state/fee_validation_test.go b/pkg/state/fee_validation_test.go index f8d0c1dc7..7039bc722 100644 --- a/pkg/state/fee_validation_test.go +++ b/pkg/state/fee_validation_test.go @@ -41,11 +41,11 @@ func TestAssetScriptExtraFee(t *testing.T) { initialisation: false, txAssets: &txAssets{feeAsset: proto.OptionalAsset{Present: false}, smartAssets: []crypto.Digest{tx.AssetID}}, } - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) // it doesn't matter for these tests what version estimator is assert.Error(t, err, "checkMinFeeWaves() did not fail with invalid Burn fee") // One more extra fee for asset script must be added. tx.Fee += scriptExtraFee - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeWaves() failed with valid Burn fee") } @@ -75,10 +75,10 @@ func TestAccountScriptExtraFee(t *testing.T) { initialisation: false, txAssets: &txAssets{feeAsset: proto.OptionalAsset{Present: false}}, } - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) assert.Error(t, err, "checkMinFeeWaves() did not fail with invalid Burn fee") tx.Fee += scriptExtraFee - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeWaves() failed with valid Burn fee") } @@ -101,11 +101,11 @@ func TestCheckMinFeeWaves(t *testing.T) { initialisation: false, txAssets: &txAssets{feeAsset: proto.OptionalAsset{Present: false}}, } - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeWaves() failed with valid Burn fee") tx.Fee = 1 - err = checkMinFeeWaves(tx, params) + err = checkMinFeeWaves(tx, params, false, maxEstimatorVersion) assert.Error(t, err, "checkMinFeeWaves() did not fail with invalid Burn fee") // MassTransfer special case. @@ -113,21 +113,21 @@ func TestCheckMinFeeWaves(t *testing.T) { entries := generateMassTransferEntries(t, entriesNum) tx1 := createMassTransferWithProofs(t, entries) tx1.Fee = FeeUnit * 34 - err = checkMinFeeWaves(tx1, params) + err = checkMinFeeWaves(tx1, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeWaves() failed with valid MassTransfer fee") tx1.Fee -= 1 - err = checkMinFeeWaves(tx1, params) + err = checkMinFeeWaves(tx1, params, false, maxEstimatorVersion) assert.Error(t, err, "checkMinFeeWaves did not fail with invalid MassTransfer fee") // Data transaction special case. tx2 := createDataWithProofs(t, 100) tx2.Fee = FeeUnit * 2 - err = checkMinFeeWaves(tx2, params) + err = checkMinFeeWaves(tx2, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeWaves() failed with valid Data transaction fee") tx2.Fee -= 1 - err = checkMinFeeWaves(tx2, params) + err = checkMinFeeWaves(tx2, params, false, maxEstimatorVersion) assert.Error(t, err, "checkMinFeeWaves() did not fail with invalid Data transaction fee") } @@ -157,11 +157,11 @@ func TestCheckMinFeeAsset(t *testing.T) { to.stor.flush(t) tx.Fee = 1 * assetCost - err = checkMinFeeAsset(tx, tx.FeeAsset.ID, params) + err = checkMinFeeAsset(tx, tx.FeeAsset.ID, params, false, maxEstimatorVersion) assert.NoError(t, err, "checkMinFeeAsset() failed with valid Transfer transaction fee in asset") tx.Fee -= 1 - err = checkMinFeeAsset(tx, tx.FeeAsset.ID, params) + err = checkMinFeeAsset(tx, tx.FeeAsset.ID, params, false, maxEstimatorVersion) assert.Error(t, err, "checkMinFeeAsset() did not fail with invalid Transfer transaction fee in asset") } @@ -189,23 +189,23 @@ func TestNFTMinFee(t *testing.T) { nftA1 := createNFTIssueWithSig(t) nftA2 := createNFTIssueWithProofs(t) - require.Error(t, checkMinFeeWaves(issueA1, params)) - require.Error(t, checkMinFeeWaves(issueA2, params)) - require.NoError(t, checkMinFeeWaves(issueB1, params)) - require.NoError(t, checkMinFeeWaves(issueB2, params)) + require.Error(t, checkMinFeeWaves(issueA1, params, false, maxEstimatorVersion)) + require.Error(t, checkMinFeeWaves(issueA2, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(issueB1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(issueB2, params, false, maxEstimatorVersion)) - require.Error(t, checkMinFeeWaves(nftA1, params)) - require.Error(t, checkMinFeeWaves(nftA2, params)) + require.Error(t, checkMinFeeWaves(nftA1, params, false, maxEstimatorVersion)) + require.Error(t, checkMinFeeWaves(nftA2, params, false, maxEstimatorVersion)) storage.activateFeature(t, int16(settings.ReduceNFTFee)) - require.Error(t, checkMinFeeWaves(issueA1, params)) - require.Error(t, checkMinFeeWaves(issueA2, params)) - require.NoError(t, checkMinFeeWaves(issueB1, params)) - require.NoError(t, checkMinFeeWaves(issueB2, params)) + require.Error(t, checkMinFeeWaves(issueA1, params, false, maxEstimatorVersion)) + require.Error(t, checkMinFeeWaves(issueA2, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(issueB1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(issueB2, params, false, maxEstimatorVersion)) - require.NoError(t, checkMinFeeWaves(nftA1, params)) - require.NoError(t, checkMinFeeWaves(nftA2, params)) + require.NoError(t, checkMinFeeWaves(nftA1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(nftA2, params, false, maxEstimatorVersion)) } func TestReissueFeeReduction(t *testing.T) { @@ -230,17 +230,17 @@ func TestReissueFeeReduction(t *testing.T) { reissueB1 := createReissueWithSig(t, 1000) reissueB2 := createReissueWithProofs(t, 1000) - require.Error(t, checkMinFeeWaves(reissueA1, params)) - require.Error(t, checkMinFeeWaves(reissueA2, params)) - require.NoError(t, checkMinFeeWaves(reissueB1, params)) - require.NoError(t, checkMinFeeWaves(reissueB2, params)) + require.Error(t, checkMinFeeWaves(reissueA1, params, false, maxEstimatorVersion)) + require.Error(t, checkMinFeeWaves(reissueA2, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(reissueB1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(reissueB2, params, false, maxEstimatorVersion)) storage.activateFeature(t, int16(settings.BlockV5)) - require.NoError(t, checkMinFeeWaves(reissueA1, params)) - require.NoError(t, checkMinFeeWaves(reissueA2, params)) - require.NoError(t, checkMinFeeWaves(reissueB1, params)) - require.NoError(t, checkMinFeeWaves(reissueB2, params)) + require.NoError(t, checkMinFeeWaves(reissueA1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(reissueA2, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(reissueB1, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(reissueB2, params, false, maxEstimatorVersion)) } func TestSponsorshipFeeReduction(t *testing.T) { @@ -263,11 +263,11 @@ func TestSponsorshipFeeReduction(t *testing.T) { sponsorshipA := createSponsorshipWithProofs(t, 1) sponsorshipB := createSponsorshipWithProofs(t, 1000) - require.Error(t, checkMinFeeWaves(sponsorshipA, params)) - require.NoError(t, checkMinFeeWaves(sponsorshipB, params)) + require.Error(t, checkMinFeeWaves(sponsorshipA, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(sponsorshipB, params, false, maxEstimatorVersion)) storage.activateFeature(t, int16(settings.BlockV5)) - require.NoError(t, checkMinFeeWaves(sponsorshipA, params)) - require.NoError(t, checkMinFeeWaves(sponsorshipB, params)) + require.NoError(t, checkMinFeeWaves(sponsorshipA, params, false, maxEstimatorVersion)) + require.NoError(t, checkMinFeeWaves(sponsorshipB, params, false, maxEstimatorVersion)) } diff --git a/pkg/state/history_storage.go b/pkg/state/history_storage.go index c89a054c6..99e6924d4 100644 --- a/pkg/state/history_storage.go +++ b/pkg/state/history_storage.go @@ -37,6 +37,7 @@ const ( stateHash hitSource feeDistr + accountOriginalEstimatorVersion ) type blockchainEntityProperties struct { @@ -63,8 +64,7 @@ var properties = map[blockchainEntity]blockchainEntityProperties{ lease: { needToFilter: true, needToCut: true, - fixedSize: true, - recordSize: leasingRecordSize + 4, + fixedSize: false, }, wavesBalance: { needToFilter: true, @@ -171,6 +171,11 @@ var properties = map[blockchainEntity]blockchainEntityProperties{ needToCut: true, fixedSize: false, }, + accountOriginalEstimatorVersion: { + needToFilter: true, + needToCut: true, + fixedSize: false, + }, } type historyEntry struct { diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index 7690c75c9..e0289ac1e 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -12,6 +12,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/ride" "github.com/wavesplatform/gowaves/pkg/settings" "github.com/wavesplatform/gowaves/pkg/types" + "go.uber.org/zap" ) type invokeApplier struct { @@ -61,7 +62,7 @@ type payment struct { asset proto.OptionalAsset } -func (ia *invokeApplier) newPaymentFromTransferScriptAction(scriptAddr *proto.Address, action *proto.TransferScriptAction) (*payment, error) { +func (ia *invokeApplier) newPaymentFromTransferScriptAction(senderAddress proto.Address, action *proto.TransferScriptAction) (*payment, error) { if action.Recipient.Address == nil { return nil, errors.New("transfer has unresolved aliases") } @@ -69,14 +70,14 @@ func (ia *invokeApplier) newPaymentFromTransferScriptAction(scriptAddr *proto.Ad return nil, errors.New("negative transfer amount") } return &payment{ - sender: *scriptAddr, + sender: senderAddress, receiver: *action.Recipient.Address, amount: uint64(action.Amount), asset: action.Asset, }, nil } -func (ia *invokeApplier) newTxDiffFromPayment(pmt *payment, updateMinIntermediateBalance bool, _ *fallibleValidationParams) (txDiff, error) { +func (ia *invokeApplier) newTxDiffFromPayment(pmt *payment, updateMinIntermediateBalance bool) (txDiff, error) { diff := newTxDiff() senderKey := byteKey(pmt.sender, pmt.asset.ToID()) senderBalanceDiff := -int64(pmt.amount) @@ -91,19 +92,19 @@ func (ia *invokeApplier) newTxDiffFromPayment(pmt *payment, updateMinIntermediat return diff, nil } -func (ia *invokeApplier) newTxDiffFromScriptTransfer(scriptAddr *proto.Address, action *proto.TransferScriptAction, info *fallibleValidationParams) (txDiff, error) { +func (ia *invokeApplier) newTxDiffFromScriptTransfer(scriptAddr proto.Address, action *proto.TransferScriptAction) (txDiff, error) { pmt, err := ia.newPaymentFromTransferScriptAction(scriptAddr, action) if err != nil { return txDiff{}, err } // updateMinIntermediateBalance is set to false here, because in Scala implementation // only fee and payments are checked for temporary negative balance. - return ia.newTxDiffFromPayment(pmt, false, info) + return ia.newTxDiffFromPayment(pmt, false) } -func (ia *invokeApplier) newTxDiffFromScriptIssue(scriptAddr *proto.Address, action *proto.IssueScriptAction) (txDiff, error) { +func (ia *invokeApplier) newTxDiffFromScriptIssue(senderAddress proto.Address, action *proto.IssueScriptAction) (txDiff, error) { diff := newTxDiff() - senderAssetKey := assetBalanceKey{address: *scriptAddr, asset: action.ID[:]} + senderAssetKey := assetBalanceKey{address: senderAddress, asset: action.ID[:]} senderAssetBalanceDiff := action.Quantity if err := diff.appendBalanceDiff(senderAssetKey.bytes(), newBalanceDiff(senderAssetBalanceDiff, 0, 0, false)); err != nil { return nil, err @@ -111,9 +112,9 @@ func (ia *invokeApplier) newTxDiffFromScriptIssue(scriptAddr *proto.Address, act return diff, nil } -func (ia *invokeApplier) newTxDiffFromScriptReissue(scriptAddr *proto.Address, action *proto.ReissueScriptAction) (txDiff, error) { +func (ia *invokeApplier) newTxDiffFromScriptReissue(senderAddress proto.Address, action *proto.ReissueScriptAction) (txDiff, error) { diff := newTxDiff() - senderAssetKey := assetBalanceKey{address: *scriptAddr, asset: action.AssetID[:]} + senderAssetKey := assetBalanceKey{address: senderAddress, asset: action.AssetID[:]} senderAssetBalanceDiff := action.Quantity if err := diff.appendBalanceDiff(senderAssetKey.bytes(), newBalanceDiff(senderAssetBalanceDiff, 0, 0, false)); err != nil { return nil, err @@ -121,9 +122,9 @@ func (ia *invokeApplier) newTxDiffFromScriptReissue(scriptAddr *proto.Address, a return diff, nil } -func (ia *invokeApplier) newTxDiffFromScriptBurn(scriptAddr *proto.Address, action *proto.BurnScriptAction) (txDiff, error) { +func (ia *invokeApplier) newTxDiffFromScriptBurn(senderAddress proto.Address, action *proto.BurnScriptAction) (txDiff, error) { diff := newTxDiff() - senderAssetKey := assetBalanceKey{address: *scriptAddr, asset: action.AssetID[:]} + senderAssetKey := assetBalanceKey{address: senderAddress, asset: action.AssetID[:]} senderAssetBalanceDiff := -action.Quantity if err := diff.appendBalanceDiff(senderAssetKey.bytes(), newBalanceDiff(senderAssetBalanceDiff, 0, 0, false)); err != nil { return nil, err @@ -131,22 +132,56 @@ func (ia *invokeApplier) newTxDiffFromScriptBurn(scriptAddr *proto.Address, acti return diff, nil } +func (ia *invokeApplier) newTxDiffFromScriptLease(senderAddress, recipientAddress proto.Address, action *proto.LeaseScriptAction) (txDiff, error) { + diff := newTxDiff() + senderKey := wavesBalanceKey{address: senderAddress} + receiverKey := wavesBalanceKey{address: recipientAddress} + if err := diff.appendBalanceDiff(senderKey.bytes(), newBalanceDiff(0, 0, action.Amount, false)); err != nil { + return nil, err + } + if err := diff.appendBalanceDiff(receiverKey.bytes(), newBalanceDiff(0, action.Amount, 0, false)); err != nil { + return nil, err + } + return diff, nil +} + +func (ia *invokeApplier) newTxDiffFromScriptLeaseCancel(senderAddress proto.Address, leaseInfo *leasing) (txDiff, error) { + diff := newTxDiff() + senderKey := wavesBalanceKey{address: senderAddress} + senderLeaseOutDiff := -int64(leaseInfo.Amount) + if err := diff.appendBalanceDiff(senderKey.bytes(), newBalanceDiff(0, 0, senderLeaseOutDiff, false)); err != nil { + return nil, err + } + receiverKey := wavesBalanceKey{address: leaseInfo.Recipient} + receiverLeaseInDiff := -int64(leaseInfo.Amount) + if err := diff.appendBalanceDiff(receiverKey.bytes(), newBalanceDiff(0, receiverLeaseInDiff, 0, false)); err != nil { + return nil, err + } + return diff, nil +} + func (ia *invokeApplier) saveIntermediateDiff(diff txDiff) error { return ia.invokeDiffStor.saveTxDiff(diff) } func (ia *invokeApplier) resolveAliases(actions []proto.ScriptAction, initialisation bool) error { for i, a := range actions { - tr, ok := a.(proto.TransferScriptAction) - if !ok { - continue - } - addr, err := recipientToAddress(tr.Recipient, ia.stor.aliases, !initialisation) - if err != nil { - return err + switch ta := a.(type) { + case proto.TransferScriptAction: + addr, err := recipientToAddress(ta.Recipient, ia.stor.aliases, !initialisation) + if err != nil { + return err + } + ta.Recipient = proto.NewRecipientFromAddress(*addr) + actions[i] = ta + case proto.LeaseScriptAction: + addr, err := recipientToAddress(ta.Recipient, ia.stor.aliases, !initialisation) + if err != nil { + return err + } + ta.Recipient = proto.NewRecipientFromAddress(*addr) + actions[i] = ta } - tr.Recipient = proto.NewRecipientFromAddress(*addr) - actions[i] = tr } return nil } @@ -204,7 +239,7 @@ func (ia *invokeApplier) countActionScriptRuns(actions []proto.ScriptAction, ini return scriptRuns } -func errorForSmartAsset(res ride.RideResult, asset crypto.Digest) error { +func errorForSmartAsset(res ride.Result, asset crypto.Digest) error { var text string if res.UserError() != "" { text = fmt.Sprintf("Transaction is not allowed by token-script id %s: throw from asset script.", asset.String()) @@ -228,10 +263,24 @@ type addlInvokeInfo struct { libVersion byte } +func (ia *invokeApplier) senderCredentialsFromScriptAction(a proto.ScriptAction, info *addlInvokeInfo) (crypto.PublicKey, proto.Address, error) { + senderPK := info.scriptPK + senderAddress := *info.scriptAddr + if a.SenderPK() != nil { + var err error + senderPK = *a.SenderPK() + senderAddress, err = proto.NewAddressFromPublicKey(ia.settings.AddressSchemeCharacter, senderPK) + if err != nil { + return crypto.PublicKey{}, proto.Address{}, err + } + } + return senderPK, senderAddress, nil +} + func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, info *addlInvokeInfo) (proto.TxFailureReason, txBalanceChanges, error) { // Check smart asset scripts on payments. for _, smartAsset := range info.paymentSmartAssets { - r, err := ia.sc.callAssetScript(tx, smartAsset, info.blockInfo, info.initialisation, info.acceptFailed) + r, err := ia.sc.callAssetScript(tx, smartAsset, info.fallibleValidationParams.appendTxParams) if err != nil { return proto.DAppError, info.failedChanges, errors.Errorf("failed to call asset %s script on payment: %v", smartAsset.String(), err) } @@ -246,15 +295,15 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in } // Validate produced actions. var keySizeValidationVersion byte = 1 - if info.libVersion == 4 { + if info.libVersion >= 4 { keySizeValidationVersion = 2 } restrictions := proto.ActionsValidationRestrictions{ DisableSelfTransfers: info.disableSelfTransfers, - ScriptAddress: *info.scriptAddr, KeySizeValidationVersion: keySizeValidationVersion, } - if err := proto.ValidateActions(info.actions, restrictions); err != nil { + + if err := proto.ValidateActions(info.actions, restrictions, int(info.libVersion)); err != nil { return proto.DAppError, info.failedChanges, err } // Check full transaction fee (with actions and payments scripts). @@ -281,34 +330,31 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in } // Perform actions. for _, action := range info.actions { + senderPK, senderAddress, err := ia.senderCredentialsFromScriptAction(action, info) + if err != nil { + return proto.DAppError, info.failedChanges, err + } + totalChanges.appendAddr(senderAddress) switch a := action.(type) { case *proto.DataEntryScriptAction: - // Perform data storage writes. - ia.stor.accountsDataStor.appendEntryUncertain(*info.scriptAddr, a.Entry) + ia.stor.accountsDataStor.appendEntryUncertain(senderAddress, a.Entry) + case *proto.TransferScriptAction: // Perform transfers. - addr := a.Recipient.Address - totalChanges.appendAddr(*addr) + recipientAddress := a.Recipient.Address + totalChanges.appendAddr(*recipientAddress) assetExists := ia.stor.assets.newestAssetExists(a.Asset, !info.initialisation) if !assetExists { return proto.DAppError, info.failedChanges, errors.New("invalid asset in transfer") } isSmartAsset := ia.stor.scriptsStorage.newestIsSmartAsset(a.Asset.ID, !info.initialisation) if isSmartAsset { - sender := tx.ScriptRecipient.Address - if sender == nil { - addr, err := recipientToAddress(tx.ScriptRecipient, ia.stor.aliases, !info.initialisation) - if err != nil { - return proto.DAppError, info.failedChanges, errors.Wrap(err, "fallibleValidation") - } - sender = addr - } - fullTr, err := proto.NewFullScriptTransfer(a, *sender, info.scriptPK, tx) + fullTr, err := proto.NewFullScriptTransfer(a, senderAddress, info.scriptPK, tx) if err != nil { return proto.DAppError, info.failedChanges, errors.Wrap(err, "failed to convert transfer to full script transfer") } // Call asset script if transferring smart asset. - res, err := ia.sc.callAssetScriptWithScriptTransfer(fullTr, a.Asset.ID, info.blockInfo, info.initialisation, info.acceptFailed) + res, err := ia.sc.callAssetScriptWithScriptTransfer(fullTr, a.Asset.ID, info.appendTxParams) if err != nil { return proto.DAppError, info.failedChanges, errors.Wrap(err, "failed to call asset script on transfer set") } @@ -316,7 +362,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.SmartAssetOnActionFailure, info.failedChanges, errorForSmartAsset(res, a.Asset.ID) } } - txDiff, err := ia.newTxDiffFromScriptTransfer(info.scriptAddr, a, info.fallibleValidationParams) + txDiff, err := ia.newTxDiffFromScriptTransfer(senderAddress, a) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -331,11 +377,12 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.DAppError, info.failedChanges, err } } + case *proto.IssueScriptAction: // Create asset's info. assetInfo := &assetInfo{ assetConstInfo: assetConstInfo{ - issuer: info.scriptPK, + issuer: senderPK, decimals: int8(a.Decimals), }, assetChangeableInfo: assetChangeableInfo{ @@ -349,8 +396,8 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in // Currently asset script is always empty. // TODO: if this script is ever set, don't forget to // also save complexity for it here using saveComplexityForAsset(). - ia.stor.scriptsStorage.setAssetScriptUncertain(a.ID, proto.Script{}, info.scriptPK) - txDiff, err := ia.newTxDiffFromScriptIssue(info.scriptAddr, a) + ia.stor.scriptsStorage.setAssetScriptUncertain(a.ID, proto.Script{}, senderPK) + txDiff, err := ia.newTxDiffFromScriptIssue(senderAddress, a) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -365,13 +412,14 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.DAppError, info.failedChanges, err } } + case *proto.ReissueScriptAction: // Check validity of reissue. assetInfo, err := ia.stor.assets.newestAssetInfo(a.AssetID, !info.initialisation) if err != nil { return proto.DAppError, info.failedChanges, err } - if assetInfo.issuer != info.scriptPK { + if assetInfo.issuer != senderPK { return proto.DAppError, info.failedChanges, errs.NewAssetIssuedByOtherAddress("asset was issued by other address") } if !assetInfo.reissuable { @@ -380,7 +428,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in if math.MaxInt64-a.Quantity < assetInfo.quantity.Int64() && info.block.Timestamp >= ia.settings.ReissueBugWindowTimeEnd { return proto.DAppError, info.failedChanges, errors.New("asset total value overflow") } - ok, res, err := ia.validateActionSmartAsset(a.AssetID, a, info.scriptPK, info.blockInfo, *tx.ID, tx.Timestamp, info.initialisation, info.acceptFailed) + ok, res, err := ia.validateActionSmartAsset(a.AssetID, a, senderPK, *tx.ID, tx.Timestamp, info.appendTxParams) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -395,7 +443,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in if err := ia.stor.assets.reissueAssetUncertain(a.AssetID, change, !info.initialisation); err != nil { return proto.DAppError, info.failedChanges, err } - txDiff, err := ia.newTxDiffFromScriptReissue(info.scriptAddr, a) + txDiff, err := ia.newTxDiffFromScriptReissue(senderAddress, a) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -410,6 +458,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.DAppError, info.failedChanges, err } } + case *proto.BurnScriptAction: // Check burn. assetInfo, err := ia.stor.assets.newestAssetInfo(a.AssetID, !info.initialisation) @@ -420,14 +469,14 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in if err != nil { return proto.DAppError, info.failedChanges, err } - if !burnAnyTokensEnabled && assetInfo.issuer != info.scriptPK { + if !burnAnyTokensEnabled && assetInfo.issuer != senderPK { return proto.DAppError, info.failedChanges, errors.New("asset was issued by other address") } quantityDiff := big.NewInt(a.Quantity) if assetInfo.quantity.Cmp(quantityDiff) == -1 { return proto.DAppError, info.failedChanges, errs.NewAccountBalanceError("trying to burn more assets than exist at all") } - ok, res, err := ia.validateActionSmartAsset(a.AssetID, a, info.scriptPK, info.blockInfo, *tx.ID, tx.Timestamp, info.initialisation, info.acceptFailed) + ok, res, err := ia.validateActionSmartAsset(a.AssetID, a, senderPK, *tx.ID, tx.Timestamp, info.appendTxParams) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -442,7 +491,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in if err := ia.stor.assets.burnAssetUncertain(a.AssetID, change, !info.initialisation); err != nil { return proto.DAppError, info.failedChanges, errors.Wrap(err, "failed to burn asset") } - txDiff, err := ia.newTxDiffFromScriptBurn(info.scriptAddr, a) + txDiff, err := ia.newTxDiffFromScriptBurn(senderAddress, a) if err != nil { return proto.DAppError, info.failedChanges, err } @@ -457,6 +506,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.DAppError, info.failedChanges, err } } + case *proto.SponsorshipScriptAction: assetInfo, err := ia.stor.assets.newestAssetInfo(a.AssetID, !info.initialisation) if err != nil { @@ -469,7 +519,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in if !sponsorshipActivated { return proto.DAppError, info.failedChanges, errors.New("sponsorship has not been activated yet") } - if assetInfo.issuer != info.scriptPK { + if assetInfo.issuer != senderPK { return proto.DAppError, info.failedChanges, errors.Errorf("asset %s was not issued by this DApp", a.AssetID.String()) } isSmart := ia.stor.scriptsStorage.newestIsSmartAsset(a.AssetID, !info.initialisation) @@ -477,6 +527,73 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in return proto.DAppError, info.failedChanges, errors.Errorf("can not sponsor smart asset %s", a.AssetID.String()) } ia.stor.sponsoredAssets.sponsorAssetUncertain(a.AssetID, uint64(a.MinFee)) + + case *proto.LeaseScriptAction: + if a.Recipient.Address == nil { + return proto.DAppError, info.failedChanges, errors.New("transfer has unresolved aliases") + } + recipientAddress := *a.Recipient.Address + if senderAddress == recipientAddress { + return proto.DAppError, info.failedChanges, errors.New("leasing to itself is not allowed") + } + if a.Amount <= 0 { + return proto.DAppError, info.failedChanges, errors.New("non-positive leasing amount") + } + totalChanges.appendAddr(recipientAddress) + + // Add new leasing info + l := &leasing{ + OriginTransactionID: tx.ID, + Sender: senderAddress, + Recipient: recipientAddress, + Amount: uint64(a.Amount), + Height: info.blockInfo.Height, + Status: LeaseActive, + RecipientAlias: a.Recipient.Alias, + } + ia.stor.leases.addLeasingUncertain(a.ID, l) + + txDiff, err := ia.newTxDiffFromScriptLease(senderAddress, recipientAddress, a) + if err != nil { + return proto.DAppError, info.failedChanges, err + } + if err := ia.saveIntermediateDiff(txDiff); err != nil { + return proto.DAppError, info.failedChanges, err + } + for key, balanceDiff := range txDiff { + if err := totalChanges.diff.appendBalanceDiffStr(key, balanceDiff); err != nil { + return proto.DAppError, info.failedChanges, err + } + } + + case *proto.LeaseCancelScriptAction: + li, err := ia.stor.leases.newestLeasingInfo(a.LeaseID, !info.initialisation) + if err != nil { + return proto.DAppError, info.failedChanges, err + } + if senderAddress != li.Sender { + return proto.DAppError, info.failedChanges, errors.Errorf("attempt to cancel leasing that was created by other account; leaser '%s'; canceller '%s'; leasing: %s", li.Sender.String(), senderAddress.String(), a.LeaseID.String()) //TODO: Create a scala compatible error in errs package and use it here + } + // Update leasing info + if err := ia.stor.leases.cancelLeasingUncertain(a.LeaseID, info.blockInfo.Height, tx.ID, !info.initialisation); err != nil { + return proto.DAppError, info.failedChanges, errors.Wrap(err, "failed to cancel leasing") + } + + totalChanges.appendAddr(li.Sender) + totalChanges.appendAddr(li.Recipient) + txDiff, err := ia.newTxDiffFromScriptLeaseCancel(senderAddress, li) + if err != nil { + return proto.DAppError, info.failedChanges, err + } + if err := ia.saveIntermediateDiff(txDiff); err != nil { + return proto.DAppError, info.failedChanges, err + } + for key, balanceDiff := range txDiff { + if err := totalChanges.diff.appendBalanceDiffStr(key, balanceDiff); err != nil { + return proto.DAppError, info.failedChanges, err + } + } + default: return proto.DAppError, info.failedChanges, errors.Errorf("unsupported script action '%T'", a) } @@ -508,7 +625,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf info.acceptFailed = info.blockV5Activated && info.acceptFailed // Check sender script, if any. if info.senderScripted { - if err := ia.sc.callAccountScriptWithTx(tx, info.blockInfo, info.initialisation); err != nil { + if err := ia.sc.callAccountScriptWithTx(tx, info.appendTxParams); err != nil { // Never accept invokes with failed script on transaction sender. return nil, err } @@ -526,13 +643,13 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf if err != nil { return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) } - scriptPK, err := ia.stor.scriptsStorage.newestScriptPKByAddr(*scriptAddr, !info.initialisation) + scriptPK, err := ia.stor.scriptsStorage.NewestScriptPKByAddr(*scriptAddr, !info.initialisation) if err != nil { return nil, errors.Wrapf(err, "failed to get script's public key on address '%s'", scriptAddr.String()) } // Check that the script's library supports multiple payments. // We don't have to check feature activation because we done it before. - if len(tx.Payments) == 2 && tree.LibVersion < 4 { + if len(tx.Payments) >= 2 && tree.LibVersion < 4 { return nil, errors.Errorf("multiple payments is not allowed for RIDE library version %d", tree.LibVersion) } // Refuse payments to DApp itself since activation of BlockV5 (acceptFailed) and for DApps with StdLib V4. @@ -554,7 +671,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf return nil, err } // Call script function. - ok, scriptActions, err := ia.sc.invokeFunction(tree, tx, info.blockInfo, *scriptAddr, info.initialisation) + ok, scriptActions, err := ia.sc.invokeFunction(tree, tx, info, *scriptAddr) if !ok { // When ok is false, it means that we could not even start invocation. // We just return error in such case. @@ -568,10 +685,25 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), actions: scriptActions, changes: failedChanges} return ia.handleInvocationResult(tx, info, res) } - actionScriptRuns := ia.countActionScriptRuns(scriptActions, info.initialisation) - scriptRuns := uint64(len(paymentSmartAssets)) + actionScriptRuns + var scriptRuns uint64 = 0 + // After activation of RideV5 (16) feature we don't take extra fee for execution of smart asset scripts. + if !info.rideV5Activated { + actionScriptRuns := ia.countActionScriptRuns(scriptActions, info.initialisation) + scriptRuns += uint64(len(paymentSmartAssets)) + actionScriptRuns + } if info.senderScripted { - scriptRuns += 1 + // Since activation of RideV5 (16) feature we don't take fee for verifier execution if it's complexity is less than `FreeVerifierComplexity` limit + if info.rideV5Activated { + treeEstimation, err := ia.stor.scriptsComplexity.newestScriptComplexityByAddr(*scriptAddr, info.checkerInfo.estimatorVersion(), !info.initialisation) + if err != nil { + return nil, errors.Wrap(err, "invoke failed to get verifier complexity") + } + if treeEstimation.Verifier > FreeVerifierComplexity { + scriptRuns++ + } + } else { + scriptRuns++ + } } var res *invocationResult code, changes, err := ia.fallibleValidation(tx, &addlInvokeInfo{ @@ -586,6 +718,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf libVersion: byte(tree.LibVersion), }) if err != nil { + zap.S().Debugf("fallibleValidation error in tx %s. Error: %s", tx.ID.String(), err.Error()) // If fallibleValidation fails, we should save transaction to blockchain when acceptFailed is true. if !info.acceptFailed { return nil, err @@ -673,8 +806,8 @@ func (ia *invokeApplier) checkFullFee(tx *proto.InvokeScriptWithProofs, scriptRu } func (ia *invokeApplier) validateActionSmartAsset(asset crypto.Digest, action proto.ScriptAction, callerPK crypto.PublicKey, - blockInfo *proto.BlockInfo, txID crypto.Digest, txTimestamp uint64, initialisation, acceptFailed bool) (bool, ride.RideResult, error) { - isSmartAsset := ia.stor.scriptsStorage.newestIsSmartAsset(asset, !initialisation) + txID crypto.Digest, txTimestamp uint64, params *appendTxParams) (bool, ride.Result, error) { + isSmartAsset := ia.stor.scriptsStorage.newestIsSmartAsset(asset, !params.initialisation) if !isSmartAsset { return true, nil, nil } @@ -686,7 +819,7 @@ func (ia *invokeApplier) validateActionSmartAsset(asset crypto.Digest, action pr if err != nil { return false, nil, err } - res, err := ia.sc.callAssetScriptCommon(env, asset, blockInfo, initialisation, acceptFailed) + res, err := ia.sc.callAssetScriptCommon(env, asset, params) if err != nil { return false, nil, err } diff --git a/pkg/state/invoke_applier_test.go b/pkg/state/invoke_applier_test.go index 2ac712466..f800a3083 100644 --- a/pkg/state/invoke_applier_test.go +++ b/pkg/state/invoke_applier_test.go @@ -141,6 +141,13 @@ type rcpKey struct { key string } +type fullBalance struct { + regular uint64 + generating uint64 + available uint64 + effective uint64 +} + type invokeApplierTestData struct { // Indicates that invocation should happen multiple times. invokeMultipleTimes bool @@ -156,9 +163,10 @@ type invokeApplierTestData struct { failRes bool // Result state. - correctBalances map[rcpAsset]uint64 - dataEntries map[rcpKey]proto.DataEntry - correctAddrs []proto.Address + correctBalances map[rcpAsset]uint64 + correctFullBalances map[proto.Recipient]fullBalance + dataEntries map[rcpKey]proto.DataEntry + correctAddrs []proto.Address } func (id *invokeApplierTestData) applyTest(t *testing.T, to *invokeApplierTestObjects, info *fallibleValidationParams) { @@ -181,7 +189,15 @@ func (id *invokeApplierTestData) applyTest(t *testing.T, to *invokeApplierTestOb for aa, correct := range id.correctBalances { balance, err := to.state.NewestAccountBalance(aa.rcp, aa.asset()) assert.NoError(t, err) - assert.Equal(t, correct, balance) + assert.Equal(t, int(correct), int(balance)) + } + for aa, correct := range id.correctFullBalances { + fb, err := to.state.NewestFullWavesBalance(aa) + assert.NoError(t, err) + assert.Equal(t, int(correct.available), int(fb.Available)) + assert.Equal(t, int(correct.effective), int(fb.Effective)) + assert.Equal(t, int(correct.generating), int(fb.Generating)) + assert.Equal(t, int(correct.regular), int(fb.Regular)) } for ak, correct := range id.dataEntries { entry, err := to.state.RetrieveNewestEntry(ak.rcp, ak.key) @@ -200,8 +216,16 @@ func (id *invokeApplierTestData) applyTest(t *testing.T, to *invokeApplierTestOb for aa, correct := range id.correctBalances { balance, err := to.state.AccountBalance(aa.rcp, aa.asset()) assert.NoError(t, err) - assert.Equal(t, correct, balance) + assert.Equal(t, int(correct), int(balance)) } + //for aa, correct := range id.correctFullBalances { + // fb, err := to.state.FullWavesBalance(aa) + // assert.NoError(t, err) + // assert.Equal(t, correct.available, fb.Available) + // assert.Equal(t, correct.effective, fb.Effective) + // assert.Equal(t, correct.generating, fb.Generating) + // assert.Equal(t, correct.regular, fb.Regular) + //} for ak, correct := range id.dataEntries { entry, err := to.state.RetrieveEntry(ak.rcp, ak.key) assert.NoError(t, err) @@ -702,6 +726,173 @@ func TestFailedApplyInvokeScript(t *testing.T) { } } +// Tests on leasing actions use the following script +/* +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +@Callable(i) +func simpleLeaseToAddress(rcp: String, amount: Int) = { + let addr = addressFromStringValue(rcp) + ([Lease(addr, amount)], unit) +} + +@Callable(i) +func detailedLeaseToAddress(rcp: String, amount: Int) = { + let addr = addressFromStringValue(rcp) + let lease = Lease(addr, amount, 0) + let id = calculateLeaseId(lease) + ([lease], id) +} + +@Callable(i) +func simpleLeaseToAlias(rcp: String, amount: Int) = { + let alias = Alias(rcp) + ([Lease(alias, amount)], unit) +} + +@Callable(i) +func detailedLeaseToAlias(rcp: String, amount: Int) = { + let alias = Alias(rcp) + let lease = Lease(alias, amount, 0) + let id = calculateLeaseId(lease) + ([lease], id) +} + +@Callable(i) +func simpleLeaseToSender(amount: Int) = { + ([Lease(i.caller, amount)], unit) +} + +@Callable(i) +func detailedLeaseToSender(amount: Int) = { + let lease = Lease(i.caller, amount, 0) + let id = calculateLeaseId(lease) + ([lease], id) +} + +@Callable(i) +func cancel(id: ByteVector) = ([LeaseCancel(id)], unit) + +*/ + +func TestApplyInvokeScriptWithLease(t *testing.T) { + to, path := createInvokeApplierTestObjects(t) + to.activateFeature(t, int16(settings.RideV5)) + + defer func() { + err := to.state.Close() + require.NoError(t, err, "state.Close() failed") + err = os.RemoveAll(path) + require.NoError(t, err, "failed to remove test data dir") + }() + + info := to.fallibleValidationParams(t) + to.setDApp(t, "ride5_leasing.base64", testGlobal.recipientInfo) + + var thousandWaves int64 = 1_000 * 100_000_000 + // Invoker pays only fee, but receives a leasing of 1000 waves + to.setAndCheckInitialWavesBalance(t, testGlobal.senderInfo.addr, invokeFee) + to.setAndCheckInitialWavesBalance(t, testGlobal.recipientInfo.addr, uint64(2*thousandWaves)) + + sender, dapp := invokeSenderRecipient() + fc := proto.FunctionCall{ + Name: "simpleLeaseToSender", + Arguments: []proto.Argument{&proto.IntegerArgument{Value: thousandWaves}}, + } + tests := []invokeApplierTestData{ + { + payments: []proto.ScriptPayment{}, + fc: fc, + errorRes: false, + failRes: false, + correctBalances: map[rcpAsset]uint64{ + {sender, nil}: 0, + }, + correctFullBalances: map[proto.Recipient]fullBalance{ + sender: {regular: 0, generating: 0, available: 0, effective: uint64(thousandWaves)}, + dapp: {regular: uint64(2 * thousandWaves), generating: 0, available: uint64(thousandWaves), effective: uint64(thousandWaves)}, + }, + correctAddrs: []proto.Address{ + testGlobal.senderInfo.addr, testGlobal.recipientInfo.addr, + }, + }, + } + for _, tc := range tests { + tc.applyTest(t, to, info) + } +} + +func TestApplyInvokeScriptWithLeaseAndLeaseCancel(t *testing.T) { + to, path := createInvokeApplierTestObjects(t) + to.activateFeature(t, int16(settings.RideV5)) + + defer func() { + err := to.state.Close() + require.NoError(t, err, "state.Close() failed") + err = os.RemoveAll(path) + require.NoError(t, err, "failed to remove test data dir") + }() + + info := to.fallibleValidationParams(t) + to.setDApp(t, "ride5_leasing.base64", testGlobal.recipientInfo) + + var thousandWaves int64 = 1_000 * 100_000_000 + // Invoker pays only fee, but receives a leasing of 1000 waves + to.setAndCheckInitialWavesBalance(t, testGlobal.senderInfo.addr, 2*invokeFee) + to.setAndCheckInitialWavesBalance(t, testGlobal.recipientInfo.addr, uint64(2*thousandWaves)) + + sender, dapp := invokeSenderRecipient() + fc1 := proto.FunctionCall{ + Name: "simpleLeaseToSender", + Arguments: []proto.Argument{&proto.IntegerArgument{Value: thousandWaves}}, + } + tx := createInvokeScriptWithProofs(t, []proto.ScriptPayment{}, fc1, feeAsset, invokeFee) + id := proto.GenerateLeaseScriptActionID(sender, thousandWaves, 0, *tx.ID) + fc2 := proto.FunctionCall{ + Name: "cancel", + Arguments: []proto.Argument{&proto.BinaryArgument{Value: id.Bytes()}}, + } + tests := []invokeApplierTestData{ + { + payments: []proto.ScriptPayment{}, + fc: fc1, + errorRes: false, + failRes: false, + correctBalances: map[rcpAsset]uint64{ + {sender, nil}: invokeFee, + }, + correctFullBalances: map[proto.Recipient]fullBalance{ + sender: {regular: invokeFee, generating: 0, available: invokeFee, effective: uint64(thousandWaves) + invokeFee}, + dapp: {regular: uint64(2 * thousandWaves), generating: 0, available: uint64(thousandWaves), effective: uint64(thousandWaves)}, + }, + correctAddrs: []proto.Address{ + testGlobal.senderInfo.addr, testGlobal.recipientInfo.addr, + }, + }, + { + payments: []proto.ScriptPayment{}, + fc: fc2, + errorRes: false, + failRes: false, + correctBalances: map[rcpAsset]uint64{ + {sender, nil}: 0, + }, + correctFullBalances: map[proto.Recipient]fullBalance{ + sender: {regular: 0, generating: 0, available: 0, effective: 0}, + dapp: {regular: uint64(2 * thousandWaves), generating: 0, available: uint64(2 * thousandWaves), effective: uint64(2 * thousandWaves)}, + }, + correctAddrs: []proto.Address{ + testGlobal.senderInfo.addr, testGlobal.recipientInfo.addr, + }, + }, + } + for _, tc := range tests { + tc.applyTest(t, to, info) + } +} + // TODO: add test on sponsorship made by DApp: create new DApp that will issue and sponsor asset, // test also the function call that issues and sets sponsorship in one turn. diff --git a/pkg/state/invoke_results_test.go b/pkg/state/invoke_results_test.go index f616b6b2c..2a51bdea1 100644 --- a/pkg/state/invoke_results_test.go +++ b/pkg/state/invoke_results_test.go @@ -93,6 +93,14 @@ func TestSaveResult(t *testing.T) { {AssetID: testGlobal.asset0.asset.ID, MinFee: 12345}, {AssetID: testGlobal.asset0.asset.ID, MinFee: 0}, }, + Leases: []*proto.LeaseScriptAction{ + {ID: testGlobal.asset0.asset.ID, Recipient: rcp, Amount: 100500, Nonce: 10}, + {ID: testGlobal.asset1.asset.ID, Recipient: rcp, Amount: 12345, Nonce: 67890}, + }, + LeaseCancels: []*proto.LeaseCancelScriptAction{ + {LeaseID: invokeID}, + {LeaseID: testGlobal.asset0.asset.ID}, + }, } err = to.invokeResults.saveResult(invokeID, savedRes, blockID0) require.NoError(t, err) diff --git a/pkg/state/keys.go b/pkg/state/keys.go index d74c7071e..5e4d36de9 100644 --- a/pkg/state/keys.go +++ b/pkg/state/keys.go @@ -58,9 +58,6 @@ const ( // Leases. leaseKeyPrefix - // Known peers. - knownPeersPrefix - // Aliases. aliasKeyPrefix disabledAliasKeyPrefix @@ -91,6 +88,7 @@ const ( assetScriptKeyPrefix accountScriptComplexityKeyPrefix assetScriptComplexityKeyPrefix + accountOriginalEstimatorVersionKeyPrefix // Block Reward. blockRewardKeyPrefix @@ -108,7 +106,7 @@ const ( stateInfoKeyPrefix // Size of TransactionsByAddresses file. - txsByAddrsFileSizeKeyPrefix + txsByAddressesFileSizeKeyPrefix // Stores protobuf-related info for blockReadWriter. rwProtobufInfoKeyPrefix @@ -171,6 +169,8 @@ func prefixByEntity(entity blockchainEntity) ([]byte, error) { return []byte{hitSourceKeyPrefix}, nil case feeDistr: return []byte{blocksInfoKeyPrefix}, nil + case accountOriginalEstimatorVersion: + return []byte{accountOriginalEstimatorVersionKeyPrefix}, nil default: return nil, errors.New("bad entity type") } @@ -390,6 +390,21 @@ func (k *disabledAliasKey) bytes() []byte { return buf } +func (k *disabledAliasKey) unmarshal(data []byte) error { + if len(data) != disabledAliasKeySize { + return errInvalidDataSize + } + if data[0] != disabledAliasKeyPrefix { + return errInvalidPrefix + } + var err error + k.alias, err = proto.StringWithUInt16Len(data[1:]) + if err != nil { + return errors.Wrap(err, "StringWithUInt16Len() failed") + } + return nil +} + type activatedFeaturesKey struct { featureID int16 } @@ -580,15 +595,24 @@ func (k *accountScriptComplexityKey) bytes() []byte { } type assetScriptComplexityKey struct { - ver int asset crypto.Digest } func (k *assetScriptComplexityKey) bytes() []byte { - buf := make([]byte, 2+crypto.DigestSize) + buf := make([]byte, 1+crypto.DigestSize) buf[0] = assetScriptComplexityKeyPrefix - buf[1] = byte(k.ver) - copy(buf[2:], k.asset[:]) + copy(buf[1:], k.asset[:]) + return buf +} + +type accountOriginalEstimatorVersionKey struct { + addr proto.Address +} + +func (k *accountOriginalEstimatorVersionKey) bytes() []byte { + buf := make([]byte, 1+proto.AddressSize) + buf[0] = accountOriginalEstimatorVersionKeyPrefix + copy(buf[1:], k.addr[:]) return buf } diff --git a/pkg/state/known_peer.go b/pkg/state/known_peer.go deleted file mode 100644 index 4f9461bde..000000000 --- a/pkg/state/known_peer.go +++ /dev/null @@ -1,25 +0,0 @@ -package state - -import ( - "github.com/pkg/errors" - "github.com/wavesplatform/gowaves/pkg/proto" -) - -const KnownPeerKeyLength = proto.IpPortLength + 1 - -func intoBytes(p proto.TCPAddr) []byte { - out := make([]byte, KnownPeerKeyLength) - out[0] = knownPeersPrefix - ipPort := p.ToIpPort() - copy(out[1:], ipPort[:]) - return out -} - -func fromBytes(b []byte) (proto.TCPAddr, error) { - i := proto.IpPort{} - if len(b) < KnownPeerKeyLength { - return i.ToTcpAddr(), errors.Errorf("not enough bytes to decode to KnownPeerKey") - } - copy(i[:], b[1:]) - return i.ToTcpAddr(), nil -} diff --git a/pkg/state/known_peer_test.go b/pkg/state/known_peer_test.go deleted file mode 100644 index 47e5d2469..000000000 --- a/pkg/state/known_peer_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package state - -import ( - "github.com/stretchr/testify/require" - "github.com/wavesplatform/gowaves/pkg/proto" - "net" - "testing" -) - -func TestKnownPeer(t *testing.T) { - p := proto.NewTCPAddr(net.IPv4(127, 0, 0, 1), 65535) - k := intoBytes(p) - p2, _ := fromBytes(k) - require.Equal(t, p, p2) -} diff --git a/pkg/state/leases.go b/pkg/state/leases.go index e4413e2a5..faaf46528 100644 --- a/pkg/state/leases.go +++ b/pkg/state/leases.go @@ -2,9 +2,9 @@ package state import ( "bytes" - "encoding/binary" "io" + "github.com/fxamacker/cbor/v2" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/keyvalue" @@ -12,8 +12,12 @@ import ( "go.uber.org/zap" ) +type LeaseStatus byte + const ( - leasingRecordSize = 1 + 8 + proto.AddressSize*2 + LeaseActive LeaseStatus = iota + LeaseCanceled + LeaseExpired ) type leaseRecordForStateHashes struct { @@ -37,49 +41,37 @@ func (lr *leaseRecordForStateHashes) less(other stateComponent) bool { } type leasing struct { - isActive bool - leaseAmount uint64 - recipient proto.Address - sender proto.Address -} - -type leasingRecord struct { - leasing + Sender proto.Address `cbor:"0,keyasint"` + Recipient proto.Address `cbor:"1,keyasint"` + Amount uint64 `cbor:"2,keyasint"` + Height uint64 `cbor:"3,keyasint"` + Status LeaseStatus `cbor:"4,keyasint"` + OriginTransactionID *crypto.Digest `cbor:"5,keyasint,omitempty"` + RecipientAlias *proto.Alias `cbor:"6,keyasint,omitempty"` + CancelHeight uint64 `cbor:"7,keyasint,omitempty"` + CancelTransactionID *crypto.Digest `cbor:"8,keyasint,omitempty"` } -func (l *leasingRecord) marshalBinary() ([]byte, error) { - res := make([]byte, leasingRecordSize) - proto.PutBool(res[0:1], l.isActive) - binary.BigEndian.PutUint64(res[1:9], l.leaseAmount) - copy(res[9:9+proto.AddressSize], l.recipient[:]) - copy(res[9+proto.AddressSize:9+proto.AddressSize*2], l.sender[:]) - return res, nil -} - -func (l *leasingRecord) unmarshalBinary(data []byte) error { - if len(data) != leasingRecordSize { - return errInvalidDataSize - } - var err error - l.isActive, err = proto.Bool(data[0:1]) - if err != nil { - return err - } - l.leaseAmount = binary.BigEndian.Uint64(data[1:9]) - copy(l.recipient[:], data[9:9+proto.AddressSize]) - copy(l.sender[:], data[9+proto.AddressSize:9+proto.AddressSize*2]) - return nil +func (l leasing) isActive() bool { + return l.Status == LeaseActive } type leases struct { hs *historyStorage + uncertainLeases map[crypto.Digest]*leasing + calculateHashes bool hasher *stateHasher } func newLeases(hs *historyStorage, calcHashes bool) *leases { - return &leases{hs: hs, calculateHashes: calcHashes, hasher: newStateHasher()} + return &leases{ + hs: hs, + uncertainLeases: make(map[crypto.Digest]*leasing), + calculateHashes: calcHashes, + hasher: newStateHasher(), + } } func (l *leases) cancelLeases(bySenders map[proto.Address]struct{}, blockID proto.BlockID) error { @@ -99,24 +91,24 @@ func (l *leases) cancelLeases(bySenders map[proto.Address]struct{}, blockID prot for leaseIter.Next() { key := keyvalue.SafeKey(leaseIter) leaseBytes := keyvalue.SafeValue(leaseIter) - var leaseRecord leasingRecord - if err := leaseRecord.unmarshalBinary(leaseBytes); err != nil { - return errors.Errorf("failed to unmarshal lease: %v", err) + record := new(leasing) + if err := cbor.Unmarshal(leaseBytes, record); err != nil { + return errors.Wrap(err, "failed to unmarshal lease") } toCancel := true if bySenders != nil { - _, toCancel = bySenders[leaseRecord.sender] + _, toCancel = bySenders[record.Sender] } - if leaseRecord.isActive && toCancel { + if record.isActive() && toCancel { // Cancel lease. var k leaseKey if err := k.unmarshal(key); err != nil { - return errors.Errorf("failed to unmarshal lease key: %v", err) + return errors.Wrap(err, "failed to unmarshal lease key") } zap.S().Infof("State: cancelling lease %s", k.leaseID.String()) - leaseRecord.isActive = false - if err := l.addLeasing(k.leaseID, &leaseRecord.leasing, blockID); err != nil { - return errors.Errorf("failed to save lease to storage: %v", err) + record.Status = LeaseCanceled + if err := l.addLeasing(k.leaseID, record, blockID); err != nil { + return errors.Wrap(err, "failed to save lease to storage") } } } @@ -124,6 +116,45 @@ func (l *leases) cancelLeases(bySenders map[proto.Address]struct{}, blockID prot return nil } +func (l *leases) cancelLeasesToAliases(aliases map[string]struct{}, blockID proto.BlockID) error { + leaseIter, err := l.hs.newNewestTopEntryIterator(lease, true) + if err != nil { + return errors.Wrap(err, "failed to create key iterator to cancel leases to stolen aliases") + } + defer func() { + leaseIter.Release() + if err := leaseIter.Error(); err != nil { + zap.S().Fatalf("Iterator error: %v", err) + } + }() + + // Iterate all the leases. + zap.S().Info("Started collecting leases") + for leaseIter.Next() { + keyBytes := keyvalue.SafeKey(leaseIter) + var key leaseKey + if err := key.unmarshal(keyBytes); err != nil { + return errors.Wrap(err, "failed ot unmarshal leasing key") + } + leaseBytes := keyvalue.SafeValue(leaseIter) + record := new(leasing) + if err := cbor.Unmarshal(leaseBytes, record); err != nil { + return errors.Wrap(err, "failed to unmarshal lease") + } + if record.isActive() && record.RecipientAlias != nil { + if _, ok := aliases[record.RecipientAlias.Alias]; ok { + zap.S().Infof("State: canceling lease %s", key.leaseID.String()) + record.Status = LeaseCanceled + if err := l.addLeasing(key.leaseID, record, blockID); err != nil { + return errors.Wrap(err, "failed to save lease to storage") + } + } + } + } + zap.S().Info("Finished collecting leases") + return nil +} + func (l *leases) validLeaseIns() (map[proto.Address]int64, error) { leaseIter, err := l.hs.newNewestTopEntryIterator(lease, true) if err != nil { @@ -141,12 +172,12 @@ func (l *leases) validLeaseIns() (map[proto.Address]int64, error) { zap.S().Info("Started collecting leases") for leaseIter.Next() { leaseBytes := keyvalue.SafeValue(leaseIter) - var lease leasingRecord - if err := lease.unmarshalBinary(leaseBytes); err != nil { - return nil, errors.Errorf("failed to unmarshal lease: %v", err) + record := new(leasing) + if err := cbor.Unmarshal(leaseBytes, record); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal lease") } - if lease.isActive { - leaseIns[lease.recipient] += int64(lease.leaseAmount) + if record.isActive() { + leaseIns[record.Recipient] += int64(record.Amount) } } zap.S().Info("Finished collecting leases") @@ -155,16 +186,23 @@ func (l *leases) validLeaseIns() (map[proto.Address]int64, error) { // Leasing info from DB or local storage. func (l *leases) newestLeasingInfo(id crypto.Digest, filter bool) (*leasing, error) { + if leasing, ok := l.uncertainLeases[id]; ok { + return leasing, nil + } + key := leaseKey{leaseID: id} recordBytes, err := l.hs.newestTopEntryData(key.bytes(), filter) if err != nil { return nil, err } - var record leasingRecord - if err := record.unmarshalBinary(recordBytes); err != nil { - return nil, errors.Errorf("failed to unmarshal record: %v", err) + record := new(leasing) + if err := cbor.Unmarshal(recordBytes, record); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal record") } - return &record.leasing, nil + if record.OriginTransactionID == nil { + record.OriginTransactionID = &id + } + return record, nil } // Stable leasing info from DB. @@ -174,11 +212,14 @@ func (l *leases) leasingInfo(id crypto.Digest, filter bool) (*leasing, error) { if err != nil { return nil, err } - var record leasingRecord - if err := record.unmarshalBinary(recordBytes); err != nil { - return nil, errors.Errorf("failed to unmarshal record: %v", err) + record := new(leasing) + if err := cbor.Unmarshal(recordBytes, record); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal record") + } + if record.OriginTransactionID == nil { + record.OriginTransactionID = &id } - return &record.leasing, nil + return record, nil } func (l *leases) isActive(id crypto.Digest, filter bool) (bool, error) { @@ -186,21 +227,20 @@ func (l *leases) isActive(id crypto.Digest, filter bool) (bool, error) { if err != nil { return false, err } - return info.isActive, nil + return info.isActive(), nil } func (l *leases) addLeasing(id crypto.Digest, leasing *leasing, blockID proto.BlockID) error { key := leaseKey{leaseID: id} keyBytes := key.bytes() keyStr := string(keyBytes) - r := &leasingRecord{*leasing} - recordBytes, err := r.marshalBinary() + recordBytes, err := cbor.Marshal(leasing) if err != nil { - return errors.Errorf("failed to marshal record: %v", err) + return errors.Wrap(err, "failed to marshal record") } if l.calculateHashes { active := byte(0) - if leasing.isActive { + if leasing.isActive() { active = byte(1) } lr := &leaseRecordForStateHashes{ @@ -217,15 +257,33 @@ func (l *leases) addLeasing(id crypto.Digest, leasing *leasing, blockID proto.Bl return nil } -func (l *leases) cancelLeasing(id crypto.Digest, blockID proto.BlockID, filter bool) error { +func (l *leases) addLeasingUncertain(id crypto.Digest, leasing *leasing) { + l.uncertainLeases[id] = leasing +} + +func (l *leases) cancelLeasing(id crypto.Digest, blockID proto.BlockID, height uint64, txID *crypto.Digest, filter bool) error { leasing, err := l.newestLeasingInfo(id, filter) if err != nil { return errors.Errorf("failed to get leasing info: %v", err) } - leasing.isActive = false + leasing.Status = LeaseCanceled + leasing.CancelHeight = height + leasing.CancelTransactionID = txID return l.addLeasing(id, leasing, blockID) } +func (l *leases) cancelLeasingUncertain(id crypto.Digest, height uint64, txID *crypto.Digest, filter bool) error { + leasing, err := l.newestLeasingInfo(id, filter) + if err != nil { + return errors.Errorf("failed to get leasing info: %v", err) + } + leasing.Status = LeaseCanceled + leasing.CancelTransactionID = txID + leasing.CancelHeight = height + l.addLeasingUncertain(id, leasing) + return nil +} + func (l *leases) prepareHashes() error { return l.hasher.stop() } @@ -233,3 +291,16 @@ func (l *leases) prepareHashes() error { func (l *leases) reset() { l.hasher.reset() } + +func (l *leases) commitUncertain(blockID proto.BlockID) error { + for id, leasing := range l.uncertainLeases { + if err := l.addLeasing(id, leasing, blockID); err != nil { + return err + } + } + return nil +} + +func (l *leases) dropUncertain() { + l.uncertainLeases = make(map[crypto.Digest]*leasing) +} diff --git a/pkg/state/leases_test.go b/pkg/state/leases_test.go index 63e0a251f..f890f3dc2 100644 --- a/pkg/state/leases_test.go +++ b/pkg/state/leases_test.go @@ -24,16 +24,17 @@ func createLeases() (*leasesTestObjects, []string, error) { return &leasesTestObjects{stor, leases}, path, nil } -func createLease(t *testing.T, sender string) *leasing { +func createLease(t *testing.T, sender string, id crypto.Digest) *leasing { senderAddr, err := proto.NewAddressFromString(sender) assert.NoError(t, err, "failed to create address from string") recipientAddr, err := proto.NewAddressFromString("3PDdGex1meSUf4Yq5bjPBpyAbx6us9PaLfo") assert.NoError(t, err, "failed to create address from string") return &leasing{ - isActive: true, - leaseAmount: 10, - recipient: recipientAddr, - sender: senderAddr, + OriginTransactionID: &id, + Recipient: recipientAddr, + Sender: senderAddr, + Amount: 10, + Status: LeaseActive, } } @@ -59,7 +60,7 @@ func TestCancelLeases(t *testing.T) { for _, l := range leasings { leaseID, err := crypto.NewDigestFromBytes(bytes.Repeat([]byte{l.leaseIDByte}, crypto.DigestSize)) assert.NoError(t, err, "failed to create digest from bytes") - r := createLease(t, l.sender) + r := createLease(t, l.sender, leaseID) err = to.leases.addLeasing(leaseID, r, blockID0) assert.NoError(t, err, "failed to add leasing") } @@ -82,10 +83,10 @@ func TestCancelLeases(t *testing.T) { assert.NoError(t, err) if l.sender == badSenderStr { assert.Equal(t, false, active) - assert.Equal(t, leasing.isActive, false, "did not cancel leasing by sender") + assert.Equal(t, leasing.isActive(), false, "did not cancel leasing by sender") } else { assert.Equal(t, true, active) - assert.Equal(t, leasing.isActive, true, "cancelled leasing with different sender") + assert.Equal(t, leasing.isActive(), true, "cancelled leasing with different sender") } } // Cancel all the leases and check. @@ -97,7 +98,7 @@ func TestCancelLeases(t *testing.T) { assert.NoError(t, err, "failed to create digest from bytes") leasing, err := to.leases.leasingInfo(leaseID, true) assert.NoError(t, err, "failed to get leasing") - assert.Equal(t, leasing.isActive, false, "did not cancel all the leasings") + assert.Equal(t, leasing.isActive(), false, "did not cancel all the leasings") active, err := to.leases.isActive(leaseID, true) assert.NoError(t, err) assert.Equal(t, false, active) @@ -127,10 +128,10 @@ func TestValidLeaseIns(t *testing.T) { for _, l := range leasings { leaseID, err := crypto.NewDigestFromBytes(bytes.Repeat([]byte{l.leaseIDByte}, crypto.DigestSize)) assert.NoError(t, err, "failed to create digest from bytes") - r := createLease(t, l.sender) + r := createLease(t, l.sender, leaseID) err = to.leases.addLeasing(leaseID, r, blockID0) assert.NoError(t, err, "failed to add leasing") - properLeaseIns[r.recipient] += int64(r.leaseAmount) + properLeaseIns[r.Recipient] += int64(r.Amount) } leaseIns, err := to.leases.validLeaseIns() assert.NoError(t, err, "validLeaseIns() failed") @@ -156,7 +157,7 @@ func TestAddLeasing(t *testing.T) { leaseID, err := crypto.NewDigestFromBytes(bytes.Repeat([]byte{0xff}, crypto.DigestSize)) assert.NoError(t, err, "failed to create digest from bytes") senderStr := "3PNXHYoWp83VaWudq9ds9LpS5xykWuJHiHp" - r := createLease(t, senderStr) + r := createLease(t, senderStr, leaseID) err = to.leases.addLeasing(leaseID, r, blockID0) assert.NoError(t, err, "failed to add leasing") l, err := to.leases.newestLeasingInfo(leaseID, true) @@ -182,15 +183,19 @@ func TestCancelLeasing(t *testing.T) { to.stor.addBlock(t, blockID0) leaseID, err := crypto.NewDigestFromBytes(bytes.Repeat([]byte{0xff}, crypto.DigestSize)) assert.NoError(t, err, "failed to create digest from bytes") + txID, err := crypto.NewDigestFromBytes(bytes.Repeat([]byte{0xfe}, crypto.DigestSize)) + assert.NoError(t, err, "failed to create digest from bytes") senderStr := "3PNXHYoWp83VaWudq9ds9LpS5xykWuJHiHp" - r := createLease(t, senderStr) + r := createLease(t, senderStr, leaseID) err = to.leases.addLeasing(leaseID, r, blockID0) assert.NoError(t, err, "failed to add leasing") - err = to.leases.cancelLeasing(leaseID, blockID0, true) + err = to.leases.cancelLeasing(leaseID, blockID0, to.stor.rw.height, &txID, true) assert.NoError(t, err, "failed to cancel leasing") - r.isActive = false + r.Status = LeaseCanceled + r.CancelHeight = 1 + r.CancelTransactionID = &txID to.stor.flush(t) resLeasing, err := to.leases.leasingInfo(leaseID, true) assert.NoError(t, err, "failed to get leasing info") - assert.Equal(t, resLeasing, r, "invalid leasing record after cancelation") + assert.Equal(t, resLeasing, r, "invalid leasing record after cancellation") } diff --git a/pkg/state/peer_storage.go b/pkg/state/peer_storage.go deleted file mode 100644 index e64e13be4..000000000 --- a/pkg/state/peer_storage.go +++ /dev/null @@ -1,60 +0,0 @@ -package state - -import ( - "github.com/wavesplatform/gowaves/pkg/keyvalue" - "github.com/wavesplatform/gowaves/pkg/proto" -) - -type peerStorage struct { - db keyvalue.IterableKeyVal -} - -func newPeerStorage(db keyvalue.IterableKeyVal) *peerStorage { - return &peerStorage{ - db: db, - } -} - -func (a *peerStorage) savePeers(peers []proto.TCPAddr) error { - if len(peers) == 0 { - return nil - } - - batch, err := a.db.NewBatch() - if err != nil { - return StateError{errorType: ModificationError, originalError: err} - } - - for _, p := range peers { - k := intoBytes(p) - batch.Put(k[:], nil) - } - - err = a.db.Flush(batch) - if err != nil { - return err - } - return nil -} - -func (a *peerStorage) peers() ([]proto.TCPAddr, error) { - iter, err := a.db.NewKeyIterator([]byte{knownPeersPrefix}) - if err != nil { - return nil, err - } - defer iter.Release() - - var peers []proto.TCPAddr - for iter.Next() { - p, err := fromBytes(iter.Key()) - if err != nil { - return nil, err - } - - peers = append(peers, p) - } - if err := iter.Error(); err != nil { - return nil, err - } - return peers, nil -} diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 96f44e7df..42c46ad79 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -33,7 +33,7 @@ func newScriptCaller( }, nil } -func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockInfo *proto.BlockInfo, initialisation bool) error { +func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockInfo *proto.BlockInfo, isRideV5 bool, initialisation bool) error { sender, err := proto.NewAddressFromPublicKey(a.settings.AddressSchemeCharacter, order.GetSenderPK()) if err != nil { return err @@ -53,6 +53,9 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn env.SetThisFromAddress(sender) env.SetLastBlock(lastBlockInfo) env.ChooseSizeCheck(tree.LibVersion) + if err := env.ChooseTakeString(isRideV5); err != nil { + return errors.Wrap(err, "failed to initialize environment") + } err = env.SetTransactionFromOrder(order) if err != nil { return errors.Wrap(err, "failed to convert order") @@ -68,24 +71,25 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn return errors.Errorf("account script on order '%s' returned false result", base58.Encode(id)) } // Increase complexity. - ev, err := a.state.EstimatorVersion() - if err != nil { - return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) - } - est, err := a.stor.scriptsComplexity.newestScriptComplexityByAddr(sender, ev, !initialisation) - if err != nil { - return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) + if isRideV5 { // After activation of RideV5 + a.recentTxComplexity += uint64(r.Complexity()) + } else { + // For account script we use original estimation + est, err := a.stor.scriptsComplexity.newestOriginalScriptComplexityByAddr(sender, !initialisation) + if err != nil { + return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) + } + a.recentTxComplexity += uint64(est.Verifier) } - a.recentTxComplexity += uint64(est.Verifier) return nil } -func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockInfo *proto.BlockInfo, initialisation bool) error { +func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, params *appendTxParams) error { senderAddr, err := proto.NewAddressFromPublicKey(a.settings.AddressSchemeCharacter, tx.GetSenderPK()) if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !params.initialisation) if err != nil { return err } @@ -97,8 +101,12 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } + env.ChooseSizeCheck(tree.LibVersion) + if err := env.ChooseTakeString(params.rideV5Activated); err != nil { + return errors.Wrap(err, "failed to initialize environment") + } env.SetThisFromAddress(senderAddr) - env.SetLastBlock(lastBlockInfo) + env.SetLastBlock(params.blockInfo) err = env.SetTransaction(tx) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) @@ -114,26 +122,30 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errs.NewTransactionNotAllowedByScript("script failed", id) } // Increase complexity. - ev, err := a.state.EstimatorVersion() - if err != nil { - return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) - } - est, err := a.stor.scriptsComplexity.newestScriptComplexityByAddr(senderAddr, ev, !initialisation) - if err != nil { - return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) + if params.rideV5Activated { // After activation of RideV5 add actual complexity + a.recentTxComplexity += uint64(r.Complexity()) + } else { + // For account script we use original estimation + est, err := a.stor.scriptsComplexity.newestOriginalScriptComplexityByAddr(senderAddr, !params.initialisation) + if err != nil { + return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) + } + a.recentTxComplexity += uint64(est.Verifier) } - a.recentTxComplexity += uint64(est.Verifier) return nil } -func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { - tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) +func (a *scriptCaller) callAssetScriptCommon(env *ride.EvaluationEnvironment, assetID crypto.Digest, params *appendTxParams) (ride.Result, error) { + tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !params.initialisation) if err != nil { return nil, err } env.ChooseSizeCheck(tree.LibVersion) + if err := env.ChooseTakeString(params.rideV5Activated); err != nil { + return nil, errors.Wrap(err, "failed to initialize environment") + } switch tree.LibVersion { - case 4: + case 4, 5: assetInfo, err := a.state.NewestFullAssetInfo(assetID) if err != nil { return nil, err @@ -146,37 +158,38 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp } env.SetThisFromAssetInfo(assetInfo) } - env.SetLastBlock(lastBlockInfo) + env.SetLastBlock(params.blockInfo) r, err := ride.CallVerifier(env, tree) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } - if !r.Result() && !acceptFailed { + if !r.Result() && !params.acceptFailed { return nil, errs.NewTransactionNotAllowedByScript(r.UserError(), assetID.Bytes()) } // Increase complexity. - ev, err := a.state.EstimatorVersion() - if err != nil { - return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) - } - est, err := a.stor.scriptsComplexity.newestScriptComplexityByAsset(assetID, ev, !initialisation) - if err != nil { - return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) + if params.rideV5Activated { // After activation of RideV5 add actual execution complexity + a.recentTxComplexity += uint64(r.Complexity()) + } else { + // For asset script we use original estimation + est, err := a.stor.scriptsComplexity.newestScriptComplexityByAsset(assetID, !params.initialisation) + if err != nil { + return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) + } + a.recentTxComplexity += uint64(est.Verifier) } - a.recentTxComplexity += uint64(est.Verifier) return r, nil } -func (a *scriptCaller) callAssetScriptWithScriptTransfer(tr *proto.FullScriptTransfer, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { +func (a *scriptCaller) callAssetScriptWithScriptTransfer(tr *proto.FullScriptTransfer, assetID crypto.Digest, params *appendTxParams) (ride.Result, error) { env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { return nil, err } env.SetTransactionFromScriptTransfer(tr) - return a.callAssetScriptCommon(env, assetID, lastBlockInfo, initialisation, acceptFailed) + return a.callAssetScriptCommon(env, assetID, params) } -func (a *scriptCaller) callAssetScript(tx proto.Transaction, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { +func (a *scriptCaller) callAssetScript(tx proto.Transaction, assetID crypto.Digest, params *appendTxParams) (ride.Result, error) { env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { return nil, err @@ -185,16 +198,17 @@ func (a *scriptCaller) callAssetScript(tx proto.Transaction, assetID crypto.Dige if err != nil { return nil, err } - return a.callAssetScriptCommon(env, assetID, lastBlockInfo, initialisation, acceptFailed) + return a.callAssetScriptCommon(env, assetID, params) } -func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWithProofs, lastBlockInfo *proto.BlockInfo, scriptAddress proto.Address, initialisation bool) (bool, []proto.ScriptAction, error) { +func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWithProofs, info *fallibleValidationParams, scriptAddress proto.Address) (bool, []proto.ScriptAction, error) { env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { return false, nil, errors.Wrap(err, "failed to create RIDE environment") } env.SetThisFromAddress(scriptAddress) - env.SetLastBlock(lastBlockInfo) + env.SetLastBlock(info.blockInfo) + env.SetTimestamp(tx.Timestamp) err = env.SetTransaction(tx) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) @@ -204,6 +218,19 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWit return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } env.ChooseSizeCheck(tree.LibVersion) + + err = env.ChooseTakeString(info.rideV5Activated) + if err != nil { + return false, nil, errors.Wrap(err, "failed to choose takeString") + } + // Since V5 we have to create environment with wrapped state to which we put attached payments + if tree.LibVersion >= 5 { + env, err = ride.NewEnvironmentWithWrappedState(env, tx.Payments, tx.SenderPK) + if err != nil { + return false, nil, errors.Wrapf(err, "failed to create RIDE environment with wrapped state") + } + } + r, err := ride.CallFunction(env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) @@ -212,23 +239,28 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWit return false, nil, errors.Errorf("unexpected ScriptResult: %v", sr) } // Increase complexity. - ev, err := a.state.EstimatorVersion() - if err != nil { - return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) - } - est, err := a.stor.scriptsComplexity.newestScriptComplexityByAddr(scriptAddress, ev, !initialisation) - if err != nil { - return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) - } - fn := tx.FunctionCall.Name - if fn == "" && tx.FunctionCall.Default { - fn = "default" - } - c, ok := est.Functions[fn] - if !ok { - return false, nil, errors.Errorf("no estimation for function '%s' on invocation of transaction '%s'", fn, tx.ID.String()) + if info.rideV5Activated { // After activation of RideV5 add actual execution complexity + a.recentTxComplexity += uint64(r.Complexity()) + } else { + // For callable (function) we have to use latest possible estimation + ev, err := a.state.EstimatorVersion() + if err != nil { + return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) + } + est, err := a.stor.scriptsComplexity.newestScriptComplexityByAddr(scriptAddress, ev, !info.initialisation) + if err != nil { + return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) + } + fn := tx.FunctionCall.Name + if fn == "" && tx.FunctionCall.Default { + fn = "default" + } + c, ok := est.Functions[fn] + if !ok { + return false, nil, errors.Errorf("no estimation for function '%s' on invocation of transaction '%s'", fn, tx.ID.String()) + } + a.recentTxComplexity += uint64(c) } - a.recentTxComplexity += uint64(c) err = nil if !r.Result() { // Replace failure status with an error err = errors.Errorf("call failed: %s", r.UserError()) diff --git a/pkg/state/scripts_complexity.go b/pkg/state/scripts_complexity.go index 6972a8f93..9ea9478c9 100644 --- a/pkg/state/scripts_complexity.go +++ b/pkg/state/scripts_complexity.go @@ -1,6 +1,8 @@ package state import ( + "math" + "github.com/fxamacker/cbor/v2" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" @@ -8,6 +10,10 @@ import ( "github.com/wavesplatform/gowaves/pkg/ride" ) +type estimatorVersionRecord struct { + Version uint8 `cbor:"0,keyasint"` +} + type scriptsComplexity struct { hs *historyStorage } @@ -29,8 +35,29 @@ func (sc *scriptsComplexity) newestScriptComplexityByAddr(addr proto.Address, ev return record, nil } -func (sc *scriptsComplexity) newestScriptComplexityByAsset(asset crypto.Digest, ev int, filter bool) (*ride.TreeEstimation, error) { - key := assetScriptComplexityKey{ev, asset} +func (sc *scriptsComplexity) originalEstimatorVersion(addr proto.Address, filter bool) (int, error) { + key := accountOriginalEstimatorVersionKey{addr} + recordBytes, err := sc.hs.newestTopEntryData(key.bytes(), filter) + if err != nil { + return 0, err + } + record := new(estimatorVersionRecord) + if err := cbor.Unmarshal(recordBytes, record); err != nil { + return 0, errors.Wrap(err, "failed to unmarshal original estimator version record") + } + return int(record.Version), nil +} + +func (sc *scriptsComplexity) newestOriginalScriptComplexityByAddr(addr proto.Address, filter bool) (*ride.TreeEstimation, error) { + ev, err := sc.originalEstimatorVersion(addr, filter) + if err != nil { + return nil, err + } + return sc.newestScriptComplexityByAddr(addr, ev, filter) +} + +func (sc *scriptsComplexity) newestScriptComplexityByAsset(asset crypto.Digest, filter bool) (*ride.TreeEstimation, error) { + key := assetScriptComplexityKey{asset} recordBytes, err := sc.hs.newestTopEntryData(key.bytes(), filter) if err != nil { return nil, err @@ -42,8 +69,8 @@ func (sc *scriptsComplexity) newestScriptComplexityByAsset(asset crypto.Digest, return record, nil } -func (sc *scriptsComplexity) scriptComplexityByAsset(asset crypto.Digest, ev int, filter bool) (*ride.TreeEstimation, error) { - key := assetScriptComplexityKey{ev, asset} +func (sc *scriptsComplexity) scriptComplexityByAsset(asset crypto.Digest, filter bool) (*ride.TreeEstimation, error) { + key := assetScriptComplexityKey{asset} recordBytes, err := sc.hs.topEntryData(key.bytes(), filter) if err != nil { return nil, err @@ -69,7 +96,11 @@ func (sc *scriptsComplexity) scriptComplexityByAddress(addr proto.Address, ev in } func (sc *scriptsComplexity) saveComplexitiesForAddr(addr proto.Address, estimations map[int]ride.TreeEstimation, blockID proto.BlockID) error { + min := math.MaxUint8 for v, e := range estimations { + if v < min { + min = v + } recordBytes, err := cbor.Marshal(e) if err != nil { return errors.Wrapf(err, "failed to save complexities record for address '%s' in block '%s'", addr.String(), blockID.String()) @@ -80,20 +111,28 @@ func (sc *scriptsComplexity) saveComplexitiesForAddr(addr proto.Address, estimat return errors.Wrapf(err, "failed to save complexities record for address '%s' in block '%s'", addr.String(), blockID.String()) } } + key := accountOriginalEstimatorVersionKey{addr} + record := estimatorVersionRecord{uint8(min)} + recordBytes, err := cbor.Marshal(record) + if err != nil { + return errors.Wrapf(err, "failed to save original estimator version for address '%s' in block '%s'", addr.String(), blockID.String()) + } + err = sc.hs.addNewEntry(accountOriginalEstimatorVersion, key.bytes(), recordBytes, blockID) + if err != nil { + return errors.Wrapf(err, "failed to save original estimator version for address '%s' in block '%s'", addr.String(), blockID.String()) + } return nil } -func (sc *scriptsComplexity) saveComplexitiesForAsset(asset crypto.Digest, estimations map[int]ride.TreeEstimation, blockID proto.BlockID) error { - for v, e := range estimations { - recordBytes, err := cbor.Marshal(e) - if err != nil { - return errors.Wrapf(err, "failed to save complexities record for asset '%s' in block '%s'", asset.String(), blockID.String()) - } - key := assetScriptComplexityKey{v, asset} - err = sc.hs.addNewEntry(assetScriptComplexity, key.bytes(), recordBytes, blockID) - if err != nil { - return errors.Wrapf(err, "failed to save complexities record for asset '%s' in block '%s'", asset.String(), blockID.String()) - } +func (sc *scriptsComplexity) saveComplexitiesForAsset(asset crypto.Digest, estimation ride.TreeEstimation, blockID proto.BlockID) error { + recordBytes, err := cbor.Marshal(estimation) + if err != nil { + return errors.Wrapf(err, "failed to save complexity record for asset '%s' in block '%s'", asset.String(), blockID.String()) + } + key := assetScriptComplexityKey{asset} + err = sc.hs.addNewEntry(assetScriptComplexity, key.bytes(), recordBytes, blockID) + if err != nil { + return errors.Wrapf(err, "failed to save complexity record for asset '%s' in block '%s'", asset.String(), blockID.String()) } return nil } diff --git a/pkg/state/scripts_complexity_test.go b/pkg/state/scripts_complexity_test.go index 792f28ee7..89ea9797a 100644 --- a/pkg/state/scripts_complexity_test.go +++ b/pkg/state/scripts_complexity_test.go @@ -63,6 +63,9 @@ func TestSaveComplexityForAddr(t *testing.T) { res3, err := to.scriptsComplexity.newestScriptComplexityByAddr(addr, 3, true) require.NoError(t, err) assert.Equal(t, est3, *res3) + res, err := to.scriptsComplexity.newestOriginalScriptComplexityByAddr(addr, true) + require.NoError(t, err) + assert.Equal(t, est1, *res) to.stor.flush(t) @@ -75,6 +78,9 @@ func TestSaveComplexityForAddr(t *testing.T) { res3, err = to.scriptsComplexity.newestScriptComplexityByAddr(addr, 3, true) require.NoError(t, err) assert.Equal(t, est3, *res3) + res, err = to.scriptsComplexity.newestOriginalScriptComplexityByAddr(addr, true) + require.NoError(t, err) + assert.Equal(t, est1, *res) } func TestSaveComplexityForAsset(t *testing.T) { @@ -90,31 +96,16 @@ func TestSaveComplexityForAsset(t *testing.T) { to.stor.addBlock(t, blockID0) asset := testGlobal.asset0.asset.ID - est1 := ride.TreeEstimation{Estimation: 500, Verifier: 500} - est2 := ride.TreeEstimation{Estimation: 600, Verifier: 600} - est3 := ride.TreeEstimation{Estimation: 700, Verifier: 700} - estimations := map[int]ride.TreeEstimation{1: est1, 2: est2, 3: est3} - err = to.scriptsComplexity.saveComplexitiesForAsset(asset, estimations, blockID0) + est := ride.TreeEstimation{Estimation: 500, Verifier: 500} + err = to.scriptsComplexity.saveComplexitiesForAsset(asset, est, blockID0) assert.NoError(t, err) - res1, err := to.scriptsComplexity.newestScriptComplexityByAsset(asset, 1, true) - require.NoError(t, err) - assert.Equal(t, est1, *res1) - res2, err := to.scriptsComplexity.newestScriptComplexityByAsset(asset, 2, true) - require.NoError(t, err) - assert.Equal(t, est2, *res2) - res3, err := to.scriptsComplexity.newestScriptComplexityByAsset(asset, 3, true) + res1, err := to.scriptsComplexity.newestScriptComplexityByAsset(asset, true) require.NoError(t, err) - assert.Equal(t, est3, *res3) + assert.Equal(t, est, *res1) to.stor.flush(t) - res1, err = to.scriptsComplexity.newestScriptComplexityByAsset(asset, 1, true) - require.NoError(t, err) - assert.Equal(t, est1, *res1) - res2, err = to.scriptsComplexity.newestScriptComplexityByAsset(asset, 2, true) + res1, err = to.scriptsComplexity.newestScriptComplexityByAsset(asset, true) require.NoError(t, err) - assert.Equal(t, est2, *res2) - res3, err = to.scriptsComplexity.newestScriptComplexityByAsset(asset, 3, true) - require.NoError(t, err) - assert.Equal(t, est3, *res3) + assert.Equal(t, est, *res1) } diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 49b382208..5300d6087 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -381,7 +381,7 @@ func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (* return tree, nil } -func (ss *scriptsStorage) newestScriptPKByAddr(addr proto.Address, filter bool) (crypto.PublicKey, error) { +func (ss *scriptsStorage) NewestScriptPKByAddr(addr proto.Address, filter bool) (crypto.PublicKey, error) { key := accountScriptKey{addr} recordBytes, err := ss.hs.newestTopEntryData(key.bytes(), filter) if err != nil { diff --git a/pkg/state/state.go b/pkg/state/state.go index 2b104bf8e..0c4041ebd 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -24,12 +24,10 @@ import ( ) const ( - rollbackMaxBlocks = 2000 - blocksStorDir = "blocks_storage" - keyvalueDir = "key_value" - - maxScriptsRunsInBlock = 101 - maxScriptsComplexityInBlock = 1000000 + rollbackMaxBlocks = 2000 + blocksStorDir = "blocks_storage" + keyvalueDir = "key_value" + maxScriptsRunsInBlock = 101 ) var empty struct{} @@ -179,6 +177,9 @@ func (s *blockchainEntitiesStorage) commitUncertain(blockID proto.BlockID) error if err := s.scriptsStorage.commitUncertain(blockID); err != nil { return err } + if err := s.leases.commitUncertain(blockID); err != nil { + return err + } if err := s.sponsoredAssets.commitUncertain(blockID); err != nil { return err } @@ -189,6 +190,7 @@ func (s *blockchainEntitiesStorage) dropUncertain() { s.assets.dropUncertain() s.accountsDataStor.dropUncertain() s.scriptsStorage.dropUncertain() + s.leases.dropUncertain() s.sponsoredAssets.dropUncertain() } @@ -336,9 +338,8 @@ type stateManager struct { genesis proto.Block stateDB *stateDB - stor *blockchainEntitiesStorage - rw *blockReadWriter - peers *peerStorage + stor *blockchainEntitiesStorage + rw *blockReadWriter // BlockchainSettings: general info about the blockchain type, constants etc. settings *settings.BlockchainSettings @@ -433,7 +434,6 @@ func newStateManager(dataDir string, params StateParams, settings *settings.Bloc rw: rw, settings: settings, atx: atx, - peers: newPeerStorage(db), verificationGoroutinesNum: params.VerificationGoroutinesNum, newBlocks: newNewBlocks(rw, settings), } @@ -464,12 +464,40 @@ func newStateManager(dataDir string, params StateParams, settings *settings.Bloc return state, nil } -func (s *stateManager) Mutex() *lock.RwMutex { - return lock.NewRwMutex(s.mu) +func (s *stateManager) GetByteTree(recipient proto.Recipient) (proto.Script, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment + if recipient.Address != nil { + key := accountScriptKey{*recipient.Address} + script, err := s.stor.scriptsStorage.newestScriptBytesByKey(key.bytes(), true) + if err != nil { + return nil, errors.Wrapf(err, "failed to get script by address") + } + return script, nil + } + if recipient.Alias != nil { + address, err := s.NewestAddrByAlias(*recipient.Alias) + if err != nil { + return nil, errors.Wrapf(err, "failed to get address by alias") + } + key := accountScriptKey{address} + script, err := s.stor.scriptsStorage.newestScriptBytesByKey(key.bytes(), true) + if err != nil { + return nil, errors.Wrapf(err, "failed to get script by address") + } + return script, nil + } + return nil, errors.Errorf("address and alias from recipient are nil") } -func (s *stateManager) Peers() ([]proto.TCPAddr, error) { - return s.peers.peers() +func (s *stateManager) NewestScriptByAsset(asset proto.OptionalAsset) (proto.Script, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment + return s.stor.scriptsStorage.newestScriptBytesByAsset(asset.ID, true) +} + +func (s *stateManager) Mutex() *lock.RwMutex { + return lock.NewRwMutex(s.mu) } func (s *stateManager) setGenesisBlock(genesisBlock proto.Block) error { @@ -654,6 +682,28 @@ func (s *stateManager) BlockByHeight(height uint64) (*proto.Block, error) { return s.Block(blockID) } +func (s *stateManager) NewestLeasingInfo(id crypto.Digest) (*proto.LeaseInfo, error) { + // This function is used only from RIDE for now do not pass filter as an optimization + // TODO: Pass real filter value then supported in environment + leaseFromStore, err := s.stor.leases.newestLeasingInfo(id, true) + if err != nil { + return nil, err + } + leaseInfo := proto.LeaseInfo{ + Sender: leaseFromStore.Sender, + Recipient: leaseFromStore.Recipient, + IsActive: leaseFromStore.isActive(), + LeaseAmount: leaseFromStore.Amount, + } + return &leaseInfo, nil +} + +func (s *stateManager) NewestScriptPKByAddr(addr proto.Address) (crypto.PublicKey, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment + return s.stor.scriptsStorage.NewestScriptPKByAddr(addr, true) +} + func (s *stateManager) AddingBlockHeight() (uint64, error) { return s.rw.addingBlockHeight(), nil } @@ -785,7 +835,7 @@ func (s *stateManager) FullWavesBalance(account proto.Recipient) (*proto.FullWav } func (s *stateManager) NewestFullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } @@ -813,19 +863,33 @@ func (s *stateManager) NewestFullWavesBalance(account proto.Recipient) (*proto.F }, nil } -func (s *stateManager) NewestAccountBalance(account proto.Recipient, asset []byte) (uint64, error) { - addr, err := s.newestRecipientToAddress(account) +func isWaves(assetID []byte) bool { + wavesAsset := crypto.Digest{} + if len(wavesAsset) != len(assetID) { + return false + } + for i := range assetID { + if assetID[i] != wavesAsset[i] { + return false + } + } + return true +} + +func (s *stateManager) NewestAccountBalance(account proto.Recipient, assetID []byte) (uint64, error) { + addr, err := s.NewestRecipientToAddress(account) if err != nil { return 0, wrapErr(RetrievalError, err) } - if asset == nil { + + if assetID == nil || isWaves(assetID) { profile, err := s.newestWavesBalanceProfile(*addr) if err != nil { return 0, wrapErr(RetrievalError, err) } return profile.balance, nil } - balance, err := s.newestAssetBalance(*addr, asset) + balance, err := s.newestAssetBalance(*addr, assetID) if err != nil { return 0, wrapErr(RetrievalError, err) } @@ -1093,6 +1157,15 @@ func (s *stateManager) needToCancelLeases(blockchainHeight uint64) (bool, error) } dataTxHeight = approvalHeight + s.settings.ActivationWindowSize(blockchainHeight) } + rideV5Activated := s.stor.features.newestIsActivatedAtHeight(int16(settings.RideV5), blockchainHeight) + var rideV5Height uint64 = 0 + if rideV5Activated { + approvalHeight, err := s.stor.features.newestApprovalHeight(int16(settings.RideV5)) + if err != nil { + return false, err + } + rideV5Height = approvalHeight + s.settings.ActivationWindowSize(blockchainHeight) + } switch blockchainHeight { case s.settings.ResetEffectiveBalanceAtHeight: return true, nil @@ -1102,6 +1175,9 @@ func (s *stateManager) needToCancelLeases(blockchainHeight uint64) (bool, error) case dataTxHeight: // Only needed for MainNet. return s.settings.Type == settings.MainNet, nil + case rideV5Height: + // Cancellation of leasings to stolen aliases only required for MainNet + return s.settings.Type == settings.MainNet, nil default: return false, nil } @@ -1184,6 +1260,15 @@ func (s *stateManager) cancelLeases(height uint64, blockID proto.BlockID, initia } dataTxHeight = approvalHeight + s.settings.ActivationWindowSize(height) } + rideV5Activated := s.stor.features.newestIsActivatedAtHeight(int16(settings.RideV5), height) + var rideV5Height uint64 = 0 + if rideV5Activated { + approvalHeight, err := s.stor.features.newestApprovalHeight(int16(settings.RideV5)) + if err != nil { + return err + } + rideV5Height = approvalHeight + s.settings.ActivationWindowSize(height) + } if height == s.settings.ResetEffectiveBalanceAtHeight { if err := s.stor.leases.cancelLeases(nil, blockID); err != nil { return err @@ -1207,6 +1292,14 @@ func (s *stateManager) cancelLeases(height uint64, blockID proto.BlockID, initia if err := s.stor.balances.cancelInvalidLeaseIns(leaseIns, blockID); err != nil { return err } + } else if rideV5Activated && height == rideV5Height { + disabledAliases, err := s.stor.aliases.disabledAliases() + if err != nil { + return err + } + if err = s.stor.leases.cancelLeasesToAliases(disabledAliases, blockID); err != nil { + return err + } } return nil } @@ -1429,7 +1522,7 @@ func (s *stateManager) NewestHitSourceAtHeight(height uint64) ([]byte, error) { if height < 1 || height > maxHeight { return nil, wrapErr(InvalidInputError, errors.Errorf("NewestHitSourceAtHeight: height %d out of valid range [1, %d]", height, maxHeight)) } - return s.stor.hitSources.newestHitSource(height, true) + return s.stor.hitSources.newestHitSource(height, false) } func (s *stateManager) CurrentScore() (*big.Int, error) { @@ -1440,7 +1533,9 @@ func (s *stateManager) CurrentScore() (*big.Int, error) { return s.ScoreAtHeight(height) } -func (s *stateManager) newestRecipientToAddress(recipient proto.Recipient) (*proto.Address, error) { +func (s *stateManager) NewestRecipientToAddress(recipient proto.Recipient) (*proto.Address, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment if recipient.Address == nil { return s.stor.aliases.newestAddrByAlias(recipient.Alias.Alias, true) } @@ -1467,7 +1562,7 @@ func (s *stateManager) EffectiveBalance(account proto.Recipient, startHeight, en } func (s *stateManager) NewestEffectiveBalance(account proto.Recipient, startHeight, endHeight uint64) (uint64, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return 0, wrapErr(RetrievalError, err) } @@ -1483,11 +1578,6 @@ func (s *stateManager) BlockchainSettings() (*settings.BlockchainSettings, error return &cp, nil } -func (s *stateManager) SavePeers(peers []proto.TCPAddr) error { - return s.peers.savePeers(peers) - -} - func (s *stateManager) ResetValidationList() { s.reset() if err := s.stor.scriptsStorage.clear(); err != nil { @@ -1504,6 +1594,8 @@ func (s *stateManager) ValidateNextTx(tx proto.Transaction, currentTimestamp, pa } func (s *stateManager) NewestAddrByAlias(alias proto.Alias) (proto.Address, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment addr, err := s.stor.aliases.newestAddrByAlias(alias.Alias, true) if err != nil { return proto.Address{}, wrapErr(RetrievalError, err) @@ -1615,7 +1707,7 @@ func (s *stateManager) EstimatorVersion() (int, error) { // Accounts data storage. func (s *stateManager) RetrieveNewestEntry(account proto.Recipient, key string) (proto.DataEntry, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } @@ -1638,6 +1730,20 @@ func (s *stateManager) RetrieveEntries(account proto.Recipient) ([]proto.DataEnt return entries, nil } +func (s *stateManager) IsStateUntouched(account proto.Recipient) (bool, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment + addr, err := s.recipientToAddress(account) + if err != nil { + return false, wrapErr(RetrievalError, err) + } + entryExist, err := s.stor.accountsDataStor.entryExists(*addr, true) + if err != nil { + return false, wrapErr(RetrievalError, err) + } + return !entryExist, nil +} + func (s *stateManager) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { addr, err := s.recipientToAddress(account) if err != nil { @@ -1651,10 +1757,12 @@ func (s *stateManager) RetrieveEntry(account proto.Recipient, key string) (proto } func (s *stateManager) RetrieveNewestIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment entry, err := s.stor.accountsDataStor.retrieveNewestIntegerEntry(*addr, key, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -1675,10 +1783,12 @@ func (s *stateManager) RetrieveIntegerEntry(account proto.Recipient, key string) } func (s *stateManager) RetrieveNewestBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment entry, err := s.stor.accountsDataStor.retrieveNewestBooleanEntry(*addr, key, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -1699,10 +1809,12 @@ func (s *stateManager) RetrieveBooleanEntry(account proto.Recipient, key string) } func (s *stateManager) RetrieveNewestStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment entry, err := s.stor.accountsDataStor.retrieveNewestStringEntry(*addr, key, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -1723,10 +1835,12 @@ func (s *stateManager) RetrieveStringEntry(account proto.Recipient, key string) } func (s *stateManager) RetrieveNewestBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { - addr, err := s.newestRecipientToAddress(account) + addr, err := s.NewestRecipientToAddress(account) if err != nil { return nil, wrapErr(RetrievalError, err) } + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment entry, err := s.stor.accountsDataStor.retrieveNewestBinaryEntry(*addr, key, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -1802,6 +1916,8 @@ func (s *stateManager) NewAddrTransactionsIterator(addr proto.Address) (Transact } func (s *stateManager) NewestAssetIsSponsored(assetID crypto.Digest) (bool, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment sponsored, err := s.stor.sponsoredAssets.newestIsSponsored(assetID, true) if err != nil { return false, wrapErr(RetrievalError, err) @@ -1818,6 +1934,8 @@ func (s *stateManager) AssetIsSponsored(assetID crypto.Digest) (bool, error) { } func (s *stateManager) NewestAssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment info, err := s.stor.assets.newestAssetInfo(assetID, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -1853,6 +1971,8 @@ func (s *stateManager) NewestFullAssetInfo(assetID crypto.Digest) (*proto.FullAs if err != nil { return nil, wrapErr(RetrievalError, err) } + // This function is used only from SmartState interface, so for now we set filter to true. + // TODO: Pass actual filter value after support in RIDE environment info, err := s.stor.assets.newestAssetInfo(assetID, true) if err != nil { return nil, wrapErr(RetrievalError, err) @@ -2025,11 +2145,7 @@ func (s *stateManager) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptIn return nil, wrapErr(RetrievalError, err) } text := base64.StdEncoding.EncodeToString(scriptBytes) - ev, err := s.EstimatorVersion() - if err != nil { - return nil, wrapErr(Other, err) - } - est, err := s.stor.scriptsComplexity.scriptComplexityByAsset(assetID, ev, true) + est, err := s.stor.scriptsComplexity.scriptComplexityByAsset(assetID, true) if err != nil { return nil, wrapErr(RetrievalError, err) } @@ -2051,11 +2167,7 @@ func (s *stateManager) NewestScriptInfoByAsset(assetID crypto.Digest) (*proto.Sc return nil, wrapErr(RetrievalError, err) } text := base64.StdEncoding.EncodeToString(scriptBytes) - ev, err := s.EstimatorVersion() - if err != nil { - return nil, wrapErr(Other, err) - } - est, err := s.stor.scriptsComplexity.newestScriptComplexityByAsset(assetID, ev, true) + est, err := s.stor.scriptsComplexity.newestScriptComplexityByAsset(assetID, true) if err != nil { return nil, wrapErr(RetrievalError, err) } diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 275b7e7ed..55bfe1688 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -4,7 +4,6 @@ import ( "fmt" "io/ioutil" "math/big" - "net" "os" "path/filepath" "testing" @@ -288,41 +287,6 @@ func TestStateIntegrated(t *testing.T) { } } -func TestStateManager_SavePeers(t *testing.T) { - dataDir, err := ioutil.TempDir(os.TempDir(), "dataDir") - if err != nil { - t.Fatalf("Failed to create temp dir for data: %v\n", err) - } - defer func() { - err = os.RemoveAll(dataDir) - require.NoError(t, err) - }() - - manager, err := newStateManager(dataDir, DefaultTestingStateParams(), settings.MainNetSettings) - if err != nil { - t.Fatalf("Failed to create state manager: %v.\n", err) - } - defer func() { - err := manager.Close() - require.NoError(t, err) - }() - - peers, err := manager.Peers() - require.NoError(t, err) - assert.Len(t, peers, 0) - - peers = []proto.TCPAddr{ - proto.NewTCPAddr(net.IPv4(127, 0, 0, 1), 65535), - proto.NewTCPAddr(net.IPv4(83, 127, 1, 254).To4(), 80), - } - require.NoError(t, manager.SavePeers(peers)) - - // check that peers saved - peers2, err := manager.Peers() - require.NoError(t, err) - assert.Len(t, peers2, 2) -} - func TestPreactivatedFeatures(t *testing.T) { blocksPath, err := blocksPath() assert.NoError(t, err) diff --git a/pkg/state/testdata/scripts/ride5_leasing.base64 b/pkg/state/testdata/scripts/ride5_leasing.base64 new file mode 100644 index 000000000..d3e6ff2a0 --- /dev/null +++ b/pkg/state/testdata/scripts/ride5_leasing.base64 @@ -0,0 +1 @@ +AAIFAAAAAAAAACkIAhIECgIIARIECgIIARIECgIIARIECgIIARIDCgEBEgMKAQESAwoBAgAAAAAAAAAHAAAAAWkBAAAAFHNpbXBsZUxlYXNlVG9BZGRyZXNzAAAAAgAAAANyY3AAAAAGYW1vdW50BAAAAARhZGRyCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAANyY3AJAAUUAAAAAgkABEwAAAACCQAERAAAAAIFAAAABGFkZHIFAAAABmFtb3VudAUAAAADbmlsBQAAAAR1bml0AAAAAWkBAAAAFmRldGFpbGVkTGVhc2VUb0FkZHJlc3MAAAACAAAAA3JjcAAAAAZhbW91bnQEAAAABGFkZHIJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEFAAAAA3JjcAQAAAAFbGVhc2UJAARFAAAAAwUAAAAEYWRkcgUAAAAGYW1vdW50AAAAAAAAAAAABAAAAAJpZAkABDkAAAABBQAAAAVsZWFzZQkABRQAAAACCQAETAAAAAIFAAAABWxlYXNlBQAAAANuaWwFAAAAAmlkAAAAAWkBAAAAEnNpbXBsZUxlYXNlVG9BbGlhcwAAAAIAAAADcmNwAAAABmFtb3VudAQAAAAFYWxpYXMJAQAAAAVBbGlhcwAAAAEFAAAAA3JjcAkABRQAAAACCQAETAAAAAIJAAREAAAAAgUAAAAFYWxpYXMFAAAABmFtb3VudAUAAAADbmlsBQAAAAR1bml0AAAAAWkBAAAAFGRldGFpbGVkTGVhc2VUb0FsaWFzAAAAAgAAAANyY3AAAAAGYW1vdW50BAAAAAVhbGlhcwkBAAAABUFsaWFzAAAAAQUAAAADcmNwBAAAAAVsZWFzZQkABEUAAAADBQAAAAVhbGlhcwUAAAAGYW1vdW50AAAAAAAAAAAABAAAAAJpZAkABDkAAAABBQAAAAVsZWFzZQkABRQAAAACCQAETAAAAAIFAAAABWxlYXNlBQAAAANuaWwFAAAAAmlkAAAAAWkBAAAAE3NpbXBsZUxlYXNlVG9TZW5kZXIAAAABAAAABmFtb3VudAkABRQAAAACCQAETAAAAAIJAAREAAAAAggFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAAA25pbAUAAAAEdW5pdAAAAAFpAQAAABVkZXRhaWxlZExlYXNlVG9TZW5kZXIAAAABAAAABmFtb3VudAQAAAAFbGVhc2UJAARFAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQAAAAAAAAAAAAEAAAAAmlkCQAEOQAAAAEFAAAABWxlYXNlCQAFFAAAAAIJAARMAAAAAgUAAAAFbGVhc2UFAAAAA25pbAUAAAACaWQAAAABaQEAAAAGY2FuY2VsAAAAAQAAAAJpZAkABRQAAAACCQAETAAAAAIJAQAAAAtMZWFzZUNhbmNlbAAAAAEFAAAAAmlkBQAAAANuaWwFAAAAAmlkAAAAAOkd5dA= \ No newline at end of file diff --git a/pkg/state/threadsafe_wrapper.go b/pkg/state/threadsafe_wrapper.go index 0fd4cffd1..474e4ad0e 100644 --- a/pkg/state/threadsafe_wrapper.go +++ b/pkg/state/threadsafe_wrapper.go @@ -115,12 +115,6 @@ func (a *ThreadSafeReadWrapper) BlockchainSettings() (*settings.BlockchainSettin return a.s.BlockchainSettings() } -func (a *ThreadSafeReadWrapper) Peers() ([]proto.TCPAddr, error) { - a.mu.RLock() - defer a.mu.RUnlock() - return a.s.Peers() -} - func (a *ThreadSafeReadWrapper) VotesNum(featureID int16) (uint64, error) { a.mu.RLock() defer a.mu.RUnlock() @@ -338,13 +332,7 @@ func (a *ThreadSafeWriteWrapper) Map(f func(state NonThreadSafeState) error) err return f(a.s) } -func (a *ThreadSafeWriteWrapper) ValidateNextTx( - tx proto.Transaction, - currentTimestamp uint64, - parentTimestamp uint64, - blockVersion proto.BlockVersion, - checkScripts bool, -) error { +func (a *ThreadSafeWriteWrapper) ValidateNextTx(_ proto.Transaction, _, _ uint64, _ proto.BlockVersion, _ bool) error { panic("Invalid ValidateNextTx usage on thread safe wrapper. Should call TxValidation") } @@ -407,12 +395,6 @@ func (a *ThreadSafeWriteWrapper) TxValidation(f func(validation TxValidation) er return f(a.s) } -func (a *ThreadSafeWriteWrapper) SavePeers(peers []proto.TCPAddr) error { - a.lock() - defer a.unlock() - return a.s.SavePeers(peers) -} - func (a *ThreadSafeWriteWrapper) StartProvidingExtendedApi() error { a.lock() defer a.unlock() diff --git a/pkg/state/transaction_checker.go b/pkg/state/transaction_checker.go index 5ee0c51b4..2d7cf4a59 100644 --- a/pkg/state/transaction_checker.go +++ b/pkg/state/transaction_checker.go @@ -68,6 +68,10 @@ func (tc *transactionChecker) scriptActivation(libVersion int, hasBlockV2 bool) if err != nil { return err } + continuationActivated, err := tc.stor.features.newestIsActivated(int16(settings.RideV5)) + if err != nil { + return err + } if libVersion == 3 && !rideForDAppsActivated { return errors.New("Ride4DApps feature must be activated for scripts version 3") } @@ -77,28 +81,55 @@ func (tc *transactionChecker) scriptActivation(libVersion int, hasBlockV2 bool) if libVersion == 4 && !blockV5Activated { return errors.New("MultiPaymentInvokeScript feature must be activated for scripts version 4") } + if libVersion == 5 && !continuationActivated { + return errors.New("ContinuationTransaction feature must be activated for scripts version 5") + } return nil } -func (tc *transactionChecker) checkScriptComplexity(tree *ride.Tree, estimation ride.TreeEstimation) error { - var maxComplexity int +func (tc *transactionChecker) checkScriptComplexity(tree *ride.Tree, estimation ride.TreeEstimation, reducedVerifierComplexity bool) error { + /* + | Script Type | Max complexity before BlockV5 | Max complexity after BlockV5 | + | ---------------------------------- | ----------------------------- | ---------------------------- | + | Account / DApp Verifier V1, V2 | 2000 | 2000 | + | Account / DApp Verifier V3, V4, V5 | 4000 | 2000 | + | Asset Verifier V1, V2 | 2000 | 2000 | + | Asset Verifier V3, V4, V5 | 4000 | 4000 | + | DApp Callable V1, V2 | 2000 | 2000 | + | DApp Callable V3, V4 | 4000 | 4000 | + | DApp Callable V5 | 10000 | 10000 | + */ + var maxCallableComplexity, maxVerifierComplexity int switch tree.LibVersion { case 1, 2: - maxComplexity = 2000 + maxCallableComplexity = MaxCallableScriptComplexityV12 + maxVerifierComplexity = MaxVerifierScriptComplexityReduced case 3, 4: - maxComplexity = 4000 + maxCallableComplexity = MaxCallableScriptComplexityV34 + maxVerifierComplexity = MaxVerifierScriptComplexity + case 5: + maxCallableComplexity = MaxCallableScriptComplexityV5 + maxVerifierComplexity = MaxVerifierScriptComplexity + } + if reducedVerifierComplexity { + maxVerifierComplexity = MaxVerifierScriptComplexityReduced + } + if !tree.IsDApp() { // Expression (simple) script, has only verifier. + if complexity := estimation.Verifier; complexity > maxVerifierComplexity { + return errors.Errorf("script complexity %d exceeds maximum allowed complexity of %d", complexity, maxVerifierComplexity) + } + return nil } - complexity := estimation.Verifier - if tree.IsDApp() { - complexity = estimation.Estimation + if complexity := estimation.Verifier; complexity > maxVerifierComplexity { + return errors.Errorf("verifier script complexity %d exceeds maximum allowed complexity of %d", complexity, maxVerifierComplexity) } - if complexity > maxComplexity { - return errors.Errorf("script complexity %d exceeds maximum allowed complexity of %d", complexity, maxComplexity) + if complexity := estimation.Estimation; complexity > maxCallableComplexity { + return errors.Errorf("callable script complexity %d exceeds maximum allowed complexity of %d", complexity, maxCallableComplexity) } return nil } -func (tc *transactionChecker) checkScript(script proto.Script, estimatorVersion int) (map[int]ride.TreeEstimation, error) { +func (tc *transactionChecker) checkScript(script proto.Script, estimatorVersion int, reducedVerifierComplexity, expandEstimations bool) (map[int]ride.TreeEstimation, error) { tree, err := ride.Parse(script) if err != nil { return nil, errs.Extend(err, "failed to build AST") @@ -115,14 +146,18 @@ func (tc *transactionChecker) checkScript(script proto.Script, estimatorVersion } estimations := make(map[int]ride.TreeEstimation) - for ev := estimatorVersion; ev <= maxEstimatorVersion; ev++ { + maxVersion := maxEstimatorVersion + if !expandEstimations { + maxVersion = estimatorVersion + } + for ev := estimatorVersion; ev <= maxVersion; ev++ { est, err := ride.EstimateTree(tree, ev) if err != nil { return nil, errs.Extend(err, "failed to estimate script complexity") } estimations[ev] = est } - if err := tc.checkScriptComplexity(tree, estimations[estimatorVersion]); err != nil { + if err := tc.checkScriptComplexity(tree, estimations[estimatorVersion], reducedVerifierComplexity); err != nil { return nil, errors.Wrap(err, "failed to check script complexity") } return estimations, nil @@ -152,11 +187,16 @@ func (tc *transactionChecker) checkFee( initialisation: info.initialisation, txAssets: assets, } + + isRideV5Activated, err := tc.stor.features.newestIsActivated(int16(settings.RideV5)) + if err != nil { + return errors.Errorf("failed to check if feature is was activated, %v", err) + } if !assets.feeAsset.Present { // Waves. - return checkMinFeeWaves(tx, params) + return checkMinFeeWaves(tx, params, isRideV5Activated, info.estimatorVersion()) } - return checkMinFeeAsset(tx, assets.feeAsset.ID, params) + return checkMinFeeAsset(tx, assets.feeAsset.ID, params, isRideV5Activated, info.estimatorVersion()) } func (tc *transactionChecker) checkFromFuture(timestamp uint64) bool { @@ -376,13 +416,19 @@ func (tc *transactionChecker) checkIssueWithProofs(transaction proto.Transaction // No script checks / actions are needed. return nil, nil } - estimations, err := tc.checkScript(tx.Script, info.estimatorVersion()) + // For asset scripts do not reduce verifier complexity and only one estimation is required + currentEstimatorVersion := info.estimatorVersion() + estimations, err := tc.checkScript(tx.Script, currentEstimatorVersion, false, false) if err != nil { return nil, errors.Errorf("checkScript() tx %s: %v", tx.ID.String(), err) } assetID := *tx.ID // Save complexities to storage so we won't have to calculate it every time the script is called. - if err := tc.stor.scriptsComplexity.saveComplexitiesForAsset(assetID, estimations, info.blockID); err != nil { + complexity, ok := estimations[currentEstimatorVersion] + if !ok { + return nil, errors.Errorf("failed to calculate asset script complexity by estimator version %d", currentEstimatorVersion) + } + if err := tc.stor.scriptsComplexity.saveComplexitiesForAsset(assetID, complexity, info.blockID); err != nil { return nil, err } return nil, nil @@ -518,6 +564,7 @@ func (tc *transactionChecker) checkBurnWithProofs(transaction proto.Transaction, if err != nil { return nil, err } + assets := &txAssets{feeAsset: proto.OptionalAsset{Present: false}, smartAssets: smartAssets} if err := tc.checkFee(transaction, assets, info); err != nil { return nil, err @@ -772,14 +819,14 @@ func (tc *transactionChecker) checkLeaseCancel(tx *proto.LeaseCancel, info *chec if err != nil { return errs.Extend(err, "no leasing info found for this leaseID") } - if !l.isActive && (info.currentTimestamp > tc.settings.AllowMultipleLeaseCancelUntilTime) { + if !l.isActive() && (info.currentTimestamp > tc.settings.AllowMultipleLeaseCancelUntilTime) { return errs.NewTxValidationError("Reason: Cannot cancel already cancelled lease") } senderAddr, err := proto.NewAddressFromPublicKey(tc.settings.AddressSchemeCharacter, tx.SenderPK) if err != nil { return err } - if (l.sender != senderAddr) && (info.currentTimestamp > tc.settings.AllowMultipleLeaseCancelUntilTime) { + if (l.Sender != senderAddr) && (info.currentTimestamp > tc.settings.AllowMultipleLeaseCancelUntilTime) { return errs.NewTxValidationError("LeaseTransaction was leased by other sender") } return nil @@ -971,9 +1018,11 @@ func (tc *transactionChecker) checkSetScriptWithProofs(transaction proto.Transac return nil, errs.Extend(err, "invalid timestamp") } assets := &txAssets{feeAsset: proto.OptionalAsset{Present: false}} + if err := tc.checkFee(transaction, assets, info); err != nil { return nil, err } + addr, err := proto.NewAddressFromPublicKey(tc.settings.AddressSchemeCharacter, tx.SenderPK) if err != nil { return nil, err @@ -985,7 +1034,7 @@ func (tc *transactionChecker) checkSetScriptWithProofs(transaction proto.Transac } return nil, nil } - estimations, err := tc.checkScript(tx.Script, info.estimatorVersion()) + estimations, err := tc.checkScript(tx.Script, info.estimatorVersion(), info.blockVersion == proto.ProtobufBlockVersion, true) if err != nil { return nil, errors.Errorf("checkScript() tx %s: %v", tx.ID.String(), err) } @@ -993,6 +1042,7 @@ func (tc *transactionChecker) checkSetScriptWithProofs(transaction proto.Transac if err := tc.stor.scriptsComplexity.saveComplexitiesForAddr(addr, estimations, info.blockID); err != nil { return nil, err } + return nil, nil } @@ -1014,9 +1064,11 @@ func (tc *transactionChecker) checkSetAssetScriptWithProofs(transaction proto.Tr if err := tc.checkFee(transaction, assets, info); err != nil { return nil, errs.Extend(err, "check fee") } + if !bytes.Equal(assetInfo.issuer[:], tx.SenderPK[:]) { return nil, errs.NewAssetIssuedByOtherAddress("asset was issued by other address") } + isSmartAsset := tc.stor.scriptsStorage.newestIsSmartAsset(tx.AssetID, !info.initialisation) if len(tx.Script) == 0 { return nil, errs.NewTxValidationError("Cannot set empty script") @@ -1024,12 +1076,18 @@ func (tc *transactionChecker) checkSetAssetScriptWithProofs(transaction proto.Tr if !isSmartAsset { return nil, errs.NewTxValidationError("Reason: Cannot set script on an asset issued without a script. Referenced assetId not found") } - estimations, err := tc.checkScript(tx.Script, info.estimatorVersion()) + currentEstimatorVersion := info.estimatorVersion() + // Do not reduce verifier complexity for asset scripts and only one estimation is required + estimations, err := tc.checkScript(tx.Script, currentEstimatorVersion, false, false) if err != nil { return nil, errors.Errorf("checkScript() tx %s: %v", tx.ID.String(), err) } // Save complexity to storage so we won't have to calculate it every time the script is called. - if err := tc.stor.scriptsComplexity.saveComplexitiesForAsset(tx.AssetID, estimations, info.blockID); err != nil { + estimation, ok := estimations[currentEstimatorVersion] + if !ok { + return nil, errors.Errorf("failed to calculate asset script complexity by estimator version %d", currentEstimatorVersion) + } + if err := tc.stor.scriptsComplexity.saveComplexitiesForAsset(tx.AssetID, estimation, info.blockID); err != nil { return nil, errs.Extend(err, "saveComplexityForAsset") } return smartAssets, nil @@ -1057,12 +1115,18 @@ func (tc *transactionChecker) checkInvokeScriptWithProofs(transaction proto.Tran if err != nil { return nil, err } + rideV5activated, err := tc.stor.features.newestIsActivated(int16(settings.RideV5)) + if err != nil { + return nil, err + } l := len(tx.Payments) switch { - case l > 1 && !multiPaymentActivated: + case l > 1 && !multiPaymentActivated && !rideV5activated: return nil, errors.New("no more than one payment is allowed") - case l > 2 && multiPaymentActivated: + case l > 2 && multiPaymentActivated && !rideV5activated: return nil, errors.New("no more than two payments is allowed") + case l > 10 && rideV5activated: + return nil, errors.New("no more than ten payments is allowed since RideV5 activation") } var paymentAssets []proto.OptionalAsset for _, payment := range tx.Payments { diff --git a/pkg/state/transaction_checker_test.go b/pkg/state/transaction_checker_test.go index 52f3aec90..30d44e8b4 100644 --- a/pkg/state/transaction_checker_test.go +++ b/pkg/state/transaction_checker_test.go @@ -49,7 +49,7 @@ func TestCheckGenesis(t *testing.T) { assert.NoError(t, err, "failed to clean test data dirs") }() - tx := createGenesis(t) + tx := createGenesis() info := defaultCheckerInfo(t) _, err := to.tc.checkGenesis(tx, info) info.blockID = proto.NewBlockIDFromSignature(genSig) @@ -286,7 +286,7 @@ func TestCheckReissueWithSig(t *testing.T) { tx.SenderPK = assetInfo.issuer tx.Reissuable = false - err = to.tp.performReissueWithSig(tx, defaultPerformerInfo(t)) + err = to.tp.performReissueWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performReissueWithSig failed") to.stor.addBlock(t, blockID0) to.stor.flush(t) @@ -340,7 +340,7 @@ func TestCheckReissueWithProofs(t *testing.T) { tx.SenderPK = assetInfo.issuer tx.Reissuable = false - err = to.tp.performReissueWithProofs(tx, defaultPerformerInfo(t)) + err = to.tp.performReissueWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performReissueWithProofs failed") to.stor.addBlock(t, blockID0) to.stor.flush(t) @@ -722,7 +722,7 @@ func TestCheckLeaseCancelWithSig(t *testing.T) { assert.Error(t, err, "checkLeaseCancelWithSig did not fail when cancelling nonexistent lease") to.stor.addBlock(t, blockID0) - err = to.tp.performLeaseWithSig(leaseTx, defaultPerformerInfo(t)) + err = to.tp.performLeaseWithSig(leaseTx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithSig failed") to.stor.flush(t) @@ -757,7 +757,7 @@ func TestCheckLeaseCancelWithProofs(t *testing.T) { assert.Error(t, err, "checkLeaseCancelWithProofs did not fail when cancelling nonexistent lease") to.stor.addBlock(t, blockID0) - err = to.tp.performLeaseWithProofs(leaseTx, defaultPerformerInfo(t)) + err = to.tp.performLeaseWithProofs(leaseTx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithProofs failed") to.stor.flush(t) @@ -773,7 +773,7 @@ func TestCheckLeaseCancelWithProofs(t *testing.T) { _, err = to.tc.checkLeaseCancelWithProofs(tx, info) assert.NoError(t, err, "checkLeaseCancelWithProofs failed with valid leaseCancel tx") - err = to.tp.performLeaseCancelWithProofs(tx, defaultPerformerInfo(t)) + err = to.tp.performLeaseCancelWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseCancelWithProofs() failed") _, err = to.tc.checkLeaseCancelWithProofs(tx, info) @@ -797,7 +797,7 @@ func TestCheckCreateAliasWithSig(t *testing.T) { assert.NoError(t, err, "checkCreateAliasWithSig failed with valid createAlias tx") to.stor.addBlock(t, blockID0) - err = to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo(t)) + err = to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithSig failed") to.stor.flush(t) @@ -832,7 +832,7 @@ func TestCheckCreateAliasWithProofs(t *testing.T) { assert.NoError(t, err, "checkCreateAliasWithProofs failed with valid createAlias tx") to.stor.addBlock(t, blockID0) - err = to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo(t)) + err = to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithProofs failed") to.stor.flush(t) diff --git a/pkg/state/transaction_differ.go b/pkg/state/transaction_differ.go index e37c02f0f..05b4340d6 100644 --- a/pkg/state/transaction_differ.go +++ b/pkg/state/transaction_differ.go @@ -971,7 +971,7 @@ func (td *transactionDiffer) createDiffLeaseCancel(tx *proto.LeaseCancel, info * return txBalanceChanges{}, err } senderKey := wavesBalanceKey{address: senderAddr} - senderLeaseOutDiff := -int64(l.leaseAmount) + senderLeaseOutDiff := -int64(l.Amount) if err := diff.appendBalanceDiff(senderKey.bytes(), newBalanceDiff(0, 0, senderLeaseOutDiff, false)); err != nil { return txBalanceChanges{}, err } @@ -980,8 +980,8 @@ func (td *transactionDiffer) createDiffLeaseCancel(tx *proto.LeaseCancel, info * return txBalanceChanges{}, err } // Append receiver diff. - receiverKey := wavesBalanceKey{address: l.recipient} - receiverLeaseInDiff := -int64(l.leaseAmount) + receiverKey := wavesBalanceKey{address: l.Recipient} + receiverLeaseInDiff := -int64(l.Amount) if err := diff.appendBalanceDiff(receiverKey.bytes(), newBalanceDiff(0, receiverLeaseInDiff, 0, false)); err != nil { return txBalanceChanges{}, err } @@ -990,7 +990,7 @@ func (td *transactionDiffer) createDiffLeaseCancel(tx *proto.LeaseCancel, info * return txBalanceChanges{}, errors.Wrap(err, "failed to append miner payout") } } - addresses := []proto.Address{senderAddr, l.recipient} + addresses := []proto.Address{senderAddr, l.Recipient} changes := newTxBalanceChanges(addresses, diff) return changes, nil } diff --git a/pkg/state/transaction_differ_test.go b/pkg/state/transaction_differ_test.go index b45ced18f..3a2debf50 100644 --- a/pkg/state/transaction_differ_test.go +++ b/pkg/state/transaction_differ_test.go @@ -41,7 +41,7 @@ func createDifferTestObjects(t *testing.T) (*differTestObjects, []string) { return &differTestObjects{stor, td, tp}, path } -func createGenesis(t *testing.T) *proto.Genesis { +func createGenesis() *proto.Genesis { return proto.NewUnsignedGenesis(testGlobal.recipientInfo.addr, defaultAmount, defaultTimestamp) } @@ -55,8 +55,8 @@ func TestCreateDiffGenesis(t *testing.T) { assert.NoError(t, err, "failed to clean test data dirs") }() - tx := createGenesis(t) - ch, err := to.td.createDiffGenesis(tx, defaultDifferInfo(t)) + tx := createGenesis() + ch, err := to.td.createDiffGenesis(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffGenesis() failed") correctDiff := txDiff{testGlobal.recipientInfo.wavesKey: newBalanceDiff(int64(tx.Amount), 0, 0, false)} assert.Equal(t, correctDiff, ch.diff) @@ -84,7 +84,7 @@ func TestCreateDiffPayment(t *testing.T) { }() tx := createPayment(t) - ch, err := to.td.createDiffPayment(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffPayment(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffPayment() failed") correctDiff := txDiff{ @@ -121,7 +121,7 @@ func TestCreateDiffTransferWithSig(t *testing.T) { assetId := tx.FeeAsset.ID to.stor.createAsset(t, assetId) - ch, err := to.td.createDiffTransferWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffTransferWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffTransferWithSig() failed") correctDiff := txDiff{ @@ -137,11 +137,11 @@ func TestCreateDiffTransferWithSig(t *testing.T) { assert.Equal(t, correctAddrs, ch.addrs) to.stor.activateSponsorship(t) - _, err = to.td.createDiffTransferWithSig(tx, defaultDifferInfo(t)) + _, err = to.td.createDiffTransferWithSig(tx, defaultDifferInfo()) assert.Error(t, err, "createDiffTransferWithSig() did not fail with unsponsored asset") err = to.stor.entities.sponsoredAssets.sponsorAsset(assetId, 10, blockID0) assert.NoError(t, err, "sponsorAsset() failed") - ch, err = to.td.createDiffTransferWithSig(tx, defaultDifferInfo(t)) + ch, err = to.td.createDiffTransferWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffTransferWithSig() failed with valid sponsored asset") feeInWaves, err := to.stor.entities.sponsoredAssets.sponsoredAssetToWaves(assetId, tx.Fee) @@ -183,7 +183,7 @@ func TestCreateDiffTransferWithProofs(t *testing.T) { assetId := tx.FeeAsset.ID to.stor.createAsset(t, assetId) - ch, err := to.td.createDiffTransferWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffTransferWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffTransferWithProofs() failed") correctDiff := txDiff{ @@ -199,11 +199,11 @@ func TestCreateDiffTransferWithProofs(t *testing.T) { assert.Equal(t, correctAddrs, ch.addrs) to.stor.activateSponsorship(t) - _, err = to.td.createDiffTransferWithProofs(tx, defaultDifferInfo(t)) + _, err = to.td.createDiffTransferWithProofs(tx, defaultDifferInfo()) assert.Error(t, err, "createDiffTransferWithProofs() did not fail with unsponsored asset") err = to.stor.entities.sponsoredAssets.sponsorAsset(assetId, 10, blockID0) assert.NoError(t, err, "sponsorAsset() failed") - ch, err = to.td.createDiffTransferWithProofs(tx, defaultDifferInfo(t)) + ch, err = to.td.createDiffTransferWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffTransferWithProofs() failed with valid sponsored asset") feeInWaves, err := to.stor.entities.sponsoredAssets.sponsoredAssetToWaves(assetId, tx.Fee) @@ -249,7 +249,7 @@ func TestCreateDiffIssueWithSig(t *testing.T) { }() tx := createIssueWithSig(t, 1000) - ch, err := to.td.createDiffIssueWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffIssueWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffIssueWithSig() failed") correctDiff := txDiff{ @@ -289,7 +289,7 @@ func TestCreateDiffIssueWithProofs(t *testing.T) { }() tx := createIssueWithProofs(t, 1000) - ch, err := to.td.createDiffIssueWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffIssueWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffIssueWithProofs() failed") correctDiff := txDiff{ @@ -322,7 +322,7 @@ func TestCreateDiffReissueWithSig(t *testing.T) { }() tx := createReissueWithSig(t, 1000) - ch, err := to.td.createDiffReissueWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffReissueWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffReissueWithSig() failed") correctDiff := txDiff{ @@ -355,7 +355,7 @@ func TestCreateDiffReissueWithProofs(t *testing.T) { }() tx := createReissueWithProofs(t, 1000) - ch, err := to.td.createDiffReissueWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffReissueWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffReissueWithProofs() failed") correctDiff := txDiff{ @@ -388,7 +388,7 @@ func TestCreateDiffBurnWithSig(t *testing.T) { }() tx := createBurnWithSig(t) - ch, err := to.td.createDiffBurnWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffBurnWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffBurnWithSig() failed") correctDiff := txDiff{ @@ -421,7 +421,7 @@ func TestCreateDiffBurnWithProofs(t *testing.T) { }() tx := createBurnWithProofs(t) - ch, err := to.td.createDiffBurnWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffBurnWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffBurnWithProofs() failed") correctDiff := txDiff{ @@ -474,7 +474,7 @@ func TestCreateDiffExchangeWithSig(t *testing.T) { }() tx := createExchangeWithSig(t) - ch, err := to.td.createDiffExchange(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffExchange(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") price := tx.Price * tx.Amount / priceConstant @@ -534,7 +534,7 @@ func TestCreateDiffExchangeWithProofs(t *testing.T) { }() tx := createExchangeWithProofs(t) - ch, err := to.td.createDiffExchange(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffExchange(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") price := tx.Price * tx.Amount / priceConstant @@ -571,39 +571,39 @@ func createExchangeWithProofsWithOrdersV3(t *testing.T) *proto.ExchangeWithProof } func createExchangeWithProofsWithOrdersV4(t *testing.T, price, amount uint64) *proto.ExchangeWithProofs { - bo := proto.NewUnsignedOrderV4(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, uint64(price), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + bo := proto.NewUnsignedOrderV4(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, price, amount, 0, 0, 3, *testGlobal.asset2.asset) err := bo.Sign(proto.MainNetScheme, testGlobal.senderInfo.sk) require.NoError(t, err, "bo.Sign() failed") - so := proto.NewUnsignedOrderV4(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, uint64(price), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + so := proto.NewUnsignedOrderV4(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, price, amount, 0, 0, 3, *testGlobal.asset2.asset) err = so.Sign(proto.MainNetScheme, testGlobal.recipientInfo.sk) require.NoError(t, err, "so.Sign() failed") - tx := proto.NewUnsignedExchangeWithProofs(3, bo, so, uint64(price), bo.Amount, 1, 2, defaultFee, defaultTimestamp) + tx := proto.NewUnsignedExchangeWithProofs(3, bo, so, price, bo.Amount, 1, 2, defaultFee, defaultTimestamp) err = tx.Sign(proto.MainNetScheme, testGlobal.matcherInfo.sk) require.NoError(t, err, "tx.Sign() failed") return tx } func createExchangeV3WithProofsWithMixedOrders(t *testing.T, price1, price2, amount uint64) *proto.ExchangeWithProofs { - bo := proto.NewUnsignedOrderV3(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, uint64(price1), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + bo := proto.NewUnsignedOrderV3(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, price1, amount, 0, 0, 3, *testGlobal.asset2.asset) err := bo.Sign(proto.MainNetScheme, testGlobal.senderInfo.sk) require.NoError(t, err, "bo.Sign() failed") - so := proto.NewUnsignedOrderV4(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, uint64(price2), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + so := proto.NewUnsignedOrderV4(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, price2, amount, 0, 0, 3, *testGlobal.asset2.asset) err = so.Sign(proto.MainNetScheme, testGlobal.recipientInfo.sk) require.NoError(t, err, "so.Sign() failed") - tx := proto.NewUnsignedExchangeWithProofs(3, bo, so, uint64(price2), bo.Amount, 1, 2, defaultFee, defaultTimestamp) + tx := proto.NewUnsignedExchangeWithProofs(3, bo, so, price2, bo.Amount, 1, 2, defaultFee, defaultTimestamp) err = tx.Sign(proto.MainNetScheme, testGlobal.matcherInfo.sk) require.NoError(t, err, "tx.Sign() failed") return tx } func createExchangeV2WithProofsWithOrdersV3(t *testing.T, price, amount uint64) *proto.ExchangeWithProofs { - bo := proto.NewUnsignedOrderV3(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, uint64(price), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + bo := proto.NewUnsignedOrderV3(testGlobal.senderInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Buy, price, amount, 0, 0, 3, *testGlobal.asset2.asset) err := bo.Sign(proto.MainNetScheme, testGlobal.senderInfo.sk) require.NoError(t, err, "bo.Sign() failed") - so := proto.NewUnsignedOrderV3(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, uint64(price), uint64(amount), 0, 0, 3, *testGlobal.asset2.asset) + so := proto.NewUnsignedOrderV3(testGlobal.recipientInfo.pk, testGlobal.matcherInfo.pk, *testGlobal.asset0.asset, *testGlobal.asset1.asset, proto.Sell, price, amount, 0, 0, 3, *testGlobal.asset2.asset) err = so.Sign(proto.MainNetScheme, testGlobal.recipientInfo.sk) require.NoError(t, err, "so.Sign() failed") - tx := proto.NewUnsignedExchangeWithProofs(2, bo, so, uint64(price), bo.Amount, 1, 2, defaultFee, defaultTimestamp) + tx := proto.NewUnsignedExchangeWithProofs(2, bo, so, price, bo.Amount, 1, 2, defaultFee, defaultTimestamp) err = tx.Sign(proto.MainNetScheme, testGlobal.matcherInfo.sk) require.NoError(t, err, "tx.Sign() failed") return tx @@ -619,7 +619,7 @@ func TestCreateDiffExchangeWithProofsWithOrdersV3(t *testing.T) { }() tx := createExchangeWithProofsWithOrdersV3(t) - ch, err := to.td.createDiffExchange(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffExchange(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") price := tx.Price * tx.Amount / priceConstant @@ -702,15 +702,15 @@ func TestCreateDiffExchangeV3WithProofsWithOrdersV4(t *testing.T) { price := uint64(10 * priceConstant) tx3o4 := createExchangeWithProofsWithOrdersV4(t, 10*priceConstant, amount) - ch1, err := to.td.createDiffExchange(tx3o4, defaultDifferInfo(t)) + ch1, err := to.td.createDiffExchange(tx3o4, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") tx2o3 := createExchangeV2WithProofsWithOrdersV3(t, 10*priceConstant*priceConstant, amount) - ch2, err := to.td.createDiffExchange(tx2o3, defaultDifferInfo(t)) + ch2, err := to.td.createDiffExchange(tx2o3, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") tx3mo := createExchangeV3WithProofsWithMixedOrders(t, 10*priceConstant*priceConstant, 10*priceConstant, amount) - ch3, err := to.td.createDiffExchange(tx3mo, defaultDifferInfo(t)) + ch3, err := to.td.createDiffExchange(tx3mo, defaultDifferInfo()) assert.NoError(t, err, "createDiffExchange() failed") priceAmount := price * amount @@ -757,7 +757,7 @@ func TestCreateDiffLeaseWithSig(t *testing.T) { }() tx := createLeaseWithSig(t) - ch, err := to.td.createDiffLeaseWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffLeaseWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffLeaseWithSig() failed") correctDiff := txDiff{ @@ -791,7 +791,7 @@ func TestCreateDiffLeaseWithProofs(t *testing.T) { }() tx := createLeaseWithProofs(t) - ch, err := to.td.createDiffLeaseWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffLeaseWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffLeaseWithProofs() failed") correctDiff := txDiff{ @@ -825,13 +825,13 @@ func TestCreateDiffLeaseCancelWithSig(t *testing.T) { }() leaseTx := createLeaseWithSig(t) - info := defaultPerformerInfo(t) + info := defaultPerformerInfo() to.stor.addBlock(t, blockID0) err := to.tp.performLeaseWithSig(leaseTx, info) assert.NoError(t, err, "performLeaseWithSig failed") tx := createLeaseCancelWithSig(t, *leaseTx.ID) - ch, err := to.td.createDiffLeaseCancelWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffLeaseCancelWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffLeaseCancelWithSig() failed") correctDiff := txDiff{ @@ -865,13 +865,13 @@ func TestCreateDiffLeaseCancelWithProofs(t *testing.T) { }() leaseTx := createLeaseWithProofs(t) - info := defaultPerformerInfo(t) + info := defaultPerformerInfo() to.stor.addBlock(t, blockID0) err := to.tp.performLeaseWithProofs(leaseTx, info) assert.NoError(t, err, "performLeaseWithProofs failed") tx := createLeaseCancelWithProofs(t, *leaseTx.ID) - ch, err := to.td.createDiffLeaseCancelWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffLeaseCancelWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffLeaseCancelWithProofs() failed") correctDiff := txDiff{ @@ -909,7 +909,7 @@ func TestCreateDiffCreateAliasWithSig(t *testing.T) { }() tx := createCreateAliasWithSig(t) - ch, err := to.td.createDiffCreateAliasWithSig(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffCreateAliasWithSig(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffCreateAliasWithSig failed") correctDiff := txDiff{ @@ -945,7 +945,7 @@ func TestCreateDiffCreateAliasWithProofs(t *testing.T) { }() tx := createCreateAliasWithProofs(t) - ch, err := to.td.createDiffCreateAliasWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffCreateAliasWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffCreateAliasWithProofs failed") correctDiff := txDiff{ @@ -990,7 +990,7 @@ func TestCreateDiffMassTransferWithProofs(t *testing.T) { entriesNum := 66 entries := generateMassTransferEntries(t, entriesNum) tx := createMassTransferWithProofs(t, entries) - ch, err := to.td.createDiffMassTransferWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffMassTransferWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffMassTransferWithProofs failed") correctDiff := txDiff{ @@ -1035,7 +1035,7 @@ func TestCreateDiffDataWithProofs(t *testing.T) { }() tx := createDataWithProofs(t, 1) - ch, err := to.td.createDiffDataWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffDataWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffDataWithProofs failed") correctDiff := txDiff{ @@ -1067,7 +1067,7 @@ func TestCreateDiffSponsorshipWithProofs(t *testing.T) { }() tx := createSponsorshipWithProofs(t, 1000) - ch, err := to.td.createDiffSponsorshipWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffSponsorshipWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffSponsorshipWithProofs failed") correctDiff := txDiff{ @@ -1101,7 +1101,7 @@ func TestCreateDiffSetScriptWithProofs(t *testing.T) { }() tx := createSetScriptWithProofs(t) - ch, err := to.td.createDiffSetScriptWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffSetScriptWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffSetScriptWithProofs failed") correctDiff := txDiff{ @@ -1135,7 +1135,7 @@ func TestCreateDiffSetAssetScriptWithProofs(t *testing.T) { }() tx := createSetAssetScriptWithProofs(t) - ch, err := to.td.createDiffSetAssetScriptWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffSetAssetScriptWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffSetAssetScriptWithProofs failed") correctDiff := txDiff{ @@ -1193,11 +1193,11 @@ func TestCreateDiffInvokeScriptWithProofs(t *testing.T) { to.stor.createAsset(t, assetId) to.stor.activateSponsorship(t) - _, err := to.td.createDiffInvokeScriptWithProofs(tx, defaultDifferInfo(t)) + _, err := to.td.createDiffInvokeScriptWithProofs(tx, defaultDifferInfo()) assert.Error(t, err, "createDiffInvokeScriptWithProofs() did not fail with unsponsored asset") err = to.stor.entities.sponsoredAssets.sponsorAsset(assetId, 10, blockID0) assert.NoError(t, err, "sponsorAsset() failed") - ch, err := to.td.createDiffInvokeScriptWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffInvokeScriptWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffInvokeScriptWithProofs() failed with valid sponsored asset") feeInWaves, err := to.stor.entities.sponsoredAssets.sponsoredAssetToWaves(assetId, tx.Fee) @@ -1243,7 +1243,7 @@ func TestCreateDiffUpdateAssetInfoWithProofs(t *testing.T) { }() tx := createUpdateAssetInfoWithProofs(t) - ch, err := to.td.createDiffUpdateAssetInfoWithProofs(tx, defaultDifferInfo(t)) + ch, err := to.td.createDiffUpdateAssetInfoWithProofs(tx, defaultDifferInfo()) assert.NoError(t, err, "createDiffUpdateAssetInfoWithProofs() failed") correctDiff := txDiff{ diff --git a/pkg/state/transaction_performer.go b/pkg/state/transaction_performer.go index d4e9216f2..d4c70bcbb 100644 --- a/pkg/state/transaction_performer.go +++ b/pkg/state/transaction_performer.go @@ -194,7 +194,14 @@ func (tp *transactionPerformer) performLease(tx *proto.Lease, id *crypto.Digest, recipientAddr = tx.Recipient.Address } // Add leasing to lease state. - l := &leasing{true, tx.Amount, *recipientAddr, senderAddr} + l := &leasing{ + Sender: senderAddr, + Recipient: *recipientAddr, + Amount: tx.Amount, + Height: info.height, + Status: LeaseActive, + RecipientAlias: tx.Recipient.Alias, + } if err := tp.stor.leases.addLeasing(*id, l, info.blockID); err != nil { return errors.Wrap(err, "failed to add leasing") } @@ -217,8 +224,8 @@ func (tp *transactionPerformer) performLeaseWithProofs(transaction proto.Transac return tp.performLease(&tx.Lease, tx.ID, info) } -func (tp *transactionPerformer) performLeaseCancel(tx *proto.LeaseCancel, info *performerInfo) error { - if err := tp.stor.leases.cancelLeasing(tx.LeaseID, info.blockID, !info.initialisation); err != nil { +func (tp *transactionPerformer) performLeaseCancel(tx *proto.LeaseCancel, txID *crypto.Digest, info *performerInfo) error { + if err := tp.stor.leases.cancelLeasing(tx.LeaseID, info.blockID, info.height, txID, !info.initialisation); err != nil { return errors.Wrap(err, "failed to cancel leasing") } return nil @@ -229,7 +236,7 @@ func (tp *transactionPerformer) performLeaseCancelWithSig(transaction proto.Tran if !ok { return errors.New("failed to convert interface to LeaseCancelWithSig transaction") } - return tp.performLeaseCancel(&tx.LeaseCancel, info) + return tp.performLeaseCancel(&tx.LeaseCancel, tx.ID, info) } func (tp *transactionPerformer) performLeaseCancelWithProofs(transaction proto.Transaction, info *performerInfo) error { @@ -237,7 +244,7 @@ func (tp *transactionPerformer) performLeaseCancelWithProofs(transaction proto.T if !ok { return errors.New("failed to convert interface to LeaseCancelWithProofs transaction") } - return tp.performLeaseCancel(&tx.LeaseCancel, info) + return tp.performLeaseCancel(&tx.LeaseCancel, tx.ID, info) } func (tp *transactionPerformer) performCreateAlias(tx *proto.CreateAlias, info *performerInfo) error { diff --git a/pkg/state/transaction_performer_test.go b/pkg/state/transaction_performer_test.go index 3966be521..0832945ce 100644 --- a/pkg/state/transaction_performer_test.go +++ b/pkg/state/transaction_performer_test.go @@ -24,7 +24,7 @@ func createPerformerTestObjects(t *testing.T) (*performerTestObjects, []string) return &performerTestObjects{stor, tp}, path } -func defaultPerformerInfo(t *testing.T) *performerInfo { +func defaultPerformerInfo() *performerInfo { return &performerInfo{false, 0, blockID0} } @@ -40,7 +40,7 @@ func TestPerformIssueWithSig(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createIssueWithSig(t, 1000) - err := to.tp.performIssueWithSig(tx, defaultPerformerInfo(t)) + err := to.tp.performIssueWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performIssueWithSig() failed") to.stor.flush(t) assetInfo := assetInfo{ @@ -75,7 +75,7 @@ func TestPerformIssueWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createIssueWithProofs(t, 1000) - err := to.tp.performIssueWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performIssueWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performIssueWithProofs() failed") to.stor.flush(t) assetInfo := assetInfo{ @@ -110,7 +110,7 @@ func TestPerformReissueWithSig(t *testing.T) { assetInfo := to.stor.createAsset(t, testGlobal.asset0.asset.ID) tx := createReissueWithSig(t, 1000) - err := to.tp.performReissueWithSig(tx, defaultPerformerInfo(t)) + err := to.tp.performReissueWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performReissueWithSig() failed") to.stor.flush(t) assetInfo.reissuable = tx.Reissuable @@ -134,7 +134,7 @@ func TestPerformReissueWithProofs(t *testing.T) { assetInfo := to.stor.createAsset(t, testGlobal.asset0.asset.ID) tx := createReissueWithProofs(t, 1000) - err := to.tp.performReissueWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performReissueWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performReissueWithProofs() failed") to.stor.flush(t) assetInfo.reissuable = tx.Reissuable @@ -158,7 +158,7 @@ func TestPerformBurnWithSig(t *testing.T) { assetInfo := to.stor.createAsset(t, testGlobal.asset0.asset.ID) tx := createBurnWithSig(t) - err := to.tp.performBurnWithSig(tx, defaultPerformerInfo(t)) + err := to.tp.performBurnWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performBurnWithSig() failed") to.stor.flush(t) assetInfo.quantity.Sub(&assetInfo.quantity, big.NewInt(int64(tx.Amount))) @@ -181,7 +181,7 @@ func TestPerformBurnWithProofs(t *testing.T) { assetInfo := to.stor.createAsset(t, testGlobal.asset0.asset.ID) tx := createBurnWithProofs(t) - err := to.tp.performBurnWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performBurnWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performBurnWithProofs() failed") to.stor.flush(t) assetInfo.quantity.Sub(&assetInfo.quantity, big.NewInt(int64(tx.Amount))) @@ -204,7 +204,7 @@ func TestPerformExchange(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createExchangeWithSig(t) - err := to.tp.performExchange(tx, defaultPerformerInfo(t)) + err := to.tp.performExchange(tx, defaultPerformerInfo()) assert.NoError(t, err, "performExchange() failed") sellOrderId, err := tx.GetOrder2().GetID() @@ -260,14 +260,15 @@ func TestPerformLeaseWithSig(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createLeaseWithSig(t) - err := to.tp.performLeaseWithSig(tx, defaultPerformerInfo(t)) + err := to.tp.performLeaseWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithSig() failed") to.stor.flush(t) leasingInfo := &leasing{ - isActive: true, - leaseAmount: tx.Amount, - recipient: *tx.Recipient.Address, - sender: testGlobal.senderInfo.addr, + OriginTransactionID: tx.ID, + Status: LeaseActive, + Amount: tx.Amount, + Recipient: *tx.Recipient.Address, + Sender: testGlobal.senderInfo.addr, } info, err := to.stor.entities.leases.leasingInfo(*tx.ID, true) @@ -287,14 +288,15 @@ func TestPerformLeaseWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createLeaseWithProofs(t) - err := to.tp.performLeaseWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performLeaseWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithProofs() failed") to.stor.flush(t) leasingInfo := &leasing{ - isActive: true, - leaseAmount: tx.Amount, - recipient: *tx.Recipient.Address, - sender: testGlobal.senderInfo.addr, + OriginTransactionID: tx.ID, + Status: LeaseActive, + Amount: tx.Amount, + Recipient: *tx.Recipient.Address, + Sender: testGlobal.senderInfo.addr, } info, err := to.stor.entities.leases.leasingInfo(*tx.ID, true) @@ -314,17 +316,19 @@ func TestPerformLeaseCancelWithSig(t *testing.T) { to.stor.addBlock(t, blockID0) leaseTx := createLeaseWithSig(t) - err := to.tp.performLeaseWithSig(leaseTx, defaultPerformerInfo(t)) + err := to.tp.performLeaseWithSig(leaseTx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithSig() failed") to.stor.flush(t) + tx := createLeaseCancelWithSig(t, *leaseTx.ID) leasingInfo := &leasing{ - isActive: false, - leaseAmount: leaseTx.Amount, - recipient: *leaseTx.Recipient.Address, - sender: testGlobal.senderInfo.addr, + OriginTransactionID: leaseTx.ID, + Status: LeaseCanceled, + Amount: leaseTx.Amount, + Recipient: *leaseTx.Recipient.Address, + Sender: testGlobal.senderInfo.addr, + CancelTransactionID: tx.ID, } - tx := createLeaseCancelWithSig(t, *leaseTx.ID) - err = to.tp.performLeaseCancelWithSig(tx, defaultPerformerInfo(t)) + err = to.tp.performLeaseCancelWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseCancelWithSig() failed") to.stor.flush(t) info, err := to.stor.entities.leases.leasingInfo(*leaseTx.ID, true) @@ -344,17 +348,19 @@ func TestPerformLeaseCancelWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) leaseTx := createLeaseWithProofs(t) - err := to.tp.performLeaseWithProofs(leaseTx, defaultPerformerInfo(t)) + err := to.tp.performLeaseWithProofs(leaseTx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseWithProofs() failed") to.stor.flush(t) + tx := createLeaseCancelWithProofs(t, *leaseTx.ID) leasingInfo := &leasing{ - isActive: false, - leaseAmount: leaseTx.Amount, - recipient: *leaseTx.Recipient.Address, - sender: testGlobal.senderInfo.addr, + OriginTransactionID: leaseTx.ID, + Status: LeaseCanceled, + Amount: leaseTx.Amount, + Recipient: *leaseTx.Recipient.Address, + Sender: testGlobal.senderInfo.addr, + CancelTransactionID: tx.ID, } - tx := createLeaseCancelWithProofs(t, *leaseTx.ID) - err = to.tp.performLeaseCancelWithProofs(tx, defaultPerformerInfo(t)) + err = to.tp.performLeaseCancelWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performLeaseCancelWithProofs() failed") to.stor.flush(t) info, err := to.stor.entities.leases.leasingInfo(*leaseTx.ID, true) @@ -374,7 +380,7 @@ func TestPerformCreateAliasWithSig(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createCreateAliasWithSig(t) - err := to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo(t)) + err := to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithSig() failed") to.stor.flush(t) addr, err := to.stor.entities.aliases.addrByAlias(tx.Alias.Alias, true) @@ -382,7 +388,7 @@ func TestPerformCreateAliasWithSig(t *testing.T) { assert.Equal(t, testGlobal.senderInfo.addr, *addr, "invalid address by alias after performing CreateAliasWithSig transaction") // Test stealing aliases. - err = to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo(t)) + err = to.tp.performCreateAliasWithSig(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithSig() failed") to.stor.flush(t) err = to.stor.entities.aliases.disableStolenAliases() @@ -404,7 +410,7 @@ func TestPerformCreateAliasWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createCreateAliasWithProofs(t) - err := to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithProofs() failed") to.stor.flush(t) addr, err := to.stor.entities.aliases.addrByAlias(tx.Alias.Alias, true) @@ -412,7 +418,7 @@ func TestPerformCreateAliasWithProofs(t *testing.T) { assert.Equal(t, testGlobal.senderInfo.addr, *addr, "invalid address by alias after performing CreateAliasWithProofs transaction") // Test stealing aliases. - err = to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo(t)) + err = to.tp.performCreateAliasWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performCreateAliasWithProofs() failed") to.stor.flush(t) err = to.stor.entities.aliases.disableStolenAliases() @@ -436,9 +442,9 @@ func TestPerformDataWithProofs(t *testing.T) { tx := createDataWithProofs(t, 1) entry := &proto.IntegerDataEntry{Key: "TheKey", Value: int64(666)} - tx.Entries = proto.DataEntries([]proto.DataEntry{entry}) + tx.Entries = []proto.DataEntry{entry} - err := to.tp.performDataWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performDataWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performDataWithProofs() failed") to.stor.flush(t) @@ -460,7 +466,7 @@ func TestPerformSponsorshipWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createSponsorshipWithProofs(t, 1000) - err := to.tp.performSponsorshipWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performSponsorshipWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performSponsorshipWithProofs() failed") isSponsored, err := to.stor.entities.sponsoredAssets.newestIsSponsored(tx.AssetID, true) @@ -507,7 +513,7 @@ func TestPerformSetScriptWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createSetScriptWithProofs(t) - err := to.tp.performSetScriptWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performSetScriptWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performSetScriptWithProofs() failed") addr := testGlobal.senderInfo.addr @@ -571,7 +577,7 @@ func TestPerformSetAssetScriptWithProofs(t *testing.T) { to.stor.addBlock(t, blockID0) tx := createSetAssetScriptWithProofs(t) - err := to.tp.performSetAssetScriptWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performSetAssetScriptWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performSetAssetScriptWithProofs() failed") assetID := tx.AssetID @@ -653,7 +659,7 @@ func TestPerformUpdateAssetInfoWithProofs(t *testing.T) { assetInfo := to.stor.createAsset(t, testGlobal.asset0.asset.ID) tx := createUpdateAssetInfoWithProofs(t) - err := to.tp.performUpdateAssetInfoWithProofs(tx, defaultPerformerInfo(t)) + err := to.tp.performUpdateAssetInfoWithProofs(tx, defaultPerformerInfo()) assert.NoError(t, err, "performUpdateAssetInfoWithProofs() failed") to.stor.flush(t) assetInfo.name = tx.Name diff --git a/pkg/types/types.go b/pkg/types/types.go index b5e7cfe1a..2bb533c05 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -35,15 +35,19 @@ type TransactionWithBytes struct { // SmartState is a part of state used by smart contracts. type SmartState interface { + NewestScriptPKByAddr(addr proto.Address) (crypto.PublicKey, error) AddingBlockHeight() (uint64, error) NewestTransactionByID([]byte) (proto.Transaction, error) NewestTransactionHeightByID([]byte) (uint64, error) - + GetByteTree(recipient proto.Recipient) (proto.Script, error) + NewestRecipientToAddress(recipient proto.Recipient) (*proto.Address, error) + NewestAddrByAlias(alias proto.Alias) (proto.Address, error) + NewestLeasingInfo(id crypto.Digest) (*proto.LeaseInfo, error) + IsStateUntouched(account proto.Recipient) (bool, error) // NewestAccountBalance retrieves balance of address in specific currency, asset is asset's ID. // nil asset = Waves. - NewestAccountBalance(account proto.Recipient, asset []byte) (uint64, error) + NewestAccountBalance(account proto.Recipient, assetID []byte) (uint64, error) NewestFullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) - NewestAddrByAlias(alias proto.Alias) (proto.Address, error) RetrieveNewestIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) RetrieveNewestBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) RetrieveNewestStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) @@ -51,6 +55,7 @@ type SmartState interface { NewestAssetIsSponsored(assetID crypto.Digest) (bool, error) NewestAssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) NewestFullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) + NewestScriptByAsset(asset proto.OptionalAsset) (proto.Script, error) NewestHeaderByHeight(height proto.Height) (*proto.BlockHeader, error) BlockVRF(blockHeader *proto.BlockHeader, height proto.Height) ([]byte, error)