diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 90ee860c1..000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,43 +0,0 @@
-# Stage 1 of 2 stage [build]
-FROM golang:stretch
-
-ENV GOPATH /go
-ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
-
-RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
-
-WORKDIR /go/src/github.com/nebulasio/go-nebulas
-
-RUN apt-get update && \
- apt-get -yy -q install git build-essential protobuf-compiler sudo
-
-# Build Nebulas
-COPY . /go/src/github.com/nebulasio/go-nebulas
-
-RUN go get -u github.com/golang/dep/cmd/dep && \
- go get -u golang.org/x/tools/cmd/goimports && \
- make dep && \
- make deploy-v8 && \
- make build
-
-# Stage 2 of 2 [copy assets to thin image]
-FROM debian:stretch
-
-WORKDIR /nebulas
-
-ENV PATH /usr/local/bin:$PATH
-
-# Copy v8 libs from builder
-COPY --from=0 /usr/local/lib /usr/local/lib
-RUN ldconfig
-
-# Copy neb and crash reporter from builder
-COPY --from=0 /go/src/github.com/nebulasio/go-nebulas/neb /usr/local/bin/neb
-COPY --from=0 /go/src/github.com/nebulasio/go-nebulas/nebulas_crashreporter /usr/local/bin/nebulas_crashreporter
-
-# Copy conf & keydir to enable bootstrapping
-COPY --from=0 /go/src/github.com/nebulasio/go-nebulas/keydir /nebulas/keydir
-COPY --from=0 /go/src/github.com/nebulasio/go-nebulas/conf /nebulas/conf
-
-ENTRYPOINT ["/usr/local/bin/neb"]
-
diff --git a/Gopkg.lock b/Gopkg.lock
index 10d98d44f..f85651ca2 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -10,11 +10,7 @@
[[projects]]
branch = "master"
name = "github.com/agl/ed25519"
- packages = [
- ".",
- "edwards25519",
- "extra25519"
- ]
+ packages = [".","edwards25519","extra25519"]
revision = "5312a61534124124185d41f09206b9fef1d88403"
[[projects]]
@@ -44,10 +40,7 @@
[[projects]]
branch = "master"
name = "github.com/docker/spdystream"
- packages = [
- ".",
- "spdy"
- ]
+ packages = [".","spdy"]
revision = "bc6354cbbc295e925e4c611ffe90c1f287ee54db"
[[projects]]
@@ -58,10 +51,7 @@
[[projects]]
name = "github.com/gogo/protobuf"
- packages = [
- "io",
- "proto"
- ]
+ packages = ["io","proto"]
revision = "100ba4e885062801d56799d78530b73b178a78f3"
version = "v0.4"
@@ -74,16 +64,7 @@
[[projects]]
branch = "master"
name = "github.com/golang/protobuf"
- packages = [
- "jsonpb",
- "proto",
- "protoc-gen-go/descriptor",
- "ptypes",
- "ptypes/any",
- "ptypes/duration",
- "ptypes/struct",
- "ptypes/timestamp"
- ]
+ packages = ["jsonpb","proto","protoc-gen-go/descriptor","ptypes","ptypes/any","ptypes/duration","ptypes/struct","ptypes/timestamp"]
revision = "ae59567b9aab61b50b2590679a62c3c044030b61"
[[projects]]
@@ -92,6 +73,12 @@
packages = ["."]
revision = "553a641470496b2327abcac10b36396bd98e45c9"
+[[projects]]
+ branch = "master"
+ name = "github.com/google/keytransparency"
+ packages = ["core/crypto/vrf"]
+ revision = "e5573858922e6a9456ab5557779b37d30af56c4c"
+
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
@@ -131,33 +118,18 @@
[[projects]]
branch = "master"
name = "github.com/hashicorp/golang-lru"
- packages = [
- ".",
- "simplelru"
- ]
+ packages = [".","simplelru"]
revision = "0a025b7e63adc15a622f29b0b2c4c3848243bbf6"
[[projects]]
branch = "master"
name = "github.com/huin/goupnp"
- packages = [
- ".",
- "dcps/internetgateway1",
- "dcps/internetgateway2",
- "httpu",
- "scpd",
- "soap",
- "ssdp"
- ]
+ packages = [".","dcps/internetgateway1","dcps/internetgateway2","httpu","scpd","soap","ssdp"]
revision = "5b7801abd885f2f7458add715aee47e7df5370a0"
[[projects]]
name = "github.com/influxdata/influxdb"
- packages = [
- "client",
- "models",
- "pkg/escape"
- ]
+ packages = ["client","models","pkg/escape"]
revision = "6d2685d1738277a1c2672fc58df7994627769be6"
version = "v1.4.2"
@@ -200,12 +172,7 @@
[[projects]]
branch = "master"
name = "github.com/jbenet/goprocess"
- packages = [
- ".",
- "context",
- "periodic",
- "ratelimit"
- ]
+ packages = [".","context","periodic","ratelimit"]
revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b"
[[projects]]
@@ -229,20 +196,13 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-libp2p"
- packages = [
- "p2p/host/basic",
- "p2p/protocol/identify",
- "p2p/protocol/identify/pb"
- ]
+ packages = ["p2p/host/basic","p2p/protocol/identify","p2p/protocol/identify/pb"]
revision = "edb6434ddf456f58fbe2538d5336435a23915bd9"
[[projects]]
branch = "master"
name = "github.com/libp2p/go-libp2p-circuit"
- packages = [
- ".",
- "pb"
- ]
+ packages = [".","pb"]
revision = "4730183d80def7bc574e1b486b1f6e97a5c67bb9"
[[projects]]
@@ -253,10 +213,7 @@
[[projects]]
name = "github.com/libp2p/go-libp2p-crypto"
- packages = [
- ".",
- "pb"
- ]
+ packages = [".","pb"]
revision = "e89e1de117dd65c6129d99d1d853f48bc847cf17"
[[projects]]
@@ -284,10 +241,7 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-libp2p-kbucket"
- packages = [
- ".",
- "keyspace"
- ]
+ packages = [".","keyspace"]
revision = "5ce3bb926eeeadf90708fec12343cbf858ed24b6"
[[projects]]
@@ -299,11 +253,7 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-libp2p-metrics"
- packages = [
- ".",
- "conn",
- "stream"
- ]
+ packages = [".","conn","stream"]
revision = "1ac87496e992290629575655bea4330dd4ab211e"
[[projects]]
@@ -324,10 +274,7 @@
[[projects]]
name = "github.com/libp2p/go-libp2p-peerstore"
- packages = [
- ".",
- "addr"
- ]
+ packages = [".","addr"]
revision = "89838b9577a2b83eb3e1632c162cfd0daeee58e3"
[[projects]]
@@ -339,10 +286,7 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-libp2p-secio"
- packages = [
- ".",
- "pb"
- ]
+ packages = [".","pb"]
revision = "0cdc8339ad2e4f7f32e67b6a481bfbd48be5c704"
[[projects]]
@@ -365,10 +309,7 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-msgio"
- packages = [
- ".",
- "mpool"
- ]
+ packages = [".","mpool"]
revision = "d82125c9907e1365775356505f14277d47dfd4d6"
[[projects]]
@@ -380,11 +321,7 @@
[[projects]]
branch = "master"
name = "github.com/libp2p/go-reuseport"
- packages = [
- ".",
- "poll",
- "singlepoll"
- ]
+ packages = [".","poll","singlepoll"]
revision = "2a863ed0ff1167e16ff48dd1de862b180af3bf27"
[[projects]]
@@ -449,10 +386,7 @@
[[projects]]
branch = "master"
name = "github.com/multiformats/go-multicodec"
- packages = [
- ".",
- "json"
- ]
+ packages = [".","json"]
revision = "fd289ac41fba9e574f214ab2a808a1678ef8810c"
[[projects]]
@@ -476,11 +410,7 @@
[[projects]]
branch = "master"
name = "github.com/nebulasio/grpc-gateway"
- packages = [
- "runtime",
- "runtime/internal",
- "utilities"
- ]
+ packages = ["runtime","runtime/internal","utilities"]
revision = "9ed0e3fde466911904aef99bf3ecc8197d54b21d"
[[projects]]
@@ -504,10 +434,7 @@
[[projects]]
branch = "master"
name = "github.com/rcrowley/go-metrics"
- packages = [
- ".",
- "exp"
- ]
+ packages = [".","exp"]
revision = "1f30fe9094a513ce4c700b9a54458bbb0c96996c"
[[projects]]
@@ -519,15 +446,7 @@
[[projects]]
branch = "master"
name = "github.com/robertkrimen/otto"
- packages = [
- ".",
- "ast",
- "dbg",
- "file",
- "parser",
- "registry",
- "token"
- ]
+ packages = [".","ast","dbg","file","parser","registry","token"]
revision = "68a29f5e29b18d7367e686c43cf74eba1900f548"
[[projects]]
@@ -557,29 +476,13 @@
[[projects]]
branch = "master"
name = "github.com/stretchr/testify"
- packages = [
- "assert",
- "require"
- ]
+ packages = ["assert","require"]
revision = "890a5c3458b43e6104ff5da8dfa139d013d77544"
[[projects]]
branch = "master"
name = "github.com/syndtr/goleveldb"
- packages = [
- "leveldb",
- "leveldb/cache",
- "leveldb/comparer",
- "leveldb/errors",
- "leveldb/filter",
- "leveldb/iterator",
- "leveldb/journal",
- "leveldb/memdb",
- "leveldb/opt",
- "leveldb/storage",
- "leveldb/table",
- "leveldb/util"
- ]
+ packages = ["leveldb","leveldb/cache","leveldb/comparer","leveldb/errors","leveldb/filter","leveldb/iterator","leveldb/journal","leveldb/memdb","leveldb/opt","leveldb/storage","leveldb/table","leveldb/util"]
revision = "b89cc31ef7977104127d34c1bd31ebd1a9db2199"
[[projects]]
@@ -594,12 +497,6 @@
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
version = "v1.20.0"
-[[projects]]
- branch = "master"
- name = "github.com/vrischmann/go-metrics-influxdb"
- packages = ["."]
- revision = "43af8332c303f62ef62663b02b3b7d8a9802002a"
-
[[projects]]
branch = "master"
name = "github.com/whyrusleeping/go-logging"
@@ -669,129 +566,48 @@
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
- packages = [
- "blake2s",
- "blowfish",
- "pbkdf2",
- "ripemd160",
- "scrypt",
- "sha3",
- "ssh/terminal"
- ]
+ packages = ["blake2s","blowfish","pbkdf2","ripemd160","scrypt","sha3","ssh/terminal"]
revision = "faadfbdc035307d901e69eea569f5dda451a3ee3"
[[projects]]
branch = "master"
name = "golang.org/x/net"
- packages = [
- "context",
- "html",
- "html/atom",
- "html/charset",
- "http2",
- "http2/hpack",
- "idna",
- "internal/timeseries",
- "lex/httplex",
- "netutil",
- "trace"
- ]
+ packages = ["context","html","html/atom","html/charset","http2","http2/hpack","idna","internal/timeseries","lex/httplex","netutil","trace"]
revision = "8351a756f30f1297fe94bbf4b767ec589c6ea6d0"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
- packages = [
- "unix",
- "windows"
- ]
+ packages = ["unix","windows"]
revision = "062cd7e4e68206d8bab9b18396626e855c992658"
[[projects]]
branch = "master"
name = "golang.org/x/text"
- packages = [
- "collate",
- "collate/build",
- "encoding",
- "encoding/charmap",
- "encoding/htmlindex",
- "encoding/internal",
- "encoding/internal/identifier",
- "encoding/japanese",
- "encoding/korean",
- "encoding/simplifiedchinese",
- "encoding/traditionalchinese",
- "encoding/unicode",
- "internal/colltab",
- "internal/gen",
- "internal/tag",
- "internal/triegen",
- "internal/ucd",
- "internal/utf8internal",
- "language",
- "runes",
- "secure/bidirule",
- "transform",
- "unicode/bidi",
- "unicode/cldr",
- "unicode/norm",
- "unicode/rangetable"
- ]
+ packages = ["collate","collate/build","encoding","encoding/charmap","encoding/htmlindex","encoding/internal","encoding/internal/identifier","encoding/japanese","encoding/korean","encoding/simplifiedchinese","encoding/traditionalchinese","encoding/unicode","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","internal/utf8internal","language","runes","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
revision = "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
- packages = [
- "googleapis/api/annotations",
- "googleapis/rpc/status"
- ]
+ packages = ["googleapis/api/annotations","googleapis/rpc/status"]
revision = "f676e0f3ac6395ff1a529ae59a6670878a8371a6"
[[projects]]
name = "google.golang.org/grpc"
- packages = [
- ".",
- "balancer",
- "balancer/base",
- "balancer/roundrobin",
- "codes",
- "connectivity",
- "credentials",
- "encoding",
- "grpclb/grpc_lb_v1/messages",
- "grpclog",
- "internal",
- "keepalive",
- "metadata",
- "naming",
- "peer",
- "reflection",
- "reflection/grpc_reflection_v1alpha",
- "resolver",
- "resolver/dns",
- "resolver/passthrough",
- "stats",
- "status",
- "tap",
- "transport"
- ]
+ packages = [".","balancer","balancer/base","balancer/roundrobin","codes","connectivity","credentials","encoding","grpclb/grpc_lb_v1/messages","grpclog","internal","keepalive","metadata","naming","peer","reflection","reflection/grpc_reflection_v1alpha","resolver","resolver/dns","resolver/passthrough","stats","status","tap","transport"]
revision = "6b51017f791ae1cfbec89c52efdf444b13b550ef"
version = "v1.9.2"
[[projects]]
name = "gopkg.in/sourcemap.v1"
- packages = [
- ".",
- "base64vlq"
- ]
+ packages = [".","base64vlq"]
revision = "6e83acea0053641eff084973fee085f0c193c61a"
version = "v1.0.5"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "3cbb9060c41566687af55087832faa959bbf5e39cb4349bb1de287051e43b585"
+ inputs-digest = "105cf7ff893a2ebe6f3323ec78756a46b9bc5f7dc0708b4ff00a04bef0f8faaf"
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/account/manager.go b/account/manager.go
index f33114b8b..d61d8daa5 100644
--- a/account/manager.go
+++ b/account/manager.go
@@ -21,6 +21,9 @@ package account
import (
"errors"
+ "github.com/nebulasio/go-nebulas/crypto/hash"
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1/vrf/secp256k1VRF"
+
"github.com/nebulasio/go-nebulas/util/byteutils"
"path/filepath"
@@ -386,6 +389,41 @@ func (m *Manager) SignBlock(addr *core.Address, block *core.Block) error {
return block.Sign(signature)
}
+// GenerateRandomSeed generate rand
+func (m *Manager) GenerateRandomSeed(addr *core.Address, args ...[]byte) (vrfSeed, vrfProof []byte, err error) {
+
+ key, err := m.ks.GetUnlocked(addr.String())
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "err": err,
+ }).Error("Failed to get unlocked private key to generate block rand.")
+ return nil, nil, ErrAccountIsLocked
+ }
+
+ _, err = crypto.NewSignature(m.signatureAlg)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ seckey, err := key.(keystore.PrivateKey).Encoded()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ signer, err := secp256k1VRF.NewVRFSignerFromRawKey(seckey)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ data := hash.Sha3256(args...)
+
+ seed, proof := signer.Evaluate(data)
+ if proof == nil {
+ return nil, nil, secp256k1VRF.ErrEvaluateFailed
+ }
+ return seed[:], proof, nil
+}
+
// SignTransactionWithPassphrase sign transaction with the from passphrase
func (m *Manager) SignTransactionWithPassphrase(addr *core.Address, tx *core.Transaction, passphrase []byte) error {
// check sign addr is tx's from addr
diff --git a/cmd/neb/main.go b/cmd/neb/main.go
index f19505f2d..0c65227f6 100644
--- a/cmd/neb/main.go
+++ b/cmd/neb/main.go
@@ -27,6 +27,7 @@ import (
"syscall"
"time"
+ "github.com/nebulasio/go-nebulas/core"
"github.com/nebulasio/go-nebulas/neblet"
"github.com/nebulasio/go-nebulas/util/logging"
"github.com/urfave/cli"
@@ -84,6 +85,8 @@ func neb(ctx *cli.Context) error {
logging.Init(n.Config().App.LogFile, n.Config().App.LogLevel, n.Config().App.LogAge)
+ core.SetCompatibilityOptions(n.Config().Chain.ChainId)
+
// enable crash report if open the switch and configure the url
if n.Config().App.EnableCrashReport && len(n.Config().App.CrashReportUrl) > 0 {
InitCrashReporter(n.Config().App)
diff --git a/cmd/network/main.go b/cmd/network/main.go
index 29a1a9205..6ceb041bf 100644
--- a/cmd/network/main.go
+++ b/cmd/network/main.go
@@ -29,6 +29,7 @@ import (
"time"
"github.com/libp2p/go-libp2p-interface-conn"
+ "github.com/nebulasio/go-nebulas/core"
"github.com/nebulasio/go-nebulas/metrics"
"github.com/nebulasio/go-nebulas/neblet"
"github.com/nebulasio/go-nebulas/net"
@@ -108,6 +109,8 @@ func run(mode, configPath string, packageSize, concurrentMessageCount, totalMess
// init log.
logging.Init(config.App.LogFile, config.App.LogLevel, config.App.LogAge)
+ core.SetCompatibilityOptions(config.Chain.ChainId)
+
// neblet.
neblet, _ := neblet.New(config)
netService, err := net.NewNebService(neblet)
diff --git a/conf/default/config.conf b/conf/default/config.conf
index 8deece1d3..15b310cee 100644
--- a/conf/default/config.conf
+++ b/conf/default/config.conf
@@ -21,7 +21,7 @@ rpc {
http_listen: ["0.0.0.0:8685"]
http_module: ["api","admin"]
# HTTP CORS allowed origins
- # http_cors: []
+ http_cors: ["*"]
}
app {
@@ -29,7 +29,7 @@ app {
log_file: "logs"
enable_crash_report: true
crash_report_url: "https://crashreport.nebulas.io"
- pprof:{
+ pprof:{
http_listen: "0.0.0.0:8888"
}
}
diff --git a/consensus/dpos/dpos.go b/consensus/dpos/dpos.go
index b65779d84..fb0ccd7d3 100644
--- a/consensus/dpos/dpos.go
+++ b/consensus/dpos/dpos.go
@@ -56,6 +56,7 @@ var (
ErrGenerateNextConsensusState = errors.New("Failed to generate next consensus state")
ErrDoubleBlockMinted = errors.New("double block minted")
ErrAppendNewBlockFailed = errors.New("failed to append new block to real chain")
+ ErrInvalidArgument = errors.New("invalid argument")
)
// Metrics
@@ -375,33 +376,72 @@ func (dpos *Dpos) VerifyBlock(block *core.Block) error {
if err := verifyBlockSign(miner, block); err != nil {
return err
}
+
+ // check block random
+ if block.Height() >= core.RandomAvailableHeight && !block.HasRandomSeed() {
+ logging.VLog().WithFields(logrus.Fields{
+ "blockHeight": block.Height(),
+ "compatibleHeight": core.RandomAvailableHeight,
+ }).Debug("No random found in block header.")
+ return core.ErrInvalidBlockRandom
+ }
+
dpos.slot.Add(block.Timestamp(), block)
return nil
}
-func (dpos *Dpos) signBlock(block *core.Block) error {
+func (dpos *Dpos) generateRandomSeed(block *core.Block, adminService rpcpb.AdminServiceClient) error {
if dpos.enableRemoteSignServer == true {
- conn, err := rpc.Dial(dpos.remoteSignServer)
- if err != nil {
- return err
+ if adminService == nil {
+ return ErrInvalidArgument
}
- adminService := rpcpb.NewAdminServiceClient(conn)
- alg := keystore.SECP256K1
- resp, err := adminService.SignHash(
+ // generate VRF hash,proof
+ random, err := adminService.GenerateRandomSeed(
context.Background(),
- &rpcpb.SignHashRequest{
- Address: dpos.miner.String(),
- Hash: block.Hash(),
- Alg: uint32(alg),
+ &rpcpb.GenerateRandomSeedRequest{
+ Address: dpos.miner.String(),
+ ParentHash: block.ParentHash(),
+ Height: block.Height(),
})
- conn.Close()
if err != nil {
return err
}
- block.SetSignature(alg, resp.Data)
+ block.SetRandomSeed(random.VrfSeed, random.VrfProof)
return nil
}
- return dpos.am.SignBlock(dpos.miner, block)
+
+ // generate VRF hash,proof
+ inputs, err := dpos.chain.GetInputForVRFSigner(block.ParentHash(), block.Height())
+ if err != nil {
+ return err
+ }
+ vrfSeed, vrfProof, err := dpos.am.GenerateRandomSeed(dpos.miner, inputs...)
+ if err != nil {
+ return err
+ }
+ block.SetRandomSeed(vrfSeed, vrfProof)
+
+ return nil
+}
+
+func (dpos *Dpos) remoteSignBlock(block *core.Block, adminService rpcpb.AdminServiceClient) error {
+ if adminService == nil {
+ return ErrInvalidArgument
+ }
+ alg := keystore.SECP256K1
+ resp, err := adminService.SignHash(
+ context.Background(),
+ &rpcpb.SignHashRequest{
+ Address: dpos.miner.String(),
+ Hash: block.Hash(),
+ Alg: uint32(alg),
+ })
+ if err != nil {
+ return err
+ }
+
+ block.SetSignature(alg, resp.Data)
+ return nil
}
func (dpos *Dpos) unlock(passphrase string) error {
@@ -425,6 +465,24 @@ func (dpos *Dpos) newBlock(tail *core.Block, consensusState state.ConsensusState
return nil, err
}
+ var adminService rpcpb.AdminServiceClient
+ if dpos.enableRemoteSignServer == true {
+ conn, err := rpc.Dial(dpos.remoteSignServer)
+ defer func() {
+ if conn != nil {
+ conn.Close()
+ }
+ }()
+ if err != nil {
+ return nil, err
+ }
+ adminService = rpcpb.NewAdminServiceClient(conn)
+ }
+
+ if block.Height() >= core.RandomAvailableHeight {
+ dpos.generateRandomSeed(block, adminService)
+ }
+
block.WorldState().SetConsensusState(consensusState)
block.SetTimestamp(consensusState.TimeStamp())
block.CollectTransactions(deadlineInMs)
@@ -436,7 +494,13 @@ func (dpos *Dpos) newBlock(tail *core.Block, consensusState state.ConsensusState
go block.ReturnTransactions()
return nil, err
}
- if err = dpos.signBlock(block); err != nil {
+
+ if dpos.enableRemoteSignServer == true {
+ err = dpos.remoteSignBlock(block, adminService)
+ } else {
+ err = dpos.am.SignBlock(dpos.miner, block)
+ }
+ if err != nil {
logging.CLog().WithFields(logrus.Fields{
"miner": dpos.miner,
"block": block,
@@ -648,3 +712,8 @@ func (dpos *Dpos) findProposer(now int64) (proposer byteutils.Hash, err error) {
}
return proposer, nil
}
+
+// NumberOfBlocksInDynasty number of blocks in one dynasty
+func (dpos *Dpos) NumberOfBlocksInDynasty() uint64 {
+ return uint64(DynastyIntervalInMs) / uint64(BlockIntervalInMs)
+}
diff --git a/core/address.go b/core/address.go
index 37e9c926b..0e5535c49 100644
--- a/core/address.go
+++ b/core/address.go
@@ -27,6 +27,9 @@ import (
// AddressType address type
type AddressType byte
+// UndefinedAddressType undefined
+const UndefinedAddressType AddressType = 0x00
+
// address type enum
const (
AccountAddress AddressType = 0x57 + iota
@@ -151,6 +154,9 @@ func (a *Address) Equals(b *Address) bool {
// Type return the type of address.
func (a *Address) Type() AddressType {
+ if len(a.address) <= AddressTypeIndex {
+ return UndefinedAddressType
+ }
return AddressType(a.address[AddressTypeIndex])
}
diff --git a/core/block.go b/core/block.go
index b5dfcab3a..29f28e83a 100644
--- a/core/block.go
+++ b/core/block.go
@@ -74,6 +74,9 @@ type BlockHeader struct {
// sign
alg keystore.Algorithm
sign byteutils.Hash
+
+ // rand
+ random *corepb.Random
}
// ToProto converts domain BlockHeader to proto BlockHeader
@@ -90,6 +93,7 @@ func (b *BlockHeader) ToProto() (proto.Message, error) {
ChainId: b.chainID,
Alg: uint32(b.alg),
Sign: b.sign,
+ Random: b.random,
}, nil
}
@@ -121,6 +125,7 @@ func (b *BlockHeader) FromProto(msg proto.Message) error {
b.alg = alg
b.sign = msg.Sign
+ b.random = msg.Random
return nil
}
return ErrInvalidProtoToBlockHeader
@@ -189,6 +194,13 @@ func (block *Block) FromProto(msg proto.Message) error {
if err := block.header.FromProto(msg.Header); err != nil {
return err
}
+ if msg.Height >= RandomAvailableHeight && !block.HasRandomSeed() {
+ logging.VLog().WithFields(logrus.Fields{
+ "blockHeight": msg.Height,
+ "compatibleHeight": RandomAvailableHeight,
+ }).Debug("No random found in block header.")
+ return ErrInvalidProtoToBlockHeader
+ }
block.transactions = make(Transactions, len(msg.Transactions))
for idx, v := range msg.Transactions {
if v != nil {
@@ -227,6 +239,7 @@ func NewBlock(chainID uint32, coinbase *Address, parent *Block) (*Block, error)
coinbase: coinbase,
timestamp: time.Now().Unix(),
consensusRoot: &consensuspb.ConsensusRoot{},
+ random: &corepb.Random{},
},
transactions: make(Transactions, 0),
dependency: dag.NewDag(),
@@ -270,6 +283,19 @@ func (block *Block) Sign(signature keystore.Signature) error {
return nil
}
+// SetRandomSeed set block.header.random
+func (block *Block) SetRandomSeed(vrfseed, vrfproof []byte) {
+ block.header.random = &corepb.Random{
+ VrfSeed: vrfseed,
+ VrfProof: vrfproof,
+ }
+}
+
+// HasRandomSeed check random if exists
+func (block *Block) HasRandomSeed() bool {
+ return block.header.random != nil && block.header.random.VrfSeed != nil && block.header.random.VrfProof != nil
+}
+
// ChainID returns block's chainID
func (block *Block) ChainID() uint32 {
return block.header.chainID
@@ -355,6 +381,24 @@ func (block *Block) Transactions() Transactions {
return block.transactions
}
+// RandomSeed block random seed (VRF)
+func (block *Block) RandomSeed() string {
+ if block.height >= RandomAvailableHeight {
+ return byteutils.Hex(block.header.random.VrfSeed)
+ }
+ return ""
+}
+
+// RandomAvailable check if Math.random available in contract
+func (block *Block) RandomAvailable() bool {
+ return block.height >= RandomAvailableHeight
+}
+
+// DateAvailable check if date available in contract
+func (block *Block) DateAvailable() bool {
+ return block.height >= DateAvailableHeight
+}
+
// LinkParentBlock link parent block, return true if hash is the same; false otherwise.
func (block *Block) LinkParentBlock(chain *BlockChain, parentBlock *Block) error {
if !block.ParentHash().Equals(parentBlock.Hash()) {
@@ -750,7 +794,16 @@ func (block *Block) Seal() error {
}
func (block *Block) String() string {
- return fmt.Sprintf(`{"height": %d, "hash": "%s", "parent_hash": "%s", "acc_root": "%s", "timestamp": %d, "tx": %d, "miner": "%s"}`,
+ random := ""
+ if block.height >= RandomAvailableHeight && block.header.random != nil {
+ if block.header.random.VrfSeed != nil {
+ random += "/vrf_seed/" + byteutils.Hex(block.header.random.VrfSeed)
+ }
+ if block.header.random.VrfProof != nil {
+ random += "/vrf_proof/" + byteutils.Hex(block.header.random.VrfProof)
+ }
+ }
+ return fmt.Sprintf(`{"height": %d, "hash": "%s", "parent_hash": "%s", "acc_root": "%s", "timestamp": %d, "tx": %d, "miner": "%s", "random": "%s"}`,
block.height,
block.header.hash,
block.header.parentHash,
@@ -758,6 +811,7 @@ func (block *Block) String() string {
block.header.timestamp,
len(block.transactions),
byteutils.Hash(block.header.consensusRoot.Proposer).Base58(),
+ random,
)
}
diff --git a/core/block_pool.go b/core/block_pool.go
index 85737a7eb..0c47702bc 100644
--- a/core/block_pool.go
+++ b/core/block_pool.go
@@ -19,12 +19,16 @@
package core
import (
+ "bytes"
"sync"
"time"
"github.com/gogo/protobuf/proto"
lru "github.com/hashicorp/golang-lru"
"github.com/nebulasio/go-nebulas/core/pb"
+ "github.com/nebulasio/go-nebulas/crypto"
+ "github.com/nebulasio/go-nebulas/crypto/hash"
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1/vrf/secp256k1VRF"
"github.com/nebulasio/go-nebulas/net"
"github.com/nebulasio/go-nebulas/util/byteutils"
@@ -451,7 +455,6 @@ func (pool *BlockPool) push(sender string, block *Block) error {
cache.Remove(lb.hash.Hex())
return err
}
-
// remove allBlocks from cache.
for _, v := range allBlocks {
cache.Remove(v.Hash().Hex())
@@ -461,6 +464,46 @@ func (pool *BlockPool) push(sender string, block *Block) error {
return pool.bc.ConsensusHandler().ForkChoice()
}
+func vrfProof(block *Block, args [][]byte) error {
+ signature, err := crypto.NewSignature(block.Alg())
+ if err != nil {
+ return err
+ }
+ pub, err := signature.RecoverPublic(block.Hash(), block.Signature())
+ if err != nil {
+ return err
+ }
+ pubdata, err := pub.Encoded()
+ if err != nil {
+ return err
+ }
+
+ verifier, err := secp256k1VRF.NewVRFVerifierFromRawKey(pubdata)
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "err": err,
+ }).Error("Failed to new VRF verifier.")
+ return err
+ }
+
+ data := hash.Sha3256(args...)
+ index, err := verifier.ProofToHash(data, block.header.random.VrfProof)
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "err": err,
+ }).Error("Failed to calculate VRF proof.")
+ return err
+ }
+
+ if !bytes.Equal(index[:], block.header.random.VrfSeed) {
+ logging.VLog().WithFields(logrus.Fields{
+ "block": block,
+ }).Error("VRF proof failed.")
+ return ErrVRFProofFailed
+ }
+ return nil
+}
+
func (pool *BlockPool) setBlockChain(bc *BlockChain) {
pool.bc = bc
}
@@ -491,6 +534,60 @@ func (lb *linkedBlock) travelToLinkAndReturnAllValidBlocks(parentBlock *Block) (
return nil, nil, err
}
+ // verify vrf
+ if lb.block.height >= RandomAvailableHeight {
+ // prepare vrf inputs
+ inputs := make([][]byte, 0)
+
+ nob := lb.chain.ConsensusHandler().NumberOfBlocksInDynasty()
+ i := uint64(0)
+ tmp := lb
+ for i < nob*2 && tmp != nil {
+ i++
+ tmp = tmp.parentBlock
+ }
+ if tmp == nil {
+ if lb.block.height > nob*2 {
+ b := lb.chain.GetBlockOnCanonicalChainByHeight(lb.block.height - nob*2)
+ if b == nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "blockHeight": lb.block.height,
+ "targetHeight": lb.block.height - nob,
+ "numOfBlocksInDynasty": nob,
+ }).Error("Block not found, unexpected error.")
+ metricsUnexpectedBehavior.Update(1)
+ return nil, nil, ErrNotBlockInCanonicalChain
+ }
+ inputs = append(inputs, b.Hash())
+ } else {
+ inputs = append(inputs, lb.chain.GenesisBlock().Hash())
+ }
+ } else {
+ inputs = append(inputs, tmp.block.Hash())
+ }
+
+ if parentBlock.height >= RandomAvailableHeight {
+ if !parentBlock.HasRandomSeed() {
+ logging.VLog().WithFields(logrus.Fields{
+ "parent": parentBlock,
+ }).Error("Parent block has no random seed, unexpected error.")
+ metricsUnexpectedBehavior.Update(1)
+ return nil, nil, ErrInvalidBlockRandom
+ }
+ inputs = append(inputs, parentBlock.header.random.VrfSeed)
+ } else {
+ inputs = append(inputs, lb.chain.GenesisBlock().Hash())
+ }
+
+ if err := vrfProof(lb.block, inputs); err != nil {
+ logging.CLog().WithFields(logrus.Fields{
+ "err": err,
+ "lb.block": lb.block,
+ }).Error("VRF proof failed.")
+ return nil, nil, ErrVRFProofFailed
+ }
+ }
+
if err := lb.block.VerifyExecution(); err != nil {
logging.VLog().WithFields(logrus.Fields{
"block": lb.block,
diff --git a/core/block_test.go b/core/block_test.go
index f397ba9bd..0c822d61f 100644
--- a/core/block_test.go
+++ b/core/block_test.go
@@ -199,6 +199,9 @@ func (c *mockConsensus) NewState(root *consensuspb.ConsensusRoot, stor storage.S
func (c *mockConsensus) GenesisConsensusState(*BlockChain, *corepb.Genesis) (state.ConsensusState, error) {
return newMockConsensusState(0)
}
+func (c *mockConsensus) NumberOfBlocksInDynasty() uint64 {
+ return 210
+}
type mockManager struct{}
@@ -219,6 +222,9 @@ func (m mockManager) Update(*Address, []byte, []byte) error { return nil }
func (m mockManager) Load([]byte, []byte) (*Address, error) { return nil, nil }
func (m mockManager) Import([]byte, []byte) (*Address, error) { return nil, nil }
func (m mockManager) Remove(*Address, []byte) error { return nil }
+func (m mockManager) GenerateRandomSeed(addr *Address, args ...[]byte) (vrfSeed, vrfProof []byte, err error) {
+ return nil, nil, nil
+}
var (
received = []byte{}
diff --git a/core/blockchain.go b/core/blockchain.go
index a47d7b749..a0ecbe6ca 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -19,6 +19,8 @@
package core
import (
+ "crypto/rand"
+ "io"
"strings"
"time"
@@ -76,8 +78,6 @@ type BlockChain struct {
}
const (
- // TestNetID chain id for test net.
- TestNetID = 1
// EagleNebula chain id for 1.x
EagleNebula = 1 << 4
@@ -470,6 +470,48 @@ func (bc *BlockChain) GetBlockOnCanonicalChainByHash(blockHash byteutils.Hash) *
return blockByHeight
}
+// GetInputForVRFSigner returns [ getBlock(block.height - 2 * dynasty.size).hash, block.parent.seed ]
+func (bc *BlockChain) GetInputForVRFSigner(parentHash byteutils.Hash, height uint64) (out [][]byte, err error) {
+ if parentHash == nil || height < RandomAvailableHeight {
+ return nil, ErrInvalidArgument
+ }
+
+ nob := bc.consensusHandler.NumberOfBlocksInDynasty()
+ if height > nob*2 {
+ b := bc.GetBlockOnCanonicalChainByHeight(height - nob*2)
+ if b == nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "blockHeight": height,
+ "targetHeight": height - nob,
+ "numOfBlocksInDynasty": nob,
+ }).Error("Block not found.")
+ return nil, ErrNotBlockInCanonicalChain
+ }
+ out = append(out, b.Hash())
+ } else {
+ out = append(out, bc.GenesisBlock().Hash())
+ }
+
+ parent := bc.GetBlockOnCanonicalChainByHash(parentHash)
+ if parent == nil || parent.height+1 != height {
+ return nil, ErrInvalidBlockHash
+ }
+
+ if parent.height >= RandomAvailableHeight {
+ if !parent.HasRandomSeed() {
+ logging.VLog().WithFields(logrus.Fields{
+ "parent": parent,
+ }).Error("Parent block has no random seed, unexpected error.")
+ metricsUnexpectedBehavior.Update(1)
+ return nil, ErrInvalidBlockRandom
+ }
+ out = append(out, parent.header.random.VrfSeed)
+ } else {
+ out = append(out, bc.GenesisBlock().Hash())
+ }
+ return
+}
+
// FindCommonAncestorWithTail return the block's common ancestor with current tail
func (bc *BlockChain) FindCommonAncestorWithTail(block *Block) (*Block, error) {
if block == nil {
@@ -683,6 +725,13 @@ func (bc *BlockChain) SimulateTransactionExecution(tx *Transaction) (*SimulateRe
if err != nil {
return nil, err
}
+
+ sVrfSeed, sVrfProof := make([]byte, 32), make([]byte, 129)
+ _, _ = io.ReadFull(rand.Reader, sVrfSeed)
+ _, _ = io.ReadFull(rand.Reader, sVrfProof)
+ block.header.random.VrfSeed = sVrfSeed
+ block.header.random.VrfProof = sVrfProof
+
defer block.RollBack()
// simulate execution.
diff --git a/core/compatibility.go b/core/compatibility.go
new file mode 100644
index 000000000..3d0006f6c
--- /dev/null
+++ b/core/compatibility.go
@@ -0,0 +1,121 @@
+// Copyright (C) 2018 go-nebulas authors
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+package core
+
+import (
+ "github.com/nebulasio/go-nebulas/util/logging"
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ // MainNetID mainnet id
+ MainNetID uint32 = 1
+
+ // TestNetID testnet id
+ TestNetID uint32 = 1001
+)
+
+// mainnet/testnet
+const (
+ // DefaultTransferFromContractEventRecordableHeight
+ DefaultTransferFromContractEventRecordableHeight uint64 = 250000
+
+ // DefaultAcceptFuncAvailableHeight
+ DefaultAcceptFuncAvailableHeight uint64 = 250000
+
+ // DefaultRandomAvailableHeight
+ DefaultRandomAvailableHeight uint64 = 250000
+
+ // DefaultDateAvailableHeight
+ DefaultDateAvailableHeight uint64 = 250000
+
+ // DefaultRecordCallContractResultHeight
+ DefaultRecordCallContractResultHeight uint64 = 250000
+)
+
+// others, e.g. local/develop
+const (
+ // LocalTransferFromContractEventRecordableHeight
+ LocalTransferFromContractEventRecordableHeight uint64 = 0
+
+ // LocalAcceptFuncAvailableHeight
+ LocalAcceptFuncAvailableHeight uint64 = 0
+
+ // LocalRandomAvailableHeight
+ LocalRandomAvailableHeight uint64 = 0
+
+ // LocalDateAvailableHeight
+ LocalDateAvailableHeight uint64 = 0
+
+ // LocalRecordCallContractResultHeight
+ LocalRecordCallContractResultHeight uint64 = 0
+)
+
+var (
+ // TransferFromContractEventRecordableHeight record event 'TransferFromContractEvent' since this height
+ TransferFromContractEventRecordableHeight = DefaultTransferFromContractEventRecordableHeight
+
+ // AcceptFuncAvailableHeight 'accept' func available since this height
+ AcceptFuncAvailableHeight = DefaultAcceptFuncAvailableHeight
+
+ // RandomAvailableHeight make 'Math.random' available in contract since this height
+ RandomAvailableHeight = DefaultRandomAvailableHeight
+
+ // DateAvailableHeight make 'Date' available in contract since this height
+ DateAvailableHeight = DefaultDateAvailableHeight
+
+ // RecordCallContractResultHeight record result of call contract to event `TopicTransactionExecutionResult` since this height
+ RecordCallContractResultHeight = DefaultRecordCallContractResultHeight
+)
+
+// SetCompatibilityOptions set compatibility height according to chain_id
+func SetCompatibilityOptions(chainID uint32) {
+
+ if chainID == MainNetID || chainID == TestNetID {
+ logging.VLog().WithFields(logrus.Fields{
+ "chain_id": chainID,
+ "TransferFromContractEventRecordableHeight": TransferFromContractEventRecordableHeight,
+ "AcceptFuncAvailableHeight": AcceptFuncAvailableHeight,
+ "RandomAvailableHeight": RandomAvailableHeight,
+ "DateAvailableHeight": DateAvailableHeight,
+ "RecordCallContractResultHeight": RecordCallContractResultHeight,
+ }).Info("Set compatibility options for mainnet/testnet.")
+ return
+ }
+
+ TransferFromContractEventRecordableHeight = LocalTransferFromContractEventRecordableHeight
+
+ AcceptFuncAvailableHeight = LocalAcceptFuncAvailableHeight
+
+ RandomAvailableHeight = LocalRandomAvailableHeight
+
+ DateAvailableHeight = LocalDateAvailableHeight
+
+ RecordCallContractResultHeight = LocalRecordCallContractResultHeight
+
+ logging.VLog().WithFields(logrus.Fields{
+ "chain_id": chainID,
+ "TransferFromContractEventRecordableHeight": TransferFromContractEventRecordableHeight,
+ "AcceptFuncAvailableHeight": AcceptFuncAvailableHeight,
+ "RandomAvailableHeight": RandomAvailableHeight,
+ "DateAvailableHeight": DateAvailableHeight,
+ "RecordCallContractResultHeight": RecordCallContractResultHeight,
+ }).Info("Set compatibility options for local.")
+
+}
diff --git a/core/event.go b/core/event.go
index 744b3ec66..a533b77e5 100644
--- a/core/event.go
+++ b/core/event.go
@@ -46,6 +46,9 @@ const (
// TopicDropTransaction drop tx (1): smaller nonce (2) expire txLifeTime
TopicDropTransaction = "chain.dropTransaction"
+
+ // TopicTransferFromContract transfer from contract
+ TopicTransferFromContract = "chain.transferFromContract"
)
// EventSubscriber subscriber object
diff --git a/core/pb/block.pb.go b/core/pb/block.pb.go
index 474e66ca1..f6d575257 100644
--- a/core/pb/block.pb.go
+++ b/core/pb/block.pb.go
@@ -16,6 +16,7 @@ It has these top-level messages:
NetBlocks
NetBlock
DownloadBlock
+ Random
*/
package corepb
@@ -224,6 +225,7 @@ type BlockHeader struct {
TxsRoot []byte `protobuf:"bytes,10,opt,name=txs_root,json=txsRoot,proto3" json:"txs_root,omitempty"`
EventsRoot []byte `protobuf:"bytes,11,opt,name=events_root,json=eventsRoot,proto3" json:"events_root,omitempty"`
ConsensusRoot *consensuspb.ConsensusRoot `protobuf:"bytes,12,opt,name=consensus_root,json=consensusRoot" json:"consensus_root,omitempty"`
+ Random *Random `protobuf:"bytes,13,opt,name=random" json:"random,omitempty"`
}
func (m *BlockHeader) Reset() { *m = BlockHeader{} }
@@ -308,6 +310,13 @@ func (m *BlockHeader) GetConsensusRoot() *consensuspb.ConsensusRoot {
return nil
}
+func (m *BlockHeader) GetRandom() *Random {
+ if m != nil {
+ return m.Random
+ }
+ return nil
+}
+
type Block struct {
Header *BlockHeader `protobuf:"bytes,1,opt,name=header" json:"header,omitempty"`
Transactions []*Transaction `protobuf:"bytes,2,rep,name=transactions" json:"transactions,omitempty"`
@@ -436,6 +445,30 @@ func (m *DownloadBlock) GetSign() []byte {
return nil
}
+type Random struct {
+ VrfSeed []byte `protobuf:"bytes,1,opt,name=vrf_seed,json=vrfSeed,proto3" json:"vrf_seed,omitempty"`
+ VrfProof []byte `protobuf:"bytes,2,opt,name=vrf_proof,json=vrfProof,proto3" json:"vrf_proof,omitempty"`
+}
+
+func (m *Random) Reset() { *m = Random{} }
+func (m *Random) String() string { return proto.CompactTextString(m) }
+func (*Random) ProtoMessage() {}
+func (*Random) Descriptor() ([]byte, []int) { return fileDescriptorBlock, []int{8} }
+
+func (m *Random) GetVrfSeed() []byte {
+ if m != nil {
+ return m.VrfSeed
+ }
+ return nil
+}
+
+func (m *Random) GetVrfProof() []byte {
+ if m != nil {
+ return m.VrfProof
+ }
+ return nil
+}
+
func init() {
proto.RegisterType((*Account)(nil), "corepb.Account")
proto.RegisterType((*Data)(nil), "corepb.Data")
@@ -445,54 +478,59 @@ func init() {
proto.RegisterType((*NetBlocks)(nil), "corepb.NetBlocks")
proto.RegisterType((*NetBlock)(nil), "corepb.NetBlock")
proto.RegisterType((*DownloadBlock)(nil), "corepb.DownloadBlock")
+ proto.RegisterType((*Random)(nil), "corepb.Random")
}
func init() { proto.RegisterFile("block.proto", fileDescriptorBlock) }
var fileDescriptorBlock = []byte{
- // 698 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x6d, 0x8b, 0xd3, 0x40,
- 0x10, 0x26, 0x6d, 0xfa, 0x36, 0x69, 0x8f, 0x63, 0x3d, 0x24, 0x56, 0xe5, 0x4a, 0x44, 0x28, 0x8a,
- 0x2d, 0x9c, 0xc2, 0xf9, 0xf5, 0xf4, 0x3e, 0x9c, 0x22, 0x72, 0x04, 0xbf, 0x08, 0x42, 0x99, 0x6c,
- 0xd6, 0x24, 0x98, 0xee, 0x86, 0xec, 0xf6, 0xbc, 0xfb, 0x19, 0xfe, 0x0f, 0xbf, 0xf8, 0x93, 0xfc,
- 0x27, 0xb2, 0xb3, 0xe9, 0xdb, 0x79, 0x20, 0x7e, 0xea, 0x3e, 0xf3, 0x64, 0xa6, 0xf3, 0x3c, 0x33,
- 0xbb, 0x10, 0x24, 0xa5, 0xe2, 0xdf, 0x66, 0x55, 0xad, 0x8c, 0x62, 0x5d, 0xae, 0x6a, 0x51, 0x25,
- 0xe3, 0xd3, 0xac, 0x30, 0xf9, 0x2a, 0x99, 0x71, 0xb5, 0x9c, 0x4b, 0x91, 0xac, 0x4a, 0xd4, 0x85,
- 0x9a, 0x67, 0xea, 0x45, 0x03, 0xe6, 0x5c, 0x2d, 0x97, 0x4a, 0xce, 0x53, 0xcc, 0xe6, 0x55, 0x62,
- 0x7f, 0x5c, 0x81, 0xf1, 0xeb, 0x7f, 0x27, 0x4a, 0x2d, 0xa4, 0x5e, 0x69, 0x9b, 0xa7, 0x0d, 0x1a,
- 0xe1, 0x32, 0xa3, 0x1f, 0x1e, 0xf4, 0xce, 0x38, 0x57, 0x2b, 0x69, 0x58, 0x08, 0x3d, 0x4c, 0xd3,
- 0x5a, 0x68, 0x1d, 0x7a, 0x13, 0x6f, 0x3a, 0x8c, 0xd7, 0xd0, 0x32, 0x09, 0x96, 0x28, 0xb9, 0x08,
- 0x5b, 0x8e, 0x69, 0x20, 0x3b, 0x82, 0x8e, 0x54, 0x36, 0xde, 0x9e, 0x78, 0x53, 0x3f, 0x76, 0x80,
- 0x3d, 0x84, 0xc1, 0x15, 0xd6, 0x7a, 0x91, 0xa3, 0xce, 0x43, 0x9f, 0x32, 0xfa, 0x36, 0x70, 0x81,
- 0x3a, 0x67, 0xc7, 0x10, 0x24, 0x45, 0x6d, 0xf2, 0x45, 0x55, 0x22, 0x17, 0x61, 0x87, 0x68, 0xa0,
- 0xd0, 0xa5, 0x8d, 0x44, 0xaf, 0xc0, 0x3f, 0x47, 0x83, 0x8c, 0x81, 0x6f, 0x6e, 0x2a, 0x41, 0xcd,
- 0x0c, 0x62, 0x3a, 0xdb, 0x4e, 0x2a, 0xbc, 0x29, 0x15, 0xa6, 0xeb, 0x4e, 0x1a, 0x18, 0xfd, 0x6c,
- 0x41, 0xf0, 0xa9, 0x46, 0xa9, 0x91, 0x9b, 0x42, 0x49, 0x9b, 0x4d, 0x7f, 0xef, 0xa4, 0xd0, 0xd9,
- 0xc6, 0xbe, 0xd6, 0x6a, 0xd9, 0xa4, 0xd2, 0x99, 0x1d, 0x40, 0xcb, 0x28, 0x6a, 0x7f, 0x18, 0xb7,
- 0x8c, 0xb2, 0x8a, 0xae, 0xb0, 0x5c, 0x89, 0xa6, 0x6f, 0x07, 0xb6, 0x3a, 0x3b, 0xbb, 0x3a, 0x1f,
- 0xc1, 0xc0, 0x14, 0x4b, 0xa1, 0x0d, 0x2e, 0xab, 0xb0, 0x3b, 0xf1, 0xa6, 0xed, 0x78, 0x1b, 0x60,
- 0x13, 0xf0, 0x53, 0x34, 0x18, 0xf6, 0x26, 0xde, 0x34, 0x38, 0x19, 0xce, 0xdc, 0x94, 0x67, 0x56,
- 0x5b, 0x4c, 0x0c, 0x7b, 0x00, 0x7d, 0x9e, 0x63, 0x21, 0x17, 0x45, 0x1a, 0xf6, 0x27, 0xde, 0x74,
- 0x14, 0xf7, 0x08, 0xbf, 0x4b, 0xad, 0x85, 0x19, 0xea, 0x45, 0x55, 0x17, 0x5c, 0x84, 0x03, 0x67,
- 0x61, 0x86, 0xfa, 0xd2, 0xe2, 0x35, 0x59, 0x16, 0xcb, 0xc2, 0x84, 0xb0, 0x21, 0x3f, 0x58, 0xcc,
- 0x0e, 0xa1, 0x8d, 0x65, 0x16, 0x06, 0x54, 0xcf, 0x1e, 0xad, 0x6c, 0x5d, 0x64, 0x32, 0x1c, 0x3a,
- 0xd9, 0xf6, 0x1c, 0xfd, 0x6e, 0x41, 0xf0, 0xc6, 0xee, 0xe0, 0x85, 0xc0, 0x54, 0xd4, 0x77, 0xda,
- 0x75, 0x0c, 0x41, 0x85, 0xb5, 0x90, 0xc6, 0x0d, 0xd2, 0xb9, 0x06, 0x2e, 0x44, 0xa3, 0x1c, 0x43,
- 0x9f, 0xab, 0x42, 0x26, 0xa8, 0xd7, 0x76, 0x6d, 0xf0, 0xbe, 0x37, 0x9d, 0xdb, 0xde, 0xec, 0x2a,
- 0xef, 0xee, 0x2b, 0x6f, 0xfa, 0xef, 0xfd, 0xdd, 0x7f, 0x7f, 0xdb, 0x3f, 0x7b, 0x0c, 0x40, 0x7b,
- 0xbc, 0xa8, 0x95, 0x32, 0x8d, 0x41, 0x03, 0x8a, 0xc4, 0x4a, 0x19, 0x5b, 0xdf, 0x5c, 0x6b, 0x47,
- 0x3a, 0x83, 0x7a, 0xe6, 0x5a, 0x13, 0x75, 0x0c, 0x81, 0xb8, 0x12, 0xd2, 0x34, 0x6c, 0xe0, 0x54,
- 0xb9, 0x10, 0x7d, 0x70, 0x06, 0x07, 0x9b, 0xfb, 0xe2, 0xbe, 0x19, 0xd2, 0x04, 0xc7, 0xb3, 0x4d,
- 0xb8, 0x4a, 0x66, 0x6f, 0xd7, 0x67, 0x9b, 0x13, 0x8f, 0xf8, 0x2e, 0x7c, 0xef, 0xf7, 0xdb, 0x87,
- 0x7e, 0xf4, 0xcb, 0x83, 0x0e, 0x79, 0xcc, 0x9e, 0x43, 0x37, 0x27, 0x9f, 0xc9, 0xdf, 0xe0, 0xe4,
- 0xde, 0x7a, 0x19, 0x76, 0x46, 0x10, 0x37, 0x9f, 0xb0, 0x53, 0x18, 0x9a, 0xed, 0x22, 0xeb, 0xb0,
- 0x35, 0x69, 0xef, 0xa6, 0xec, 0x2c, 0x79, 0xbc, 0xf7, 0x21, 0x7b, 0x06, 0x90, 0x8a, 0x4a, 0xc8,
- 0x54, 0x48, 0x7e, 0x43, 0x2b, 0x1d, 0x9c, 0xc0, 0x2c, 0xc5, 0x8c, 0xb6, 0x2e, 0x8b, 0x77, 0x58,
- 0x76, 0xdf, 0x76, 0x54, 0x64, 0xb9, 0xa1, 0xc1, 0xf9, 0x71, 0x83, 0xa2, 0x2f, 0x30, 0xf8, 0x28,
- 0x0c, 0xb5, 0xa5, 0x37, 0xf7, 0xa5, 0xb9, 0x81, 0x74, 0x5f, 0x8e, 0xa0, 0x93, 0xa0, 0xe1, 0x6e,
- 0x1d, 0xfc, 0xd8, 0x01, 0xf6, 0x14, 0xba, 0xf4, 0xa2, 0xe9, 0xb0, 0x4d, 0xdd, 0x8e, 0xf6, 0x04,
- 0xc6, 0x0d, 0x19, 0x7d, 0x86, 0xfe, 0xba, 0xfa, 0x7f, 0x14, 0x7f, 0x02, 0x1d, 0xca, 0x6f, 0x24,
- 0xdd, 0xaa, 0xed, 0xb8, 0xe8, 0x14, 0x46, 0xe7, 0xea, 0xbb, 0xb4, 0x6f, 0xc1, 0xa6, 0xfe, 0x5d,
- 0x0f, 0x00, 0x6d, 0x52, 0x6b, 0xbb, 0x49, 0x49, 0x97, 0x5e, 0xc2, 0x97, 0x7f, 0x02, 0x00, 0x00,
- 0xff, 0xff, 0xa7, 0xc4, 0x6c, 0xca, 0x93, 0x05, 0x00, 0x00,
+ // 754 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x5f, 0x8b, 0xdb, 0x46,
+ 0x10, 0x47, 0xb6, 0x2c, 0xdb, 0x23, 0xfb, 0x38, 0xb6, 0x47, 0x51, 0xdd, 0x96, 0x33, 0x2a, 0x2d,
+ 0xa6, 0xa5, 0x36, 0x5c, 0x0b, 0xd7, 0xc7, 0x5e, 0x72, 0x0f, 0x97, 0x10, 0xc2, 0xb1, 0xc9, 0x4b,
+ 0x20, 0x60, 0x56, 0xd2, 0x5a, 0x12, 0x91, 0x76, 0x85, 0x76, 0xed, 0xdc, 0x7d, 0x84, 0x3c, 0xe6,
+ 0x7b, 0xe4, 0x25, 0xdf, 0x30, 0xec, 0xac, 0x64, 0xcb, 0x97, 0x83, 0x90, 0x27, 0xed, 0x6f, 0x7e,
+ 0x3b, 0xa3, 0xf9, 0xcd, 0x9f, 0x05, 0x3f, 0x2a, 0x64, 0xfc, 0x6e, 0x59, 0xd5, 0x52, 0x4b, 0xe2,
+ 0xc5, 0xb2, 0xe6, 0x55, 0x34, 0xbb, 0x4c, 0x73, 0x9d, 0x6d, 0xa3, 0x65, 0x2c, 0xcb, 0x95, 0xe0,
+ 0xd1, 0xb6, 0x60, 0x2a, 0x97, 0xab, 0x54, 0xfe, 0xdd, 0x80, 0x55, 0x2c, 0xcb, 0x52, 0x8a, 0x55,
+ 0xc2, 0xd2, 0x55, 0x15, 0x99, 0x8f, 0x0d, 0x30, 0xfb, 0xef, 0xdb, 0x8e, 0x42, 0x71, 0xa1, 0xb6,
+ 0xca, 0xf8, 0x29, 0xcd, 0x34, 0xb7, 0x9e, 0xe1, 0x47, 0x07, 0x86, 0x57, 0x71, 0x2c, 0xb7, 0x42,
+ 0x93, 0x00, 0x86, 0x2c, 0x49, 0x6a, 0xae, 0x54, 0xe0, 0xcc, 0x9d, 0xc5, 0x84, 0xb6, 0xd0, 0x30,
+ 0x11, 0x2b, 0x98, 0x88, 0x79, 0xd0, 0xb3, 0x4c, 0x03, 0xc9, 0x19, 0x0c, 0x84, 0x34, 0xf6, 0xfe,
+ 0xdc, 0x59, 0xb8, 0xd4, 0x02, 0xf2, 0x33, 0x8c, 0x77, 0xac, 0x56, 0xeb, 0x8c, 0xa9, 0x2c, 0x70,
+ 0xd1, 0x63, 0x64, 0x0c, 0x37, 0x4c, 0x65, 0xe4, 0x1c, 0xfc, 0x28, 0xaf, 0x75, 0xb6, 0xae, 0x0a,
+ 0x16, 0xf3, 0x60, 0x80, 0x34, 0xa0, 0xe9, 0xd6, 0x58, 0xc2, 0x7f, 0xc1, 0xbd, 0x66, 0x9a, 0x11,
+ 0x02, 0xae, 0xbe, 0xaf, 0x38, 0x26, 0x33, 0xa6, 0x78, 0x36, 0x99, 0x54, 0xec, 0xbe, 0x90, 0x2c,
+ 0x69, 0x33, 0x69, 0x60, 0xf8, 0xa9, 0x07, 0xfe, 0xeb, 0x9a, 0x09, 0xc5, 0x62, 0x9d, 0x4b, 0x61,
+ 0xbc, 0xf1, 0xf7, 0x56, 0x0a, 0x9e, 0x8d, 0x6d, 0x53, 0xcb, 0xb2, 0x71, 0xc5, 0x33, 0x39, 0x81,
+ 0x9e, 0x96, 0x98, 0xfe, 0x84, 0xf6, 0xb4, 0x34, 0x8a, 0x76, 0xac, 0xd8, 0xf2, 0x26, 0x6f, 0x0b,
+ 0x0e, 0x3a, 0x07, 0x5d, 0x9d, 0xbf, 0xc0, 0x58, 0xe7, 0x25, 0x57, 0x9a, 0x95, 0x55, 0xe0, 0xcd,
+ 0x9d, 0x45, 0x9f, 0x1e, 0x0c, 0x64, 0x0e, 0x6e, 0xc2, 0x34, 0x0b, 0x86, 0x73, 0x67, 0xe1, 0x5f,
+ 0x4c, 0x96, 0xb6, 0xcb, 0x4b, 0xa3, 0x8d, 0x22, 0x43, 0x7e, 0x82, 0x51, 0x9c, 0xb1, 0x5c, 0xac,
+ 0xf3, 0x24, 0x18, 0xcd, 0x9d, 0xc5, 0x94, 0x0e, 0x11, 0x3f, 0x4b, 0x4c, 0x09, 0x53, 0xa6, 0xd6,
+ 0x55, 0x9d, 0xc7, 0x3c, 0x18, 0xdb, 0x12, 0xa6, 0x4c, 0xdd, 0x1a, 0xdc, 0x92, 0x45, 0x5e, 0xe6,
+ 0x3a, 0x80, 0x3d, 0xf9, 0xc2, 0x60, 0x72, 0x0a, 0x7d, 0x56, 0xa4, 0x81, 0x8f, 0xf1, 0xcc, 0xd1,
+ 0xc8, 0x56, 0x79, 0x2a, 0x82, 0x89, 0x95, 0x6d, 0xce, 0xe1, 0x87, 0x3e, 0xf8, 0x4f, 0xcc, 0x0c,
+ 0xde, 0x70, 0x96, 0xf0, 0xfa, 0xd1, 0x72, 0x9d, 0x83, 0x5f, 0xb1, 0x9a, 0x0b, 0x6d, 0x1b, 0x69,
+ 0xab, 0x06, 0xd6, 0x84, 0xad, 0x9c, 0xc1, 0x28, 0x96, 0xb9, 0x88, 0x98, 0x6a, 0xcb, 0xb5, 0xc7,
+ 0xc7, 0xb5, 0x19, 0x3c, 0xac, 0x4d, 0x57, 0xb9, 0x77, 0xac, 0xbc, 0xc9, 0x7f, 0xf8, 0x75, 0xfe,
+ 0xa3, 0x43, 0xfe, 0xe4, 0x57, 0x00, 0x9c, 0xe3, 0x75, 0x2d, 0xa5, 0x6e, 0x0a, 0x34, 0x46, 0x0b,
+ 0x95, 0x52, 0x9b, 0xf8, 0xfa, 0x4e, 0x59, 0xd2, 0x16, 0x68, 0xa8, 0xef, 0x14, 0x52, 0xe7, 0xe0,
+ 0xf3, 0x1d, 0x17, 0xba, 0x61, 0x7d, 0xab, 0xca, 0x9a, 0xf0, 0xc2, 0x15, 0x9c, 0xec, 0xf7, 0xc5,
+ 0xde, 0x99, 0x60, 0x07, 0x67, 0xcb, 0xbd, 0xb9, 0x8a, 0x96, 0x4f, 0xdb, 0xb3, 0xf1, 0xa1, 0xd3,
+ 0xb8, 0x0b, 0xc9, 0x1f, 0xe0, 0xd5, 0x4c, 0x24, 0xb2, 0x0c, 0xa6, 0xe8, 0x7a, 0xd2, 0x36, 0x9f,
+ 0xa2, 0x95, 0x36, 0xec, 0x73, 0x77, 0xd4, 0x3f, 0x75, 0xc3, 0xcf, 0x0e, 0x0c, 0xb0, 0x17, 0xe4,
+ 0x2f, 0xf0, 0x32, 0xec, 0x07, 0xf6, 0xc1, 0xbf, 0xf8, 0xa1, 0xf5, 0xeb, 0xb4, 0x8a, 0x36, 0x57,
+ 0xc8, 0x25, 0x4c, 0xf4, 0x61, 0xe0, 0x55, 0xd0, 0x9b, 0xf7, 0xbb, 0x2e, 0x9d, 0x65, 0xa0, 0x47,
+ 0x17, 0xc9, 0x9f, 0x00, 0x09, 0xaf, 0xb8, 0x48, 0xb8, 0x88, 0xef, 0x71, 0xf4, 0xfd, 0x0b, 0x58,
+ 0x26, 0x2c, 0xc5, 0xe9, 0x4c, 0x69, 0x87, 0x25, 0x3f, 0x9a, 0x8c, 0xf2, 0x34, 0xd3, 0xd8, 0x60,
+ 0x97, 0x36, 0x28, 0x7c, 0x0b, 0xe3, 0x97, 0x5c, 0x63, 0x5a, 0x6a, 0xbf, 0x57, 0xcd, 0xa6, 0xe2,
+ 0x5e, 0x9d, 0xc1, 0x20, 0x62, 0x3a, 0xb6, 0x63, 0xe3, 0x52, 0x0b, 0xc8, 0xef, 0xe0, 0xe1, 0xcb,
+ 0xa7, 0x82, 0x3e, 0x66, 0x3b, 0x3d, 0x12, 0x48, 0x1b, 0x32, 0x7c, 0x03, 0xa3, 0x36, 0xfa, 0x77,
+ 0x04, 0xff, 0x0d, 0x06, 0xe8, 0xdf, 0x48, 0x7a, 0x10, 0xdb, 0x72, 0xe1, 0x25, 0x4c, 0xaf, 0xe5,
+ 0x7b, 0x61, 0xde, 0x8c, 0x7d, 0xfc, 0xc7, 0x1e, 0x0a, 0x9c, 0xb8, 0x5e, 0x67, 0x63, 0xfe, 0x07,
+ 0xcf, 0x76, 0xcf, 0x0c, 0xd7, 0xae, 0xde, 0xac, 0x15, 0xe7, 0x49, 0xfb, 0x52, 0xee, 0xea, 0xcd,
+ 0x2b, 0xce, 0x71, 0x6d, 0x0d, 0x55, 0xd5, 0x52, 0x6e, 0x1a, 0x6f, 0x73, 0xf7, 0xd6, 0xe0, 0xc8,
+ 0xc3, 0x37, 0xf7, 0x9f, 0x2f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x18, 0x56, 0x0a, 0xfd, 0x05,
+ 0x00, 0x00,
}
diff --git a/core/pb/block.proto b/core/pb/block.proto
index 24e67e288..9e1f0f714 100644
--- a/core/pb/block.proto
+++ b/core/pb/block.proto
@@ -64,6 +64,7 @@ message BlockHeader {
bytes txs_root = 10;
bytes events_root = 11;
consensuspb.ConsensusRoot consensus_root = 12;
+ Random random = 13;
}
message Block {
@@ -90,3 +91,8 @@ message DownloadBlock {
bytes hash = 1;
bytes sign = 2;
}
+
+message Random {
+ bytes vrf_seed = 1;
+ bytes vrf_proof = 2;
+}
\ No newline at end of file
diff --git a/core/state/account_state.go b/core/state/account_state.go
index 3ae8ccc8e..fed37295b 100644
--- a/core/state/account_state.go
+++ b/core/state/account_state.go
@@ -32,8 +32,9 @@ import (
// Errors
var (
- ErrBalanceInsufficient = errors.New("cannot subtract a value which is bigger than current balance")
- ErrAccountNotFound = errors.New("cannot found account in storage")
+ ErrBalanceInsufficient = errors.New("cannot subtract a value which is bigger than current balance")
+ ErrAccountNotFound = errors.New("cannot found account in storage")
+ ErrContractAccountNotFound = errors.New("cannot found contract account in storage please check contract address is valid or deploy is success")
)
// account info in state Trie
@@ -301,6 +302,10 @@ func (as *accountState) GetOrCreateUserAccount(addr byteutils.Hash) (Account, er
// GetContractAccount from current AccountState
func (as *accountState) GetContractAccount(addr byteutils.Hash) (Account, error) {
acc, err := as.getAccount(addr)
+
+ if err == ErrAccountNotFound {
+ err = ErrContractAccountNotFound
+ }
if err != nil {
return nil, err
}
diff --git a/core/transaction.go b/core/transaction.go
index 673984229..7ac6ed326 100644
--- a/core/transaction.go
+++ b/core/transaction.go
@@ -67,6 +67,9 @@ var (
// MaxEventErrLength Max error length in event
MaxEventErrLength = 256
+
+ // MaxResultLength max execution result length
+ MaxResultLength = 256
)
// TransactionEvent transaction event
@@ -77,6 +80,15 @@ type TransactionEvent struct {
Error string `json:"error"`
}
+// TransactionEventV2 add execution result
+type TransactionEventV2 struct {
+ Hash string `json:"hash"`
+ Status int8 `json:"status"`
+ GasUsed string `json:"gas_used"`
+ Error string `json:"error"`
+ ExecuteResult string `json:"execute_result"`
+}
+
// Transaction type is used to handle all transaction data.
type Transaction struct {
hash byteutils.Hash
@@ -348,7 +360,8 @@ func (tx *Transaction) LoadPayload() (TxPayload, error) {
return payload, err
}
-func submitTx(tx *Transaction, block *Block, ws WorldState, gas *util.Uint128, exeErr error, exeErrTy string) (bool, error) {
+func submitTx(tx *Transaction, block *Block, ws WorldState,
+ gas *util.Uint128, exeErr error, exeErrTy string, exeResult string) (bool, error) {
if exeErr != nil {
logging.VLog().WithFields(logrus.Fields{
"err": exeErr,
@@ -378,7 +391,7 @@ func submitTx(tx *Transaction, block *Block, ws WorldState, gas *util.Uint128, e
metricsUnexpectedBehavior.Update(1)
return true, err
}
- if err := tx.recordResultEvent(gas, exeErr, ws); err != nil {
+ if err := tx.recordResultEvent(gas, exeErr, ws, block, exeResult); err != nil {
logging.VLog().WithFields(logrus.Fields{
"err": err,
"tx": tx,
@@ -438,7 +451,7 @@ func VerifyExecution(tx *Transaction, block *Block, ws WorldState) (bool, error)
// step3. check payload vaild.
payload, payloadErr := tx.LoadPayload()
if payloadErr != nil {
- return submitTx(tx, block, ws, gasUsed, payloadErr, "Failed to load payload.")
+ return submitTx(tx, block, ws, gasUsed, payloadErr, "Failed to load payload.", "")
}
// step4. calculate base gas of payload
@@ -452,20 +465,20 @@ func VerifyExecution(tx *Transaction, block *Block, ws WorldState) (bool, error)
"block": block,
}).Error("Failed to add payload base gas, unexpected error")
metricsUnexpectedBehavior.Update(1)
- return submitTx(tx, block, ws, gasUsed, ErrGasCntOverflow, "Failed to add the count of base payload gas")
+ return submitTx(tx, block, ws, gasUsed, ErrGasCntOverflow, "Failed to add the count of base payload gas", "")
}
gasUsed = payloadGas
if tx.gasLimit.Cmp(gasUsed) < 0 {
- return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to check gasLimit >= txBaseGas + payloasBaseGas.")
+ return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to check gasLimit >= txBaseGas + payloasBaseGas.", "")
}
// step5. check balance >= limitedFee + value. and transfer
minBalanceRequired, balanceErr := limitedFee.Add(tx.value)
if balanceErr != nil {
- return submitTx(tx, block, ws, gasUsed, ErrGasFeeOverflow, "Failed to add tx.value")
+ return submitTx(tx, block, ws, gasUsed, ErrGasFeeOverflow, "Failed to add tx.value", "")
}
if fromAcc.Balance().Cmp(minBalanceRequired) < 0 {
- return submitTx(tx, block, ws, gasUsed, ErrInsufficientBalance, "Failed to check balance >= gasLimit * gasPrice + value")
+ return submitTx(tx, block, ws, gasUsed, ErrInsufficientBalance, "Failed to check balance >= gasLimit * gasPrice + value", "")
}
var transferSubErr, transferAddErr error
transferSubErr = fromAcc.SubBalance(tx.value)
@@ -482,7 +495,7 @@ func VerifyExecution(tx *Transaction, block *Block, ws WorldState) (bool, error)
"block": block,
}).Error("Failed to transfer value, unexpected error")
metricsUnexpectedBehavior.Update(1)
- return submitTx(tx, block, ws, gasUsed, ErrInvalidTransfer, "Failed to transfer tx.value")
+ return submitTx(tx, block, ws, gasUsed, ErrInvalidTransfer, "Failed to transfer tx.value", "")
}
// step6. calculate contract's limited gas
@@ -495,23 +508,23 @@ func VerifyExecution(tx *Transaction, block *Block, ws WorldState) (bool, error)
"block": block,
}).Error("Failed to calculate payload's limit gas, unexpected error")
metricsUnexpectedBehavior.Update(1)
- return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to calculate payload's limit gas")
+ return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to calculate payload's limit gas", "")
}
// step7. execute contract.
- gasExecution, _, exeErr := payload.Execute(contractLimitedGas, tx, block, ws)
+ gasExecution, exeResult, exeErr := payload.Execute(contractLimitedGas, tx, block, ws)
// step8. calculate final gas.
allGas, gasErr := gasUsed.Add(gasExecution)
if gasErr != nil {
- return submitTx(tx, block, ws, gasUsed, ErrGasCntOverflow, "Failed to add the fee of execution gas")
+ return submitTx(tx, block, ws, gasUsed, ErrGasCntOverflow, "Failed to add the fee of execution gas", "")
}
if tx.gasLimit.Cmp(allGas) < 0 {
- return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to check gasLimit >= allGas")
+ return submitTx(tx, block, ws, tx.gasLimit, ErrOutOfGasLimit, "Failed to check gasLimit >= allGas", "")
}
// step9. over
- return submitTx(tx, block, ws, allGas, exeErr, "Failed to execute payload")
+ return submitTx(tx, block, ws, allGas, exeErr, "Failed to execute payload", exeResult)
}
// simulateExecution simulate execution and return gasUsed, executionResult and executionErr, sysErr if occurred.
@@ -555,7 +568,8 @@ func (tx *Transaction) simulateExecution(block *Block) (*SimulateResult, error)
)
// try run smart contract if payload is.
- if tx.data.Type == TxPayloadCallType || tx.data.Type == TxPayloadDeployType {
+ if tx.data.Type == TxPayloadCallType || tx.data.Type == TxPayloadDeployType ||
+ (tx.data.Type == TxPayloadBinaryType && tx.to.Type() == ContractAddress && block.height >= AcceptFuncAvailableHeight) {
// transfer value to smart contract.
toAcc, err := ws.GetOrCreateUserAccount(tx.to.address)
@@ -614,22 +628,46 @@ func (tx *Transaction) recordGas(gasCnt *util.Uint128, ws WorldState) error {
return ws.RecordGas(tx.from.String(), gasCost)
}
-func (tx *Transaction) recordResultEvent(gasUsed *util.Uint128, err error, ws WorldState) error {
- txEvent := &TransactionEvent{
- Hash: tx.hash.String(),
- GasUsed: gasUsed.String(),
- Status: TxExecutionSuccess,
- }
+func (tx *Transaction) recordResultEvent(gasUsed *util.Uint128, err error, ws WorldState, block *Block, exeResult string) error {
- if err != nil {
- txEvent.Status = TxExecutionFailed
- txEvent.Error = err.Error()
- if len(txEvent.Error) > MaxEventErrLength {
- txEvent.Error = txEvent.Error[:MaxEventErrLength]
+ var txData []byte
+ if block.height >= RecordCallContractResultHeight {
+
+ if len(exeResult) > MaxResultLength {
+ exeResult = exeResult[:MaxResultLength]
+ }
+ txEvent := &TransactionEventV2{
+ Hash: tx.hash.String(),
+ GasUsed: gasUsed.String(),
+ Status: TxExecutionSuccess,
+ ExecuteResult: exeResult,
+ }
+
+ if err != nil {
+ txEvent.Status = TxExecutionFailed
+ txEvent.Error = err.Error()
+ if len(txEvent.Error) > MaxEventErrLength {
+ txEvent.Error = txEvent.Error[:MaxEventErrLength]
+ }
+ }
+ txData, err = json.Marshal(txEvent)
+ } else {
+ txEvent := &TransactionEvent{
+ Hash: tx.hash.String(),
+ GasUsed: gasUsed.String(),
+ Status: TxExecutionSuccess,
+ }
+
+ if err != nil {
+ txEvent.Status = TxExecutionFailed
+ txEvent.Error = err.Error()
+ if len(txEvent.Error) > MaxEventErrLength {
+ txEvent.Error = txEvent.Error[:MaxEventErrLength]
+ }
}
+ txData, err = json.Marshal(txEvent)
}
- txData, err := json.Marshal(txEvent)
if err != nil {
return err
}
@@ -711,6 +749,10 @@ func CheckContract(addr *Address, ws WorldState) (state.Account, error) {
return nil, ErrNilArgument
}
+ if addr.Type() != ContractAddress {
+ return nil, ErrContractCheckFailed
+ }
+
contract, err := ws.GetContractAccount(addr.Bytes())
if err != nil {
return nil, err
diff --git a/core/transaction_binary_payload.go b/core/transaction_binary_payload.go
index 44304e3c0..28cb293b0 100644
--- a/core/transaction_binary_payload.go
+++ b/core/transaction_binary_payload.go
@@ -19,6 +19,8 @@
package core
import (
+ "fmt"
+
"github.com/nebulasio/go-nebulas/util"
)
@@ -51,5 +53,55 @@ func (payload *BinaryPayload) BaseGasCount() *util.Uint128 {
// Execute the payload in tx
func (payload *BinaryPayload) Execute(limitedGas *util.Uint128, tx *Transaction, block *Block, ws WorldState) (*util.Uint128, string, error) {
+ if block == nil || tx == nil || tx.to == nil {
+ return util.NewUint128(), "", ErrNilArgument
+ }
+
+ // transfer to contract
+ if tx.to.Type() == ContractAddress && block.height >= AcceptFuncAvailableHeight {
+ // payloadGasLimit <= 0, v8 engine not limit the execution instructions
+ if limitedGas.Cmp(util.NewUint128()) <= 0 {
+ return util.NewUint128(), "", ErrOutOfGasLimit
+ }
+
+ // contract address is tx.to.
+ contract, err := CheckContract(tx.to, ws)
+ if err != nil {
+ return util.NewUint128(), "", err
+ }
+
+ birthTx, err := GetTransaction(contract.BirthPlace(), ws)
+ if err != nil {
+ return util.NewUint128(), "", err
+ }
+ deploy, err := LoadDeployPayload(birthTx.data.Payload) // ToConfirm: move deploy payload in ctx.
+ if err != nil {
+ return util.NewUint128(), "", err
+ }
+
+ engine, err := block.nvm.CreateEngine(block, tx, contract, ws)
+ if err != nil {
+ return util.NewUint128(), "", err
+ }
+ defer engine.Dispose()
+
+ if err := engine.SetExecutionLimits(limitedGas.Uint64(), DefaultLimitsOfTotalMemorySize); err != nil {
+ return util.NewUint128(), "", err
+ }
+
+ result, exeErr := engine.Call(deploy.Source, deploy.SourceType, ContractAcceptFunc, "")
+ gasCout := engine.ExecutionInstructions()
+ instructions, err := util.NewUint128FromInt(int64(gasCout))
+ if err != nil {
+ return util.NewUint128(), "", err
+ }
+ if exeErr == ErrExecutionFailed && len(result) > 0 {
+ exeErr = fmt.Errorf("Binary: %s", result)
+ }
+ if exeErr != nil {
+ return instructions, "", exeErr
+ }
+ }
+
return util.NewUint128(), "", nil
}
diff --git a/core/transaction_call_payload.go b/core/transaction_call_payload.go
index be899ad3c..cacda201d 100644
--- a/core/transaction_call_payload.go
+++ b/core/transaction_call_payload.go
@@ -115,7 +115,7 @@ func (payload *CallPayload) Execute(limitedGas *util.Uint128, tx *Transaction, b
if err != nil {
return util.NewUint128(), "", err
}
- if exeErr != nil && exeErr == ErrExecutionFailed && len(result) > 0 {
+ if exeErr == ErrExecutionFailed && len(result) > 0 {
exeErr = fmt.Errorf("Call: %s", result)
}
return instructions, result, exeErr
diff --git a/core/types.go b/core/types.go
index 1613160b3..d514f1917 100644
--- a/core/types.go
+++ b/core/types.go
@@ -51,6 +51,11 @@ const (
SourceTypeTypeScript = "ts"
)
+// Const
+const (
+ ContractAcceptFunc = "accept"
+)
+
var (
// PublicFuncNameChecker in smart contract
PublicFuncNameChecker = regexp.MustCompile("^[a-zA-Z$][A-Za-z0-9_$]*$")
@@ -75,6 +80,7 @@ var (
ErrCannotFindBlockAtGivenHeight = errors.New("cannot find a block at given height which is less than tail block's height")
ErrInvalidBlockCannotFindParentInLocalAndTryDownload = errors.New("invalid block received, download its parent from others")
ErrInvalidBlockCannotFindParentInLocalAndTrySync = errors.New("invalid block received, sync its parent from others")
+ ErrBlockNotFound = errors.New("block not found in blockchain cache nor chain")
ErrInvalidConfigChainID = errors.New("invalid chainID, genesis chainID not equal to chainID in config")
ErrCannotLoadGenesisConf = errors.New("cannot load genesis conf")
@@ -90,6 +96,8 @@ var (
ErrDoubleSealBlock = errors.New("cannot seal a block twice")
ErrDuplicatedBlock = errors.New("duplicated block")
ErrDoubleBlockMinted = errors.New("double block minted")
+ ErrVRFProofFailed = errors.New("VRF proof failed")
+ ErrInvalidBlockRandom = errors.New("invalid block random")
ErrInvalidChainID = errors.New("invalid transaction chainID")
ErrInvalidTransactionSigner = errors.New("invalid transaction signer")
@@ -212,6 +220,8 @@ type Consensus interface {
GenesisConsensusState(*BlockChain, *corepb.Genesis) (state.ConsensusState, error)
CheckTimeout(*Block) bool
CheckDoubleMint(*Block) bool
+
+ NumberOfBlocksInDynasty() uint64
}
// SyncService interface of sync service
@@ -235,6 +245,7 @@ type AccountManager interface {
SignHash(*Address, byteutils.Hash, keystore.Algorithm) ([]byte, error)
SignBlock(*Address, *Block) error
+ GenerateRandomSeed(*Address, ...[]byte) ([]byte, []byte, error)
SignTransaction(*Address, *Transaction) error
SignTransactionWithPassphrase(*Address, *Transaction, []byte) error
diff --git a/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF.go b/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF.go
new file mode 100644
index 000000000..7f53c37eb
--- /dev/null
+++ b/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF.go
@@ -0,0 +1,331 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Implements a verifiable random function using curve secp256k1.
+
+package secp256k1VRF
+
+// Discrete Log based VRF from Appendix A of CONIKS:
+// http://www.jbonneau.com/doc/MBBFF15-coniks.pdf
+// based on "Unique Ring Signatures, a Practical Construction"
+// http://fc13.ifca.ai/proc/5-1.pdf
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/binary"
+ "errors"
+ "io"
+ "math/big"
+
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1"
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1/bitelliptic"
+
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1/vrf"
+)
+
+var (
+ curve = bitelliptic.S256()
+ params = curve.Params()
+
+ // ErrPointNotOnCurve occurs when a public key is not on the curve.
+ ErrPointNotOnCurve = errors.New("point is not on the P256 curve")
+ // ErrWrongKeyType occurs when a key is not an ECDSA key.
+ ErrWrongKeyType = errors.New("not an ECDSA key")
+ // ErrNoPEMFound occurs when attempting to parse a non PEM data structure.
+ ErrNoPEMFound = errors.New("no PEM block found")
+ // ErrInvalidVRF occurs when the VRF does not validate.
+ ErrInvalidVRF = errors.New("invalid VRF proof")
+ // ErrEvaluateFailed fail
+ ErrEvaluateFailed = errors.New("failed to evaluate VRF")
+)
+
+// PublicKey holds a public VRF key.
+type PublicKey struct {
+ *ecdsa.PublicKey
+}
+
+// PrivateKey holds a private VRF key.
+type PrivateKey struct {
+ *ecdsa.PrivateKey
+}
+
+// GenerateKey generates a fresh keypair for this VRF
+func GenerateKey() (vrf.PrivateKey, vrf.PublicKey) {
+ key, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ return nil, nil
+ }
+
+ return &PrivateKey{key}, &PublicKey{&key.PublicKey}
+}
+
+// H1 hashes m to a curve point
+func H1(m []byte) (x, y *big.Int) {
+ h := sha512.New()
+ var i uint32
+ byteLen := (params.BitSize + 7) >> 3
+ for x == nil && i < 100 {
+ // TODO: Use a NIST specified DRBG.
+ h.Reset()
+ binary.Write(h, binary.BigEndian, i)
+ h.Write(m)
+ r := []byte{2} // Set point encoding to "compressed", y=0.
+ r = h.Sum(r)
+ x, y = Unmarshal(curve, r[:byteLen+1])
+ i++
+ }
+ return
+}
+
+var one = big.NewInt(1)
+
+// H2 hashes to an integer [1,N-1]
+func H2(m []byte) *big.Int {
+ // NIST SP 800-90A § A.5.1: Simple discard method.
+ byteLen := (params.BitSize + 7) >> 3
+ h := sha512.New()
+ for i := uint32(0); ; i++ {
+ // TODO: Use a NIST specified DRBG.
+ h.Reset()
+ binary.Write(h, binary.BigEndian, i)
+ h.Write(m)
+ b := h.Sum(nil)
+ k := new(big.Int).SetBytes(b[:byteLen])
+ if k.Cmp(new(big.Int).Sub(params.N, one)) == -1 {
+ return k.Add(k, one)
+ }
+ }
+}
+
+// Evaluate returns the verifiable unpredictable function evaluated at m
+func (k PrivateKey) Evaluate(m []byte) (index [32]byte, proof []byte) {
+ nilIndex := [32]byte{}
+ // Prover chooses r <-- [1,N-1]
+ r, _, _, err := generateKeyFromCurve(curve, rand.Reader)
+ if err != nil {
+ return nilIndex, nil
+ }
+ ri := new(big.Int).SetBytes(r)
+
+ // H = H1(m)
+ Hx, Hy := H1(m)
+
+ // VRF_k(m) = [k]H
+ sHx, sHy := curve.ScalarMult(Hx, Hy, k.D.Bytes())
+
+ // vrf := elliptic.Marshal(curve, sHx, sHy) // 65 bytes.
+ vrf := curve.Marshal(sHx, sHy) // 65 bytes.
+
+ // G is the base point
+ // s = H2(G, H, [k]G, VRF, [r]G, [r]H)
+ rGx, rGy := curve.ScalarBaseMult(r)
+ rHx, rHy := curve.ScalarMult(Hx, Hy, r)
+ var b bytes.Buffer
+ b.Write(curve.Marshal(params.Gx, params.Gy))
+ b.Write(curve.Marshal(Hx, Hy))
+ b.Write(curve.Marshal(k.PublicKey.X, k.PublicKey.Y))
+ b.Write(vrf)
+ b.Write(curve.Marshal(rGx, rGy))
+ b.Write(curve.Marshal(rHx, rHy))
+ s := H2(b.Bytes())
+
+ // t = r−s*k mod N
+ t := new(big.Int).Sub(ri, new(big.Int).Mul(s, k.D))
+ t.Mod(t, params.N)
+
+ // Index = H(vrf)
+ index = sha256.Sum256(vrf)
+
+ // Write s, t, and vrf to a proof blob. Also write leading zeros before s and t
+ // if needed.
+ var buf bytes.Buffer
+ buf.Write(make([]byte, 32-len(s.Bytes())))
+ buf.Write(s.Bytes())
+ buf.Write(make([]byte, 32-len(t.Bytes())))
+ buf.Write(t.Bytes())
+ buf.Write(vrf)
+
+ return index, buf.Bytes()
+}
+
+// ProofToHash asserts that proof is correct for m and outputs index.
+func (pk *PublicKey) ProofToHash(m, proof []byte) (index [32]byte, err error) {
+ nilIndex := [32]byte{}
+ // verifier checks that s == H2(m, [t]G + [s]([k]G), [t]H1(m) + [s]VRF_k(m))
+ if got, want := len(proof), 64+65; got != want {
+ return nilIndex, ErrInvalidVRF
+ }
+
+ // Parse proof into s, t, and vrf.
+ s := proof[0:32]
+ t := proof[32:64]
+ vrf := proof[64 : 64+65]
+
+ // uHx, uHy := elliptic.Unmarshal(curve, vrf)
+ uHx, uHy := curve.Unmarshal(vrf) //////???
+ if uHx == nil {
+ return nilIndex, ErrInvalidVRF
+ }
+
+ // [t]G + [s]([k]G) = [t+ks]G
+ tGx, tGy := curve.ScalarBaseMult(t)
+ ksGx, ksGy := curve.ScalarMult(pk.X, pk.Y, s)
+ tksGx, tksGy := curve.Add(tGx, tGy, ksGx, ksGy)
+
+ // H = H1(m)
+ // [t]H + [s]VRF = [t+ks]H
+ Hx, Hy := H1(m)
+ tHx, tHy := curve.ScalarMult(Hx, Hy, t)
+ sHx, sHy := curve.ScalarMult(uHx, uHy, s)
+ tksHx, tksHy := curve.Add(tHx, tHy, sHx, sHy)
+
+ // H2(G, H, [k]G, VRF, [t]G + [s]([k]G), [t]H + [s]VRF)
+ // = H2(G, H, [k]G, VRF, [t+ks]G, [t+ks]H)
+ // = H2(G, H, [k]G, VRF, [r]G, [r]H)
+ var b bytes.Buffer
+ b.Write(curve.Marshal(params.Gx, params.Gy))
+ b.Write(curve.Marshal(Hx, Hy))
+ b.Write(curve.Marshal(pk.X, pk.Y))
+ b.Write(vrf)
+ b.Write(curve.Marshal(tksGx, tksGy))
+ b.Write(curve.Marshal(tksHx, tksHy))
+ h2 := H2(b.Bytes())
+
+ // Left pad h2 with zeros if needed. This will ensure that h2 is padded
+ // the same way s is.
+ var buf bytes.Buffer
+ buf.Write(make([]byte, 32-len(h2.Bytes())))
+ buf.Write(h2.Bytes())
+
+ if !hmac.Equal(s, buf.Bytes()) {
+ return nilIndex, ErrInvalidVRF
+ }
+ return sha256.Sum256(vrf), nil
+}
+
+// NewFromWrappedKey creates a VRF signer object from an encrypted private key.
+// The opaque private key must resolve to an `ecdsa.PrivateKey` in order to work.
+// func NewFromWrappedKey(ctx context.Context, wrapped proto.Message) (vrf.PrivateKey, error) {
+// // Unwrap.
+// signer, err := keys.NewSigner(ctx, wrapped)
+// if err != nil {
+// return nil, err
+// }
+
+// switch key := signer.(type) {
+// case *ecdsa.PrivateKey:
+// return NewVRFSigner(key)
+// default:
+// return nil, fmt.Errorf("NewSigner().type: %T, want ecdsa.PrivateKey", key)
+// }
+// }
+
+// NewVRFSigner creates a signer object from a private key.
+func NewVRFSigner(key *ecdsa.PrivateKey) (vrf.PrivateKey, error) {
+ if *(key.Params()) != *curve.Params() {
+ return nil, ErrPointNotOnCurve
+ }
+ if !curve.IsOnCurve(key.X, key.Y) {
+ return nil, ErrPointNotOnCurve
+ }
+ return &PrivateKey{key}, nil
+}
+
+// Public returns the corresponding public key as bytes.
+func (k PrivateKey) Public() crypto.PublicKey {
+ return &k.PublicKey
+}
+
+// NewVRFVerifier creates a verifier object from a public key.
+func NewVRFVerifier(pubkey *ecdsa.PublicKey) (vrf.PublicKey, error) {
+ if *(pubkey.Params()) != *curve.Params() {
+ return nil, ErrPointNotOnCurve
+ }
+ if !curve.IsOnCurve(pubkey.X, pubkey.Y) {
+ return nil, ErrPointNotOnCurve
+ }
+ return &PublicKey{pubkey}, nil
+}
+
+// NewVRFSignerFromPEM creates a vrf private key from a PEM data structure.
+// func NewVRFSignerFromPEM(b []byte) (vrf.PrivateKey, error) {
+// p, _ := pem.Decode(b)
+// if p == nil {
+// return nil, ErrNoPEMFound
+// }
+// return NewVRFSignerFromRawKey(p.Bytes)
+// }
+
+// NewVRFSignerFromRawKey returns the private key from a raw private key bytes.
+func NewVRFSignerFromRawKey(b []byte) (vrf.PrivateKey, error) {
+ k, err := secp256k1.ToECDSAPrivateKey(b)
+ if err != nil {
+ return nil, err
+ }
+ return NewVRFSigner(k)
+}
+
+// NewVRFVerifierFromPEM creates a vrf public key from a PEM data structure.
+// func NewVRFVerifierFromPEM(b []byte) (vrf.PublicKey, error) {
+// p, _ := pem.Decode(b)
+// if p == nil {
+// return nil, ErrNoPEMFound
+// }
+// return NewVRFVerifierFromRawKey(p.Bytes)
+// }
+
+// NewVRFVerifierFromRawKey returns the public key from a raw public key bytes.
+func NewVRFVerifierFromRawKey(b []byte) (vrf.PublicKey, error) {
+ k, err := secp256k1.ToECDSAPublicKey(b)
+ if err != nil {
+ return nil, err
+ }
+ return NewVRFVerifier(k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+func generateKeyFromCurve(curve *bitelliptic.BitCurve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ N := curve.Params().N
+ bitSize := N.BitLen()
+ byteLen := (bitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[bitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+
+ // If the scalar is out of range, sample another random number.
+ if new(big.Int).SetBytes(priv).Cmp(N) >= 0 {
+ continue
+ }
+
+ x, y = curve.ScalarBaseMult(priv)
+ }
+ return
+}
diff --git a/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF_test.go b/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF_test.go
new file mode 100644
index 000000000..5d87a51e5
--- /dev/null
+++ b/crypto/keystore/secp256k1/vrf/secp256k1VRF/secp256k1VRF_test.go
@@ -0,0 +1,362 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package secp256k1VRF
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "math"
+ "testing"
+ "time"
+
+ "github.com/nebulasio/go-nebulas/crypto/keystore/secp256k1"
+ "github.com/nebulasio/go-nebulas/util/byteutils"
+ // _ "github.com/google/trillian/crypto/keys/der/proto"
+)
+
+const (
+ // private key in hex
+ privKey = `b02b430d4a9d7120b65038452a6da3f3c716829e5be3665adf934d4798d96ed7`
+ // public key in hex
+ pubKey = `04e4d0dde330c0b8d8d8b1b2071aa75c3e94f200a3d11ca1d908644eee50c8833a816dc0b2d003fc66187ef6750a56e1b3004d32e6159008400ab92f2ded7b4544`
+)
+
+func TestH1(t *testing.T) {
+ for i := 0; i < 10000; i++ {
+ m := make([]byte, 100)
+ if _, err := rand.Read(m); err != nil {
+ t.Fatalf("Failed generating random message: %v", err)
+ }
+ x, y := H1(m)
+ if x == nil {
+ t.Errorf("H1(%v)=%v, want curve point", m, x)
+ }
+ // attention: should not use curve.Params(), that will use elliptic.IsOnCurve()
+ if got := curve.IsOnCurve(x, y); !got {
+ t.Errorf("H1(%v)=[%v, %v], is not on curve", m, x, y)
+ }
+ }
+}
+
+func TestH2(t *testing.T) {
+ l := 32
+ for i := 0; i < 10000; i++ {
+ m := make([]byte, 100)
+ if _, err := rand.Read(m); err != nil {
+ t.Fatalf("Failed generating random message: %v", err)
+ }
+ x := H2(m)
+ if got := len(x.Bytes()); got < 1 || got > l {
+ t.Errorf("len(h2(%v)) = %v, want: 1 <= %v <= %v", m, got, got, l)
+ }
+ }
+}
+
+func TestEmmm(t *testing.T) {
+ k, pk := GenerateKey()
+ m1 := []byte("da30b4ed14affb62b3719fb5e6952d3733e84e53fe6e955f8e46da503300c985")
+ index1, proof1 := k.Evaluate(m1)
+ fmt.Println("evaluate index = ", index1)
+ fmt.Println("evaluate proof = ", proof1)
+
+ start := time.Now()
+ for i := 0; i < 100; i++ {
+ _, _ = k.Evaluate(m1)
+ }
+ end := time.Now()
+ fmt.Println("evaluate x100 total time: ", end.Sub(start))
+
+ index, _ := pk.ProofToHash(m1, proof1)
+ fmt.Println("proof index = ", index)
+
+ start = time.Now()
+ for i := 0; i < 100; i++ {
+ _, _ = pk.ProofToHash(m1, proof1)
+ }
+ end = time.Now()
+ fmt.Println("proof x100 total time: ", end.Sub(start))
+}
+
+func TestVRF(t *testing.T) {
+ k, pk := GenerateKey()
+
+ m1 := []byte("data1")
+ m2 := []byte("data2")
+ m3 := []byte("data2")
+ index1, proof1 := k.Evaluate(m1)
+ index2, proof2 := k.Evaluate(m2)
+ index3, proof3 := k.Evaluate(m3)
+ for _, tc := range []struct {
+ m []byte
+ index [32]byte
+ proof []byte
+ err error
+ }{
+ {m1, index1, proof1, nil},
+ {m2, index2, proof2, nil},
+ {m3, index3, proof3, nil},
+ {m3, index3, proof2, nil},
+ {m3, index3, proof1, ErrInvalidVRF},
+ } {
+ index, err := pk.ProofToHash(tc.m, tc.proof)
+ if got, want := err, tc.err; got != want {
+ t.Errorf("ProofToHash(%s, %x): %v, want %v", tc.m, tc.proof, got, want)
+ }
+ if err != nil {
+ continue
+ }
+ if got, want := index, tc.index; got != want {
+ t.Errorf("ProofToInex(%s, %x): %x, want %x", tc.m, tc.proof, got, want)
+ }
+ }
+}
+
+func TestProofToHash(t *testing.T) {
+ bytes, _ := byteutils.FromHex(pubKey)
+ pk, err := NewVRFVerifierFromRawKey(bytes)
+ if err != nil {
+ t.Errorf("NewVRFSigner failure: %v", err)
+ }
+
+ for _, tc := range []struct {
+ m []byte
+ index [32]byte
+ proof []byte
+ }{
+ {
+ m: []byte("data1"),
+ index: h2i("a2f4f844d46240a86790c177f21422f430b2803c7590f32625079fc13a5fe601"),
+ proof: h2b("cc23d0e1e01a20bcee479e944c94febabb8e762fa64b9443fc9dc31d3332e3a7024f4adc2cda4e8847fe67f47ab0084b677996e9325d31840531a2f91d6a5d7d04e54044c12dd5ab7b90a57117a85d6307125496ada896d9823c860c4f492c0096c714705d58ee7d66ee6cffb5f1320c5eab7f92490b0f5759145588efa0b0537d"),
+ },
+ {
+ m: []byte("data2"),
+ index: h2i("008a288a33a2620458a26b6c995d9c16ca46c293562db76985bd1b2a159efc76"),
+ proof: h2b("888e0d3191af542c40d0d8b15255e106a133ec9b219b6e26900e07a252e6ab60e510423c34bf74cc602ae2be214bffadfd639793d0a3dccd0e7303be8d0de57604322cef265dfe906cebf30de74b14aa33723435eccea3153fedb5bea70e5c58a8969af97c27e50223bc3b9a8dd8f4a60ec363a78c957f366af075cf83cc43e61c"),
+ },
+ {
+ m: []byte("data3"),
+ index: h2i("9bb53b519519a85c8c6c6739349168c42ae208aed7dadeababf5a067a6ac1313"),
+ proof: h2b("96004eb1450c68fcb1ac83e0f09c5311089829762a5e8aecdba1c51d703250d79bc9ffeb72c0c5645da6c3d2d59a5c6428b1d3a0075d75b89bae8b539453e3af044a472b26f259bd5a84f05ec8fe1d7858d6f5606adcb6febeef113a2ff4ff69d5166ebbd3c3a78c451d751490eeb37fd39358fb2fad8ae218e3fc5177fe2e9b37"),
+ },
+ } {
+
+ bytes, _ := byteutils.FromHex(privKey)
+ k, err := NewVRFSignerFromRawKey(bytes)
+ idx, proof := k.Evaluate(tc.m)
+ fmt.Println("=======")
+ fmt.Println(byteutils.Hex(idx[0:]))
+ fmt.Println(byteutils.Hex(proof))
+
+ index, err := pk.ProofToHash(tc.m, tc.proof)
+ if err != nil {
+ t.Errorf("ProofToHash(%s, %x): %v, want nil", tc.m, tc.proof, err)
+ continue
+ }
+ if got, want := index, tc.index; got != want {
+ t.Errorf("ProofToHash(%s, %x): %x, want %x", tc.m, tc.proof, got, want)
+ }
+ }
+}
+
+func TestReadFromOpenSSL(t *testing.T) {
+ for _, tc := range []struct {
+ priv string
+ pub string
+ }{
+ {privKey, pubKey},
+ } {
+ // Private VRF Key
+ bytes, _ := byteutils.FromHex(tc.priv)
+ signer, err := NewVRFSignerFromRawKey(bytes)
+ if err != nil {
+ t.Errorf("NewVRFSigner failure: %v", err)
+ }
+
+ // Public VRF key
+ bytes, _ = byteutils.FromHex(tc.pub)
+ verifier, err := NewVRFVerifierFromRawKey(bytes)
+ if err != nil {
+ t.Errorf("NewVRFSigner failure: %v", err)
+ }
+
+ // Evaluate and verify.
+ m := []byte("M")
+ _, proof := signer.Evaluate(m)
+ if _, err := verifier.ProofToHash(m, proof); err != nil {
+ t.Errorf("Failed verifying VRF proof")
+ }
+ }
+}
+
+func TestRightTruncateProof(t *testing.T) {
+ k, pk := GenerateKey()
+
+ data := []byte("data")
+ _, proof := k.Evaluate(data)
+ proofLen := len(proof)
+ for i := 0; i < proofLen; i++ {
+ proof = proof[:len(proof)-1]
+ if _, err := pk.ProofToHash(data, proof); err == nil {
+ t.Errorf("Verify unexpectedly succeeded after truncating %v bytes from the end of proof", i)
+ }
+ }
+}
+
+func TestLeftTruncateProof(t *testing.T) {
+ k, pk := GenerateKey()
+
+ data := []byte("data")
+ _, proof := k.Evaluate(data)
+ proofLen := len(proof)
+ for i := 0; i < proofLen; i++ {
+ proof = proof[1:]
+ if _, err := pk.ProofToHash(data, proof); err == nil {
+ t.Errorf("Verify unexpectedly succeeded after truncating %v bytes from the beginning of proof", i)
+ }
+ }
+}
+
+func TestBitFlip(t *testing.T) {
+ k, pk := GenerateKey()
+
+ data := []byte("data")
+ _, proof := k.Evaluate(data)
+ for i := 0; i < len(proof)*8; i++ {
+ // Flip bit in position i.
+ if _, err := pk.ProofToHash(data, flipBit(proof, i)); err == nil {
+ t.Errorf("Verify unexpectedly succeeded after flipping bit %v of vrf", i)
+ }
+ }
+}
+
+func flipBit(a []byte, pos int) []byte {
+ index := int(math.Floor(float64(pos) / 8))
+ b := byte(a[index])
+ b ^= (1 << uint(math.Mod(float64(pos), 8.0)))
+
+ var buf bytes.Buffer
+ buf.Write(a[:index])
+ buf.Write([]byte{b})
+ buf.Write(a[index+1:])
+ return buf.Bytes()
+}
+
+func TestVectors(t *testing.T) {
+ bytes, _ := byteutils.FromHex(privKey)
+ k, err := NewVRFSignerFromRawKey(bytes)
+ if err != nil {
+ t.Errorf("NewVRFSigner failure: %v", err)
+ }
+ bytes, _ = byteutils.FromHex(pubKey)
+ pk, err := NewVRFVerifierFromRawKey(bytes)
+ if err != nil {
+ t.Errorf("NewVRFSigner failure: %v", err)
+ }
+ for _, tc := range []struct {
+ m []byte
+ index [32]byte
+ }{
+ {
+ m: []byte("test"),
+ index: h2i("c095a258b89a5fbf0790e45cd2b1a31c1723f0f99c7df3df98e03eef2a4a25af"),
+ },
+ {
+ m: nil,
+ index: h2i("19a1da136a3dadfd4ffb2e95d0b236b72e7bd448541a46fde595acd5052775cb"),
+ },
+ } {
+ index, proof := k.Evaluate(tc.m)
+ if got, want := index, tc.index; got != want {
+ t.Errorf("Evaluate(%s).Index: %x, want %x", tc.m, got, want)
+ }
+ index2, err := pk.ProofToHash(tc.m, proof)
+ if err != nil {
+ t.Errorf("ProofToHash(%s): %v", tc.m, err)
+ }
+ if got, want := index2, index; got != want {
+ t.Errorf("ProofToHash(%s): %x, want %x", tc.m, got, want)
+ }
+ }
+}
+
+func h2i(h string) [32]byte {
+ b, err := hex.DecodeString(h)
+ if err != nil {
+ panic("Invalid hex")
+ }
+ var i [32]byte
+ copy(i[:], b)
+ return i
+}
+
+func h2b(h string) []byte {
+ b, err := hex.DecodeString(h)
+ if err != nil {
+ panic("Invalid hex")
+ }
+ return b
+}
+
+func Test256VRF(t *testing.T) {
+
+ seckey, err := byteutils.FromHex(privKey)
+ if err != nil {
+ t.Errorf("load priv err: %v", err)
+ }
+ ecdsaPriv, err := secp256k1.ToECDSAPrivateKey(seckey)
+ if err != nil {
+ t.Errorf("ecdsa err: %v", err)
+ }
+
+ signer, err := NewVRFSigner(ecdsaPriv)
+ if err != nil {
+ t.Errorf("new signer err: %v", err)
+ }
+
+ data := []byte("b10c1203d5ae6d4d069d5f520eb060f2f5fb74e942f391e7cadbc2b5148dfbcb")
+ sIndex, proof := signer.Evaluate(data)
+
+ seckeyPub, err := byteutils.FromHex(pubKey)
+
+ priv := new(secp256k1.PrivateKey)
+ err = priv.Decode(seckey)
+ if err != nil {
+ t.Errorf("decode priv err: %v", err)
+ }
+
+ epub, err := priv.PublicKey().Encoded()
+ if err != nil {
+ t.Errorf("encode pub err: %v", err)
+ }
+ if !bytes.Equal(seckeyPub, epub) {
+ t.Errorf("mismatched priv/pub err: %v", err)
+ }
+
+ verifier, err := NewVRFVerifierFromRawKey(seckeyPub)
+ if err != nil {
+ t.Errorf("new verifier err: %v", err)
+ }
+
+ vIndex, err := verifier.ProofToHash(data, proof)
+ if err != nil {
+ t.Errorf("exec proof err: %v", err)
+ }
+
+ if !bytes.Equal(sIndex[0:], vIndex[0:]) {
+ t.Errorf("verification failed")
+ }
+}
diff --git a/crypto/keystore/secp256k1/vrf/secp256k1VRF/unmarshal.go b/crypto/keystore/secp256k1/vrf/secp256k1VRF/unmarshal.go
new file mode 100644
index 000000000..c30ac11b9
--- /dev/null
+++ b/crypto/keystore/secp256k1/vrf/secp256k1VRF/unmarshal.go
@@ -0,0 +1,89 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package secp256k1VRF
+
+// This file implements compressed point unmarshaling. Preferably this
+// functionality would be in a standard library. Code borrowed from:
+// https://go-review.googlesource.com/#/c/1883/2/src/crypto/elliptic/elliptic.go
+
+import (
+ "crypto/elliptic"
+ "math/big"
+)
+
+// Unmarshal a compressed point in the form specified in section 4.3.6 of ANSI X9.62.
+func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) {
+ byteLen := (curve.Params().BitSize + 7) >> 3
+ if (data[0] &^ 1) != 2 {
+ return // unrecognized point encoding
+ }
+ if len(data) != 1+byteLen {
+ return
+ }
+
+ // Based on Routine 2.2.4 in NIST Mathematical routines paper
+ params := curve.Params()
+ tx := new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y2 := y2(params, tx)
+ sqrt := defaultSqrt
+ ty := sqrt(y2, params.P)
+ if ty == nil {
+ return // "y^2" is not a square: invalid point
+ }
+ var y2c big.Int
+ y2c.Mul(ty, ty).Mod(&y2c, params.P)
+ if y2c.Cmp(y2) != 0 {
+ return // sqrt(y2)^2 != y2: invalid point
+ }
+ if ty.Bit(0) != uint(data[0]&1) {
+ ty.Sub(params.P, ty)
+ }
+
+ x, y = tx, ty // valid point: return it
+ return
+}
+
+// Use the curve equation to calculate y² given x.
+// only applies to curves of the form y² = x³ - 3x + b.
+func y2(curve *elliptic.CurveParams, x *big.Int) *big.Int {
+
+ // y² = x³ - 3x + b
+ // x3 := new(big.Int).Mul(x, x)
+ // x3.Mul(x3, x)
+
+ // threeX := new(big.Int).Lsh(x, 1)
+ // threeX.Add(threeX, x)
+
+ // x3.Sub(x3, threeX)
+ // x3.Add(x3, curve.B)
+ // x3.Mod(x3, curve.P)
+
+ // change to bitelliptic : y² = x³ + b
+ x3 := new(big.Int).Mul(x, x)
+ x3.Mul(x3, x)
+
+ x3.Add(x3, curve.B)
+ x3.Mod(x3, curve.P)
+
+ return x3
+}
+
+func defaultSqrt(x, p *big.Int) *big.Int {
+ var r big.Int
+ if nil == r.ModSqrt(x, p) {
+ return nil // x is not a square
+ }
+ return &r
+}
diff --git a/crypto/keystore/secp256k1/vrf/vrf.go b/crypto/keystore/secp256k1/vrf/vrf.go
new file mode 100644
index 000000000..28c522254
--- /dev/null
+++ b/crypto/keystore/secp256k1/vrf/vrf.go
@@ -0,0 +1,35 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package vrf defines the interface to a verifiable random function.
+
+// http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=814584
+
+package vrf
+
+import "crypto"
+
+// PrivateKey supports evaluating the VRF function.
+type PrivateKey interface {
+ // Evaluate returns the output of H(f_k(m)) and its proof.
+ Evaluate(m []byte) (index [32]byte, proof []byte)
+ // Public returns the corresponding public key.
+ Public() crypto.PublicKey
+}
+
+// PublicKey supports verifying output from the VRF function.
+type PublicKey interface {
+ // ProofToHash verifies the NP-proof supplied by Proof and outputs Index.
+ ProofToHash(m, proof []byte) (index [32]byte, err error)
+}
diff --git a/crypto/keystore/secp256k1/vrf/vrf_test.go b/crypto/keystore/secp256k1/vrf/vrf_test.go
new file mode 100644
index 000000000..5a5fcfe8d
--- /dev/null
+++ b/crypto/keystore/secp256k1/vrf/vrf_test.go
@@ -0,0 +1,51 @@
+// Copyright (C) 2018 go-nebulas
+
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+package vrf
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/nebulasio/go-nebulas/crypto"
+ "github.com/nebulasio/go-nebulas/crypto/keystore"
+ "github.com/nebulasio/go-nebulas/util/byteutils"
+)
+
+const (
+ // private key in hex
+ privKey = `b02b430d4a9d7120b65038452a6da3f3c716829e5be3665adf934d4798d96ed7`
+ // public key in hex
+ pubKey = `04e4d0dde330c0b8d8d8b1b2071aa75c3e94f200a3d11ca1d908644eee50c8833a816dc0b2d003fc66187ef6750a56e1b3004d32e6159008400ab92f2ded7b4544`
+)
+
+func TestVRF(t *testing.T) {
+ priv, _ := crypto.NewPrivateKey(keystore.SECP256K1, nil)
+ seckey, err := priv.Encoded()
+ if err != nil {
+ t.Errorf("new priv err: %v", err)
+ }
+ seckeypub, err := priv.PublicKey().Encoded()
+ if err != nil {
+ t.Errorf("pub of new priv err: %v", err)
+ }
+ fmt.Println("1:", byteutils.Hex(seckey))
+ fmt.Println("2:", byteutils.Hex(seckeypub))
+
+}
diff --git a/metrics/metrics.go b/metrics/metrics.go
index 213686136..776167e67 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -95,11 +95,14 @@ func collectSystemMetrics() {
}
allocs := metrics.GetOrRegisterMeter("system_allocs", nil)
+
// totalAllocs := metrics.GetOrRegisterMeter("system_total_allocs", nil)
sys := metrics.GetOrRegisterMeter("system_sys", nil)
frees := metrics.GetOrRegisterMeter("system_frees", nil)
heapInuse := metrics.GetOrRegisterMeter("system_heapInuse", nil)
stackInuse := metrics.GetOrRegisterMeter("system_stackInuse", nil)
+ releases := metrics.GetOrRegisterMeter("system_release", nil)
+
for i := 1; ; i++ {
select {
case <-quitCh:
@@ -107,10 +110,13 @@ func collectSystemMetrics() {
default:
runtime.ReadMemStats(memstats[i%2])
allocs.Mark(int64(memstats[i%2].Alloc - memstats[(i-1)%2].Alloc))
+
sys.Mark(int64(memstats[i%2].Sys - memstats[(i-1)%2].Sys))
frees.Mark(int64(memstats[i%2].Frees - memstats[(i-1)%2].Frees))
heapInuse.Mark(int64(memstats[i%2].HeapInuse - memstats[(i-1)%2].HeapInuse))
stackInuse.Mark(int64(memstats[i%2].StackInuse - memstats[(i-1)%2].StackInuse))
+ releases.Mark(int64(memstats[i%2].HeapReleased - memstats[(i-1)%2].HeapReleased))
+
time.Sleep(2 * time.Second)
}
}
diff --git a/neblet/neblet.go b/neblet/neblet.go
index 9f76b15fe..6c24ea42e 100644
--- a/neblet/neblet.go
+++ b/neblet/neblet.go
@@ -87,6 +87,7 @@ func New(config *nebletpb.Config) (*Neblet, error) {
logging.CLog().Error("Failed to find chain config in config file")
return nil, ErrConfigShouldHasChain
}
+
var err error
n.genesis, err = core.LoadGenesisConf(config.Chain.Genesis)
if err != nil {
diff --git a/nebtestkit/cases/contract/contract.bankvault.test.js b/nebtestkit/cases/contract/contract.bankvault.test.js
index 7a704e0bd..f8077bb02 100644
--- a/nebtestkit/cases/contract/contract.bankvault.test.js
+++ b/nebtestkit/cases/contract/contract.bankvault.test.js
@@ -2,7 +2,7 @@
var HttpRequest = require("../../node-request");
-var Wallet = require("../../../cmd/console/neb.js/lib/wallet");
+var Wallet = require("nebulas");
var Account = Wallet.Account;
var Transaction = Wallet.Transaction;
var Utils = Wallet.Utils;
@@ -24,6 +24,7 @@ var coinState;
var redeploy = process.env.REDEPLOY || true;
var scriptType = process.env.script || 'js';
var env = process.env.NET || 'local';
+var blockInterval = 15;
// mocha cases/contract/xxx testneb1 -t 200000
var args = process.argv.splice(2);
@@ -36,8 +37,8 @@ console.log("env:", env);
if (env === 'local') {
neb.setRequest(new HttpRequest("http://127.0.0.1:8685"));//https://testnet.nebulas.io
ChainID = 100;
- sourceAccount = new Wallet.Account("a6e5eb290e1438fce79f5cb8774a72621637c2c9654c8b2525ed1d7e4e73653f");
- coinbase = "eb31ad2d8a89a0ca6935c308d5425730430bc2d63f2573b8";
+ sourceAccount = new Wallet.Account("1d3fe06a53919e728315e2ccca41d4aa5b190845a79007797517e62dbc0df454");
+ coinbase = "n1QZMXSZtW7BUerroSms4axNfyBGyFGkrh5";
if (!redeploy) {
contractAddr = "e5a02995444628cf7935e3ef8b613299a2d97e6d188ce808"; //js
// contractAddr = "557fccaf2f05d4b46156e9b98ca9726f1c9e91d95d3830a7"; //ts
@@ -55,8 +56,8 @@ if (env === 'local') {
} else if (env === "testneb2") {
neb.setRequest(new HttpRequest("http://34.205.26.12:8685"));
ChainID = 1002;
- sourceAccount = new Wallet.Account("43181d58178263837a9a6b08f06379a348a5b362bfab3631ac78d2ac771c5df3");
- coinbase = "0b9cd051a6d7129ab44b17833c63fe4abead40c3714cde6d";
+ sourceAccount = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+ coinbase = "n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17";
if (!redeploy) {
contractAddr = "";
}
@@ -83,11 +84,12 @@ var initFromBalance = 10;
* set this value according to the status of your testnet.
* the smaller the value, the faster the test, with the risk of causing error
*/
-var maxCheckTime = 100;
+var maxCheckTime = 15;
var checkTimes = 0;
var beginCheckTime;
function checkTransaction(hash, callback) {
+ console.log("==>checkTransaction");
if (checkTimes === 0) {
beginCheckTime = new Date().getTime();
}
@@ -104,29 +106,32 @@ function checkTransaction(hash, callback) {
if (resp.status === 2) {
setTimeout(function(){
checkTransaction(hash, callback)
- }, 2000)
+ }, 5000)
} else {
checkTimes = 0;
var endCheckTime = new Date().getTime();
console.log("check tx time: : " + (endCheckTime - beginCheckTime) / 1000);
callback(resp);
+ return
}
}).catch(function (err) {
console.log("fail to get tx receipt hash: '" + hash + "' probably being packing, continue checking...")
- console.log(err.error)
+ console.log(err);
+ console.log(err.error);
setTimeout(function(){
checkTransaction(hash, callback)
- }, 2000)
+ }, 5000)
});
}
function deployContract(testInput, done) {
+ console.log("==> deployContract");
neb.api.getAccountState(from.getAddressString()).then(function(state){
fromState = state;
console.log("from state: " + JSON.stringify(fromState));
}).then(function(){
- var filepath = "./nf/nvm/test/bank_vault_contract." + testInput.contractType;
+ var filepath = "../nf/nvm/test/bank_vault_contract." + testInput.contractType;
console.log("deploying contract: " + filepath);
var bankvault = FS.readFileSync(filepath, "utf-8");
var contract = {
@@ -142,6 +147,7 @@ function deployContract(testInput, done) {
console.log(err.error);
done(err);
}).then(function(resp){
+ console.log("111: result", resp);
expect(resp).to.be.have.property('txhash');
expect(resp).to.be.have.property('contract_address');
contractAddr = resp.contract_address;
@@ -168,6 +174,7 @@ var fromBalanceBefore,
txInfo = {};
function testSave(testInput, testExpect, done) {
+ console.log("==> testSave");
var call = {
"function": testInput.func,
@@ -191,7 +198,8 @@ function testSave(testInput, testExpect, done) {
});
return neb.api.estimateGas(from.getAddressString(), contractAddr,
- testInput.value, txInfo.nonce, 0, testInput.gasLimit, txInfo.call);
+ testInput.value, txInfo.nonce, testInput.gasPrice, testInput.gasLimit, txInfo.call);
+
}).then(function(resp){
expect(resp).to.have.property('gas');
gasUsed = resp.gas;
@@ -259,6 +267,7 @@ function testSave(testInput, testExpect, done) {
}
function testTakeout(testInput, testExpect, done) {
+ console.log("==>testTakeout");
neb.api.getAccountState(contractAddr).then(function(state){
console.log("[before take] contract state: " + JSON.stringify(state));
contractBalanceBefore = new BigNumber(state.balance);
@@ -282,7 +291,7 @@ function testTakeout(testInput, testExpect, done) {
tx.signTransaction();
neb.api.estimateGas(from.getAddressString(), contractAddr,
- testInput.value, parseInt(state.nonce) + 1, 0, testInput.gasLimit, call).then(function(resp){
+ testInput.value, parseInt(state.nonce) + 1, testInput.gasPrice, testInput.gasLimit, call).then(function(resp){
expect(resp).to.have.property('gas');
gasUsed = resp.gas;
}).catch(function(err) {
@@ -293,67 +302,73 @@ function testTakeout(testInput, testExpect, done) {
}).then(function(resp){
expect(resp).to.have.property('txhash');
checkTransaction(resp.txhash, function(receipt){
+ try {
+ console.log("22: receipt", receipt);
+ if (testExpect.canExecuteTx) {
+ expect(receipt).to.have.property('status').equal(1);
+ } else {
+ expect(receipt).to.have.property('status').equal(0);
+ }
- if (testExpect.canExecuteTx) {
- expect(receipt).to.have.property('status').equal(1);
- } else {
- expect(receipt).to.not.have.property('status');
- }
-
- neb.api.getAccountState(receipt.from).then(function(state){
+ console.log("333");
+ neb.api.getAccountState(receipt.from).then(function (state) {
- // from balance change
- fromBalanceChange = new BigNumber(state.balance).sub(new BigNumber(fromBalanceBefore));
- console.log("[after take] from state: " + JSON.stringify(state) + ", balance change: " + fromBalanceChange);
+ // from balance change
+ fromBalanceChange = new BigNumber(state.balance).sub(new BigNumber(fromBalanceBefore));
+ console.log("[after take] from state: " + JSON.stringify(state) + ", balance change: " + fromBalanceChange);
- return neb.api.getAccountState(receipt.to);
- }).then(function(cstate){
-
+ return neb.api.getAccountState(receipt.to);
+ }).then(function (cstate) {
- return neb.api.getAccountState(coinbase).then(function(state){
-
- var coinbalancechange = new BigNumber(state.balance).sub(new BigNumber(coinBalanceBefore))
- .mod(new BigNumber(1.4269).mul(new BigNumber(10).pow(new BigNumber(18))));
- console.log("[after take] coinbase state:" + JSON.stringify(state) + ", balance change: " + coinbalancechange);
+ return neb.api.getAccountState(coinbase).then(function (state) {
- var chg = contractBalanceBefore.sub(new BigNumber(cstate.balance));
- console.log("[after take] contract state: " + JSON.stringify(cstate) + ", balance change: " + chg);
+ var coinbalancechange = new BigNumber(state.balance).sub(new BigNumber(coinBalanceBefore))
+ .mod(new BigNumber(1.4269).mul(new BigNumber(10).pow(new BigNumber(18))));
+ console.log("[after take] coinbase state:" + JSON.stringify(state) + ", balance change: " + coinbalancechange);
- if (testExpect.canExecuteTx) {
- var isEqual = chg.equals(new BigNumber(testExpect.takeBalance));
- expect(isEqual).to.be.true;
- }
-
- return neb.api.getEventsByHash(receipt.hash);
-
- });
-
- }).then(function(evtResp){
+ var chg = contractBalanceBefore.sub(new BigNumber(cstate.balance));
+ console.log("[after take] contract state: " + JSON.stringify(cstate) + ", balance change: " + chg);
- if (!testExpect.canExecuteTx) {
- expect(evtResp.events[0].topic).to.equal(testExpect.eventTopic);
- done();
- } else {
- neb.api.gasPrice().then(function(resp){
- expect(resp).to.have.property('gas_price');
- console.log("[after take] gas price:" + resp['gas_price'] + ", gas used: " + gasUsed);
- gasPrice = resp['gas_price'];
-
- var t = new BigNumber(testExpect.takeBalance).sub(new BigNumber(gasUsed)
- .mul(new BigNumber(gasPrice)));
- var isEqual = fromBalanceChange.equals(t);
-
- expect(isEqual).to.be.true;
- done();
- }).catch(function(err){
- done(err);
+ if (testExpect.canExecuteTx) {
+ var isEqual = chg.equals(new BigNumber(testExpect.takeBalance));
+ expect(isEqual).to.be.true;
+ }
+
+ return neb.api.getEventsByHash(receipt.hash);
});
- }
- }).catch(function(err){
- console.log(err.error);
+
+ }).then(function (evtResp) {
+
+ if (!testExpect.canExecuteTx) {
+
+ expect(evtResp.events[0].topic).to.equal(testExpect.eventTopic);
+ done();
+
+ } else {
+ neb.api.gasPrice().then(function (resp) {
+ expect(resp).to.have.property('gas_price');
+ console.log("[after take] gas price:" + resp['gas_price'] + ", gas used: " + gasUsed);
+ gasPrice = resp['gas_price'];
+
+ var t = new BigNumber(testExpect.takeBalance).sub(new BigNumber(gasUsed)
+ .mul(new BigNumber(gasPrice)));
+ var isEqual = fromBalanceChange.equals(t);
+
+ expect(isEqual).to.be.true;
+ done();
+ }).catch(function (err) {
+ done(err);
+ });
+ }
+ }).catch(function (err) {
+ console.log(err.error);
+ done(err)
+ });
+ } catch (err) {
+ console.log(JSON.stringify(err));
done(err)
- });
- });
+ }
+ })
}).catch(function(err){
console.log(err.error);
if (testExpect.hasError) {
@@ -370,6 +385,7 @@ function testTakeout(testInput, testExpect, done) {
}
function testVerifyAddress(testInput, testExpect, done) {
+ console.log("==> testVerifyAddress");
neb.api.getAccountState(contractAddr).then(function(state){
console.log("[before verify] contract state: " + JSON.stringify(state));
contractBalanceBefore = new BigNumber(state.balance);
@@ -388,7 +404,7 @@ function testVerifyAddress(testInput, testExpect, done) {
"function": testInput.func,
"args": testInput.args
}
- return neb.api.call(from.getAddressString(), contractAddr, testInput.value, parseInt(state.nonce) + 1, 0, testInput.gasLimit, call);
+ return neb.api.call(from.getAddressString(), contractAddr, testInput.value, parseInt(state.nonce) + 1, testInput.gasPrice, testInput.gasLimit, call);
}).then(resp => {
console.log("response: " + JSON.stringify(resp));
expect(resp).to.have.property('result')
@@ -398,6 +414,7 @@ function testVerifyAddress(testInput, testExpect, done) {
}
function claimNas(contractType, done) {
+ console.log("==> claimNas");
from = Account.NewAccount();
console.log("from addr:" + from.getAddressString());
@@ -419,7 +436,8 @@ function claimNas(contractType, done) {
if (redeploy) {
var testInput = {
contractType: contractType,
- gasLimit: 2000000
+ gasLimit: 2000000,
+ gasPrice: 1000000,
};
redeploy = false;
deployContract(testInput, done);
@@ -444,14 +462,16 @@ describe('bankvault.' + scriptType, function() {
it('save before take', function(done){
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "save",
args: "[0]",
value: 20000000000,
- }
+ };
var testExpect = {
canExecuteTx: true
- }
+ };
testSave(testInput, testExpect, done);
});
@@ -461,6 +481,8 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[10000000000]",
value: "0" //no use
@@ -483,6 +505,8 @@ describe('bankvault.' + scriptType, function() {
it('save before take', function(done){
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "save",
args: "[0]",
value: 20000000000,
@@ -499,6 +523,7 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
func: "takeout",
args: "[40000000000]",
value: "0" //no use
@@ -507,7 +532,8 @@ describe('bankvault.' + scriptType, function() {
var testExpect = {
canExecuteTx: false, // actually, should be `false`
takeBalance: '40000000000', // same with testInput.args[0]
- eventTopic: 'chain.executeTxFailed',
+ // eventTopic: 'chain.executeTxFailed',
+ eventTopic: 'chain.transactionResult',
hasError: true,
errorMsg: 'execution failed'
}
@@ -519,6 +545,8 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[0]",
value: "0" //no use
@@ -536,6 +564,8 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[-40000000000]",
value: "0" //no use
@@ -544,7 +574,8 @@ describe('bankvault.' + scriptType, function() {
var testExpect = {
canExecuteTx: false, // actually, should be `false`
takeBalance: '-40000000000', // same with testInput.args[0]
- eventTopic: 'chain.executeTxFailed',
+ // eventTopic: 'chain.executeTxFailed',
+ eventTopic: 'chain.transactionResult',
hasError: true,
errorMsg: 'execution failed'
}
@@ -561,6 +592,8 @@ describe('bankvault.' + scriptType, function() {
it('save(40) before take', done => {
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "save",
args: "[15]",
value: 20000000000,
@@ -577,15 +610,18 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[10000000000]",
value: "0" //no use
}
var testExpect = {
- canExecuteTx: false, // actually, should be `false`
+ canExecuteTx: false,
takeBalance: '10000000000', // same with testInput.args[0]
- eventTopic: 'chain.executeTxFailed'
+ // eventTopic: 'chain.executeTxFailed'
+ eventTopic: 'chain.transactionResult'
}
testTakeout(testInput, testExpect, done);
@@ -595,19 +631,21 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[10000000000]",
value: "0" //no use
}
var testExpect = {
- canExecuteTx: true, // actually, should be `false`
+ canExecuteTx: true,
takeBalance: '10000000000' // same with testInput.args[0]
}
setTimeout(() => {
testTakeout(testInput, testExpect, done);
- }, 25 * 5 * 1000);
+ }, 25 * blockInterval * 1000);
});
});
@@ -622,6 +660,8 @@ describe('bankvault.' + scriptType, function() {
// take
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "takeout",
args: "[10000000000]",
value: "0" //no use
@@ -630,7 +670,8 @@ describe('bankvault.' + scriptType, function() {
var testExpect = {
canExecuteTx: false ,
takeBalance: '0',
- eventTopic: 'chain.executeTxFailed'
+ // eventTopic: 'chain.executeTxFailed'
+ eventTopic: 'chain.transactionResult'
}
testTakeout(testInput, testExpect, done);
@@ -645,6 +686,8 @@ describe('bankvault.' + scriptType, function() {
it('5-1. save non-negative value', function(done){
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "save",
args: "[0]",
value: 10000000000,
@@ -660,6 +703,8 @@ describe('bankvault.' + scriptType, function() {
it('5-2. save negative value', function(done){
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
+
func: "save",
args: "[0]",
value: -20000000000,
@@ -667,7 +712,7 @@ describe('bankvault.' + scriptType, function() {
var testExpect = {
hasError: true,
- errorMsg: "uint128: underflow"
+ errorMsg: "invalid value"
}
testSave(testInput, testExpect, done);
@@ -676,6 +721,7 @@ describe('bankvault.' + scriptType, function() {
it('5-3. save negative height', done => {
var testInput = {
gasLimit: 2000000,
+ gasPrice: 1000000,
func: "save",
args: "[-500]",
value: 20000000000,
@@ -699,8 +745,9 @@ describe('bankvault.' + scriptType, function() {
var testInput = {
value: "0",
gasLimit: 2000000,
+ gasPrice: 1000000,
func: "verifyAddress",
- args: "[\"d2e558ebf403d10cc435e7ddff5906fcb2c8d033d74cc305\"]"
+ args: "[\"n1QZMXSZtW7BUerroSms4axNfyBGyFGkrh5\"]"
}
var testExpect = {
@@ -714,6 +761,7 @@ describe('bankvault.' + scriptType, function() {
var testInput = {
value: "0",
gasLimit: 2000000,
+ gasPrice: 1000000,
func: "verifyAddress",
args: "[\"slfjlsalfksdflsfjks\"]"
}
diff --git a/nebtestkit/cases/contract/contract.feature.accept.test.js b/nebtestkit/cases/contract/contract.feature.accept.test.js
new file mode 100644
index 000000000..48988d096
--- /dev/null
+++ b/nebtestkit/cases/contract/contract.feature.accept.test.js
@@ -0,0 +1,455 @@
+'use strict';
+
+var sleep = require('system-sleep');
+var FS = require('fs');
+var expect = require('chai').expect;
+var BigNumber = require('bignumber.js');
+var HttpRequest = require('../../node-request');
+var TestnetConfig = require('../testnet_config');
+var Wallet = require('nebulas');
+
+var Account = Wallet.Account;
+var Transaction = Wallet.Transaction;
+var env = process.argv.splice(2)[1];
+var testnetConfig = new TestnetConfig(env);
+var originSource = testnetConfig.sourceAccount;
+var ChainID = testnetConfig.ChainId;
+var coinbase = testnetConfig.coinbase;
+var neb = new Wallet.Neb();
+neb.setRequest(new HttpRequest(testnetConfig.apiEndPoint));
+
+
+var deploy, from, contractAddr, source, fromState, coinState;
+var caseIndex = 0, lastnonce = 0;
+
+function prepareSource(done) {
+ console.log("originSource address: " + originSource.getAddressString());
+ neb.api.getAccountState(originSource.getAddressString()).then(function (resp) {
+ console.log("prepare source account state:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+
+ source = Account.NewAccount();
+
+ var tx = new Transaction(ChainID, originSource, source, neb.nasToBasic(1000), nonce + 1, "1000000", "200000");
+ tx.signTransaction();
+
+ console.log("cliam source tx:", tx.toString());
+
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (resp) {
+ console.log("send Raw Tx:" + JSON.stringify(resp));
+ expect(resp).to.be.have.property('txhash');
+ checkTransaction(resp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ expect(receipt).to.be.have.property('status').equal(1);
+
+ done();
+ });
+ }).catch(function (err) {
+ done(err);
+ });
+}
+
+function cliamTokens(accounts, values, done) {
+ for (var i = 0; i < accounts.length; i++) {
+ console.log("acc:"+accounts[i].getAddressString()+" value:"+values[i]);
+ sendTransaction(source, accounts[i], values[i], ++lastnonce);
+ sleep(30);
+ }
+ checkCliamTokens(done);
+}
+
+
+function sendTransaction(from, address, value, nonce) {
+ var transaction = new Transaction(ChainID, from, address, value, nonce, "1000000", "200000");
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw transaction resp:" + JSON.stringify(resp));
+ });
+}
+
+function checkCliamTokens(done) {
+ var intervalAccount = setInterval(function () {
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ // console.log("master accountState resp:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+ console.log("check cliam tokens nonce:", lastnonce);
+
+ if (lastnonce <= nonce){
+ console.log("cliam tokens success");
+ clearInterval(intervalAccount);
+ done();
+ }
+ });
+ }, 2000);
+}
+
+function checkTransaction(txhash, retry, done){
+
+ var maxRetry = 45;
+
+ // contract status and get contract_address
+ var interval = setTimeout(function () {
+ neb.api.getTransactionReceipt(txhash).then(function (resp) {
+ retry++;
+
+ console.log("check transaction status:" + resp.status);
+ if(resp.status && resp.status === 1) {
+ // clearInterval(interval);
+
+ if (resp.contract_address) {
+ console.log("deploy private key:" + deploy.getPrivateKeyString());
+ console.log("deploy address:" + deploy.getAddressString());
+ console.log("deploy contract address:" + resp.contract_address);
+
+ contractAddr = resp.contract_address;
+ }
+
+ done(resp);
+ } else if (resp.status && resp.status === 2) {
+ if (retry > maxRetry) {
+ console.log("check transaction time out");
+ // clearInterval(interval);
+ done(resp);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ } else {
+ // clearInterval(interval);
+ console.log("transaction execution failed");
+ done(resp);
+ }
+ }).catch(function (err) {
+ retry++;
+ console.log("check transaction not found retry " + retry);
+ if (retry > maxRetry) {
+ console.log(JSON.stringify(err.error));
+ // clearInterval(interval);
+ done(err);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ });
+
+ }, 2000);
+}
+
+
+function deployContract(done, caseGroup) {
+ console.log("start deploying contract: " + caseGroup.groupname);
+
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ console.log("source account state:" + JSON.stringify(resp));
+
+ var accounts = new Array();
+ var values = new Array();
+ deploy = Account.NewAccount();
+ accounts.push(deploy);
+ values.push(neb.nasToBasic(1));
+
+ from = Account.NewAccount();
+ accounts.push(from);
+ var fromBalance = (typeof caseGroup.fromBalance === "undefined") ? neb.nasToBasic(1) : caseGroup.fromBalance;
+ values.push(fromBalance);
+
+ cliamTokens(accounts, values, () => {
+ try {
+ var source = FS.readFileSync("../../../nf/nvm/test/" + caseGroup.filename, "utf-8");
+ var contract = {
+ "source": source,
+ "sourceType": caseGroup.type,
+ "args": ""
+ };
+
+ var tx = new Transaction(testnetConfig.ChainId, deploy, deploy, "0", 1, "10000000", "2000000", contract);
+ tx.signTransaction();
+ var rawTx = tx.toProtoString();
+
+ // console.log("contract:" + rawTx);
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("deploy contract " + caseGroup.groupname + " return: " + JSON.stringify(resp));
+
+ checkTransaction(resp.txhash, 0, (ret) => {
+ if (ret.status && ret.status === 1) {
+ done();
+ } else {
+ done(ret);
+ }
+ });
+ });
+ } catch (err) {
+ done(err);
+ };
+ });
+
+ }).catch (err => done(err));
+}
+
+function testBinary(testInput, testExpect, done) {
+ var fromAcc = (typeof testInput.from === "undefined") ? from : testInput.from;
+ var to = (typeof testInput.to === "undefined") ? Account.fromAddress(contractAddr) : testInput.to;
+
+ var fromBalanceBefore, toBalanceBefore;
+
+ neb.api.getAccountState(to.getAddressString()).then(function (resp) {
+ console.log("contractAddr state before: " + JSON.stringify(resp));
+ toBalanceBefore = resp.balance;
+ return neb.api.getAccountState(from.getAddressString());
+ }).then(resp => {
+ fromState = resp;
+ fromBalanceBefore = resp.balanece;
+ console.log("from state before: ", JSON.stringify(resp));
+ return neb.api.getAccountState(coinbase);
+ }).then(function (resp) {
+ console.log("coin state before: ", JSON.stringify(resp));
+ coinState = resp;
+
+ var tx = new Transaction(ChainID, fromAcc, to, testInput.value, parseInt(fromState.nonce) + testInput.nonce, testInput.gasPrice, testInput.gasLimit);
+ tx.from.address = fromAcc.address;
+ tx.to.address = to.address;
+ tx.gasPrice = new BigNumber(testInput.gasPrice);
+ tx.gasLimit = new BigNumber(testInput.gasLimit);
+ tx.signTransaction();
+ console.log("binary tx raw before send: ", tx.toString());
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (rawResp) {
+ console.log("send Raw Tx return:" + JSON.stringify(rawResp));
+ expect(rawResp).to.be.have.property('txhash');
+
+ checkTransaction(rawResp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ try {
+ expect(receipt).to.not.be.a('undefined');
+ if (true === testExpect.canExcuteTx) {
+ expect(receipt).to.be.have.property('status').equal(1);
+ } else {
+ expect(receipt).to.be.have.property('status').equal(0);
+ }
+
+ neb.api.getAccountState(receipt.from).then(function (state) {
+
+ console.log("from state after: " + JSON.stringify(state));
+ // expect(state.balance).to.equal(testExpect.fromBalanceAfterTx);
+ return neb.api.getAccountState(contractAddr);
+ }).then(function (state) {
+
+ console.log("contractAddr state after: " + JSON.stringify(state));
+ var change = new BigNumber(state.balance).minus(new BigNumber(toBalanceBefore));
+ // expect(change.toString()).to.equal(testExpect.toBalanceChange);
+ return neb.api.getAccountState(coinbase);
+ }).then(function (state) {
+
+ console.log("get coinbase account state before tx:" + JSON.stringify(coinState));
+ console.log("get coinbase account state after tx:" + JSON.stringify(state));
+ var reward = new BigNumber(state.balance).sub(coinState.balance);
+ reward = reward.mod(new BigNumber(1.42694).mul(new BigNumber(10).pow(18)));
+ // The transaction should be only
+ // expect(reward.toString()).to.equal(testExpect.transferReward);
+ console.log("coinbase reward: " + reward.toString());
+ if (receipt.gasUsed) {
+ var txCost = new BigNumber(receipt.gasUsed).mul(receipt.gasPrice).toString(10);
+ // expect(txCost).to.equal(testExpect.transferReward);
+ console.log("tx cost gas: " + txCost.toString());
+ }
+
+ return neb.api.getEventsByHash(receipt.hash);
+ }).then(function (events) {
+ for (var i = 0; i < events.events.length; i++) {
+ var event = events.events[i];
+ //console.log("tx event:", JSON.stringify(event,null,'\t'));
+ console.log("tx event:", event.data);
+ if (event.topic === "chain.transactionResult") {
+ var result = JSON.parse(event.data);
+ expect(result.status).to.equal(testExpect.status);
+
+ if (testExpect.hasOwnProperty("eventErr")){
+ console.log("Event error checked.");
+ expect(result.error).to.equal(testExpect.eventErr);
+ }
+ }
+ }
+ done();
+ }).catch(function (err) {
+ console.log("exe tx err:", err);
+ done(err);
+ });
+ } catch (err) {
+ console.log("submit tx err:", err.message);
+ done(err);
+ }
+ });
+ }).catch(function (err) {
+ console.log("send tx err", err);
+ if (err.error && err.error.error && testExpect.eventErr) {
+ try {
+ expect(err.error.error).to.equal(testExpect.eventErr)
+ done();
+ } catch (err) {
+ done(err);
+ }
+ return;
+ }
+ done(err);
+ });
+}
+
+var testCaseGroups = [];
+var caseGroup = {
+ "filename": "contract_accept_func_with_args.js",
+ "type": "js",
+ "groupname": "case group 0: accept takes some args with execution error",
+ "groupIndex": 0,
+
+ cases: [
+ {
+ "name": "0-1. value = 0, invalid args",
+ "testInput": {
+ // from: from,
+ // to: contractAddr,
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000
+ },
+ "testExpect": {
+ canExcuteTx: false,
+ toBalanceChange: "0",
+ status: 0,
+ eventErr: "Binary: BigNumber Error: plus() not a number: undefined"
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+caseGroup = {
+ "filename": "contract_accept_func_with_args_2.js",
+ "type": "js",
+ "groupname": "case group 1: accept takes some args witchout execution error",
+ "groupIndex": 1,
+
+ cases: [
+ {
+ "name": "1-1. value = 0",
+ "testInput": {
+ // from: from,
+ // to: contractAddr,
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "0",
+ status: 1
+ }
+ },
+
+ {
+ "name": "1-2. value > 0",
+ "testInput": {
+ // from: from,
+ // to: contractAddr,
+ value: "100",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "100",
+ status: 1
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+caseGroup = {
+ "filename": "bank_vault_contract.js",
+ "type": "js",
+ "groupname": "case group 2: bankvault without accept func",
+ "groupIndex": 2,
+
+ cases: [
+ {
+ "name": "2-1. value > 0",
+ "testInput": {
+ // from: from,
+ // to: contractAddr,
+ value: "100",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000
+ },
+ "testExpect": {
+ canExcuteTx: false,
+ toBalanceChange: "0",
+ status: 0,
+ eventErr: "Binary: TypeError: Cannot read property 'apply' of undefined"
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+caseGroup = {
+ "filename": "contract_accept_func_standard.js",
+ "type": "js",
+ "groupname": "case group 3: bankvault with standard accept func",
+ "groupIndex": 3,
+
+ cases: [
+ {
+ "name": "3-1. value > 0",
+ "testInput": {
+ // from: from,
+ // to: contractAddr,
+ value: "100",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "100",
+ status: 1
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+describe('accept func test', () => {
+
+ before(done => prepareSource(done));
+
+ for (var i = 0; i < testCaseGroups.length; i++) {
+
+ // if (i != 2) {continue;} // selectively run tests
+
+ let caseGroup = testCaseGroups[i];
+ describe(caseGroup.groupname, () => {
+ before(done => {
+ deployContract(done, caseGroup);
+ caseIndex = 0;
+ });
+
+
+ for (var j = 0; j < caseGroup.cases.length; j++) {
+ let testCase = caseGroup.cases[j];
+ it(testCase.name, done => {
+ console.log("===> running case: " + JSON.stringify(testCase));
+ testBinary(testCase.testInput, testCase.testExpect, done);
+ });
+ }
+
+ afterEach(() => {
+ caseIndex++;
+ console.log("case group: " + caseGroup.groupIndex + ", index: " + caseIndex);
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/nebtestkit/cases/contract/contract.feature.date.test.js b/nebtestkit/cases/contract/contract.feature.date.test.js
new file mode 100644
index 000000000..4fba6e3d6
--- /dev/null
+++ b/nebtestkit/cases/contract/contract.feature.date.test.js
@@ -0,0 +1,400 @@
+'use strict';
+
+var sleep = require('system-sleep');
+var FS = require('fs');
+var expect = require('chai').expect;
+var BigNumber = require('bignumber.js');
+var HttpRequest = require('../../node-request');
+var TestnetConfig = require('../testnet_config');
+var Wallet = require('nebulas');
+
+var Account = Wallet.Account;
+var Transaction = Wallet.Transaction;
+var env = process.argv.splice(2)[1];
+var testnetConfig = new TestnetConfig(env);
+var originSource = testnetConfig.sourceAccount;
+var ChainID = testnetConfig.ChainId;
+var coinbase = testnetConfig.coinbase;
+var neb = new Wallet.Neb();
+neb.setRequest(new HttpRequest(testnetConfig.apiEndPoint));
+
+
+var deploy, from, contractAddr, source, fromState, coinState;
+var caseIndex = 0, lastnonce = 0;
+
+function prepareSource(done) {
+ console.log("originSource address: " + originSource.getAddressString());
+ neb.api.getAccountState(originSource.getAddressString()).then(function (resp) {
+ console.log("prepare source account state:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+
+ source = Account.NewAccount();
+
+ var tx = new Transaction(ChainID, originSource, source, neb.nasToBasic(1000), nonce + 1, "1000000", "200000");
+ tx.signTransaction();
+
+ console.log("cliam source tx:", tx.toString());
+
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (resp) {
+ console.log("send Raw Tx:" + JSON.stringify(resp));
+ expect(resp).to.be.have.property('txhash');
+ checkTransaction(resp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ expect(receipt).to.be.have.property('status').equal(1);
+
+ done();
+ });
+ }).catch(function (err) {
+ done(err);
+ });
+}
+
+function cliamTokens(accounts, values, done) {
+ for (var i = 0; i < accounts.length; i++) {
+ console.log("acc:"+accounts[i].getAddressString()+" value:"+values[i]);
+ sendTransaction(source, accounts[i], values[i], ++lastnonce);
+ sleep(30);
+ }
+ checkCliamTokens(done);
+}
+
+
+function sendTransaction(from, address, value, nonce) {
+ var transaction = new Transaction(ChainID, from, address, value, nonce, "1000000", "200000");
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw transaction resp:" + JSON.stringify(resp));
+ });
+}
+
+function checkCliamTokens(done) {
+ var intervalAccount = setInterval(function () {
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ // console.log("master accountState resp:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+ console.log("check cliam tokens nonce:", lastnonce);
+
+ if (lastnonce <= nonce){
+ console.log("cliam tokens success");
+ clearInterval(intervalAccount);
+ done();
+ }
+ });
+ }, 2000);
+}
+
+function checkTransaction(txhash, retry, done){
+
+ var maxRetry = 45;
+
+ // contract status and get contract_address
+ var interval = setTimeout(function () {
+ neb.api.getTransactionReceipt(txhash).then(function (resp) {
+ retry++;
+
+ console.log("check transaction status:" + resp.status);
+ if(resp.status && resp.status === 1) {
+ // clearInterval(interval);
+
+ if (resp.contract_address) {
+ console.log("deploy private key:" + deploy.getPrivateKeyString());
+ console.log("deploy address:" + deploy.getAddressString());
+ console.log("deploy contract address:" + resp.contract_address);
+
+ contractAddr = resp.contract_address;
+ }
+
+ done(resp);
+ } else if (resp.status && resp.status === 2) {
+ if (retry > maxRetry) {
+ console.log("check transaction time out");
+ // clearInterval(interval);
+ done(resp);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ } else {
+ // clearInterval(interval);
+ console.log("transaction execution failed");
+ done(resp);
+ }
+ }).catch(function (err) {
+ retry++;
+ console.log("check transaction not found retry " + retry);
+ if (retry > maxRetry) {
+ console.log(JSON.stringify(err.error));
+ // clearInterval(interval);
+ done(err);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ });
+
+ }, 2000);
+}
+
+
+function deployContract(done, caseGroup) {
+ console.log("start deploying contract: " + caseGroup.groupname);
+
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ console.log("source account state:" + JSON.stringify(resp));
+
+ var accounts = new Array();
+ var values = new Array();
+ deploy = Account.NewAccount();
+ accounts.push(deploy);
+ values.push(neb.nasToBasic(1));
+
+ from = Account.NewAccount();
+ accounts.push(from);
+ var fromBalance = (typeof caseGroup.fromBalance === "undefined") ? neb.nasToBasic(1) : caseGroup.fromBalance;
+ values.push(fromBalance);
+
+ cliamTokens(accounts, values, () => {
+ try {
+ var source = FS.readFileSync("../../../nf/nvm/test/" + caseGroup.filename, "utf-8");
+ var contract = {
+ "source": source,
+ "sourceType": caseGroup.type,
+ "args": ""
+ };
+
+ var tx = new Transaction(testnetConfig.ChainId, deploy, deploy, "0", 1, "10000000", "2000000", contract);
+ tx.signTransaction();
+ var rawTx = tx.toProtoString();
+
+ // console.log("contract:" + rawTx);
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("deploy contract " + caseGroup.groupname + " return: " + JSON.stringify(resp));
+
+ checkTransaction(resp.txhash, 0, (ret) => {
+ if (ret.status && ret.status === 1) {
+ done();
+ } else {
+ done(ret);
+ }
+ });
+ });
+ } catch (err) {
+ done(err);
+ };
+ });
+
+ }).catch (err => done(err));
+}
+
+function runTest(testInput, testExpect, done) {
+ var fromAcc = (typeof testInput.from === "undefined") ? from : testInput.from;
+ var to = (typeof testInput.to === "undefined") ? Account.fromAddress(contractAddr) : testInput.to;
+
+ var fromBalanceBefore, toBalanceBefore;
+
+ neb.api.getAccountState(to.getAddressString()).then(function (resp) {
+ console.log("contractAddr state before: " + JSON.stringify(resp));
+ toBalanceBefore = resp.balance;
+ return neb.api.getAccountState(from.getAddressString());
+ }).then(resp => {
+ fromState = resp;
+ fromBalanceBefore = resp.balanece;
+ console.log("from state before: ", JSON.stringify(resp));
+ return neb.api.getAccountState(coinbase);
+ }).then(function (resp) {
+ console.log("coin state before: ", JSON.stringify(resp));
+ coinState = resp;
+
+ var tx = new Transaction(ChainID, fromAcc, to, testInput.value, parseInt(fromState.nonce) + testInput.nonce, testInput.gasPrice, testInput.gasLimit, testInput.contract);
+ tx.from.address = fromAcc.address;
+ tx.to.address = to.address;
+ tx.gasPrice = new BigNumber(testInput.gasPrice);
+ tx.gasLimit = new BigNumber(testInput.gasLimit);
+ tx.signTransaction();
+ console.log("binary tx raw before send: ", tx.toString());
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (rawResp) {
+ console.log("send Raw Tx return:" + JSON.stringify(rawResp));
+ expect(rawResp).to.be.have.property('txhash');
+
+ checkTransaction(rawResp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ try {
+ expect(receipt).to.not.be.a('undefined');
+ if (true === testExpect.canExcuteTx) {
+ expect(receipt).to.be.have.property('status').equal(1);
+ } else {
+ expect(receipt).to.be.have.property('status').equal(0);
+ }
+
+ neb.api.getAccountState(receipt.from).then(function (state) {
+
+ console.log("from state after: " + JSON.stringify(state));
+ // expect(state.balance).to.equal(testExpect.fromBalanceAfterTx);
+ return neb.api.getAccountState(contractAddr);
+ }).then(function (state) {
+
+ console.log("contractAddr state after: " + JSON.stringify(state));
+ var change = new BigNumber(state.balance).minus(new BigNumber(toBalanceBefore));
+ // expect(change.toString()).to.equal(testExpect.toBalanceChange);
+ return neb.api.getAccountState(coinbase);
+ }).then(function (state) {
+
+ console.log("get coinbase account state before tx:" + JSON.stringify(coinState));
+ console.log("get coinbase account state after tx:" + JSON.stringify(state));
+ var reward = new BigNumber(state.balance).sub(coinState.balance);
+ reward = reward.mod(new BigNumber(1.42694).mul(new BigNumber(10).pow(18)));
+ // The transaction should be only
+ // expect(reward.toString()).to.equal(testExpect.transferReward);
+ console.log("coinbase reward: " + reward.toString());
+ if (receipt.gasUsed) {
+ var txCost = new BigNumber(receipt.gasUsed).mul(receipt.gasPrice).toString(10);
+ // expect(txCost).to.equal(testExpect.transferReward);
+ console.log("tx cost gas: " + txCost.toString());
+ }
+
+ return neb.api.getEventsByHash(receipt.hash);
+ }).then(function (events) {
+ for (var i = 0; i < events.events.length; i++) {
+ var event = events.events[i];
+ //console.log("tx event:", JSON.stringify(event,null,'\t'));
+ console.log("tx event:", event.data);
+ if (event.topic === "chain.transactionResult") {
+ var result = JSON.parse(event.data);
+ expect(result.status).to.equal(testExpect.status);
+
+ if (testExpect.hasOwnProperty("eventErr")){
+ console.log("Event error checked.");
+ expect(result.error).to.equal(testExpect.eventErr);
+ }
+ }
+ if (event.topic === "chain.contract.Date") {
+ var result = JSON.parse(event.data);
+ expect(result.data.equalBlockTime).to.equal(testExpect.equalBlockTime);
+ console.log("check equalBlockTime success");
+ }
+ }
+ done();
+ }).catch(function (err) {
+ console.log("exe tx err:", err);
+ done(err);
+ });
+ } catch (err) {
+ console.log("submit tx err:", err.message);
+ done(err);
+ }
+ });
+ }).catch(function (err) {
+ if (err.error && err.error.error && testExpect.eventErr) {
+ try {
+ expect(err.error.error).to.equal(testExpect.eventErr)
+ done();
+ } catch (err) {
+ done(err);
+ }
+ return;
+ }
+ done(err);
+ });
+}
+
+var testCaseGroups = [];
+var caseGroup = {
+ "filename": "contract_date_and_random.js",
+ "type": "js",
+ "groupname": "case group 0: Date",
+ "groupIndex": 0,
+
+ cases: [
+ {
+ "name": "0-1. test 'new Date()'",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testDate",
+ args: ""
+ }
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "0",
+ status: 1,
+ equalBlockTime: true
+ }
+ },
+ {
+ "name": "0-2. test 'new Date('1995-12-17T03:24:00')'",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testDate",
+ args: "[\"1995-12-17T03:24:00\"]"
+ }
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "0",
+ status: 1,
+ equalBlockTime: false
+ }
+ },
+ {
+ "name": "0-3. test unsupported method",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testDate2",
+ args: ""
+ }
+ },
+ "testExpect": {
+ canExcuteTx: false,
+ toBalanceChange: "0",
+ status: 0,
+ eventErr: "Call: Error: Unsupported method!"
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+describe('Contract Date test', () => {
+
+ before(done => prepareSource(done));
+
+ for (var i = 0; i < testCaseGroups.length; i++) {
+
+ // if (i != 3) {continue;} // selectively run tests
+
+ let caseGroup = testCaseGroups[i];
+ describe(caseGroup.groupname, () => {
+ before(done => {
+ deployContract(done, caseGroup);
+ caseIndex = 0;
+ });
+
+
+ for (var j = 0; j < caseGroup.cases.length; j++) {
+ let testCase = caseGroup.cases[j];
+ it(testCase.name, done => {
+ console.log("===> running case: " + JSON.stringify(testCase));
+ runTest(testCase.testInput, testCase.testExpect, done);
+ });
+ }
+
+ afterEach(() => {
+ caseIndex++;
+ console.log("case group: " + caseGroup.groupIndex + ", index: " + caseIndex);
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/nebtestkit/cases/contract/contract.feature.random.test.js b/nebtestkit/cases/contract/contract.feature.random.test.js
new file mode 100644
index 000000000..9252ed3b8
--- /dev/null
+++ b/nebtestkit/cases/contract/contract.feature.random.test.js
@@ -0,0 +1,400 @@
+'use strict';
+
+var sleep = require('system-sleep');
+var FS = require('fs');
+var expect = require('chai').expect;
+var BigNumber = require('bignumber.js');
+var HttpRequest = require('../../node-request');
+var TestnetConfig = require('../testnet_config');
+var Wallet = require('nebulas');
+
+var Account = Wallet.Account;
+var Transaction = Wallet.Transaction;
+var env = process.argv.splice(2)[1];
+var testnetConfig = new TestnetConfig(env);
+var originSource = testnetConfig.sourceAccount;
+var ChainID = testnetConfig.ChainId;
+var coinbase = testnetConfig.coinbase;
+var neb = new Wallet.Neb();
+neb.setRequest(new HttpRequest(testnetConfig.apiEndPoint));
+
+
+var deploy, from, contractAddr, source, fromState, coinState;
+var caseIndex = 0, lastnonce = 0;
+
+function prepareSource(done) {
+ console.log("originSource address: " + originSource.getAddressString());
+ neb.api.getAccountState(originSource.getAddressString()).then(function (resp) {
+ console.log("prepare source account state:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+
+ source = Account.NewAccount();
+
+ var tx = new Transaction(ChainID, originSource, source, neb.nasToBasic(1000), nonce + 1, "1000000", "200000");
+ tx.signTransaction();
+
+ console.log("cliam source tx:", tx.toString());
+
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (resp) {
+ console.log("send Raw Tx:" + JSON.stringify(resp));
+ expect(resp).to.be.have.property('txhash');
+ checkTransaction(resp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ expect(receipt).to.be.have.property('status').equal(1);
+
+ done();
+ });
+ }).catch(function (err) {
+ done(err);
+ });
+}
+
+function cliamTokens(accounts, values, done) {
+ for (var i = 0; i < accounts.length; i++) {
+ console.log("acc:"+accounts[i].getAddressString()+" value:"+values[i]);
+ sendTransaction(source, accounts[i], values[i], ++lastnonce);
+ sleep(30);
+ }
+ checkCliamTokens(done);
+}
+
+
+function sendTransaction(from, address, value, nonce) {
+ var transaction = new Transaction(ChainID, from, address, value, nonce, "1000000", "200000");
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw transaction resp:" + JSON.stringify(resp));
+ });
+}
+
+function checkCliamTokens(done) {
+ var intervalAccount = setInterval(function () {
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ // console.log("master accountState resp:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+ console.log("check cliam tokens nonce:", lastnonce);
+
+ if (lastnonce <= nonce){
+ console.log("cliam tokens success");
+ clearInterval(intervalAccount);
+ done();
+ }
+ });
+ }, 2000);
+}
+
+function checkTransaction(txhash, retry, done){
+
+ var maxRetry = 45;
+
+ // contract status and get contract_address
+ var interval = setTimeout(function () {
+ neb.api.getTransactionReceipt(txhash).then(function (resp) {
+ retry++;
+
+ console.log("check transaction status:" + resp.status);
+ if(resp.status && resp.status === 1) {
+ // clearInterval(interval);
+
+ if (resp.contract_address) {
+ console.log("deploy private key:" + deploy.getPrivateKeyString());
+ console.log("deploy address:" + deploy.getAddressString());
+ console.log("deploy contract address:" + resp.contract_address);
+
+ contractAddr = resp.contract_address;
+ }
+
+ done(resp);
+ } else if (resp.status && resp.status === 2) {
+ if (retry > maxRetry) {
+ console.log("check transaction time out");
+ // clearInterval(interval);
+ done(resp);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ } else {
+ // clearInterval(interval);
+ console.log("transaction execution failed");
+ done(resp);
+ }
+ }).catch(function (err) {
+ retry++;
+ console.log("check transaction not found retry " + retry);
+ if (retry > maxRetry) {
+ console.log(JSON.stringify(err.error));
+ // clearInterval(interval);
+ done(err);
+ } else {
+ checkTransaction(txhash, retry++, done);
+ }
+ });
+
+ }, 2000);
+}
+
+
+function deployContract(done, caseGroup) {
+ console.log("start deploying contract: " + caseGroup.groupname);
+
+ neb.api.getAccountState(source.getAddressString()).then(function (resp) {
+ console.log("source account state:" + JSON.stringify(resp));
+
+ var accounts = new Array();
+ var values = new Array();
+ deploy = Account.NewAccount();
+ accounts.push(deploy);
+ values.push(neb.nasToBasic(1));
+
+ from = Account.NewAccount();
+ accounts.push(from);
+ var fromBalance = (typeof caseGroup.fromBalance === "undefined") ? neb.nasToBasic(1) : caseGroup.fromBalance;
+ values.push(fromBalance);
+
+ cliamTokens(accounts, values, () => {
+ try {
+ var source = FS.readFileSync("../../../nf/nvm/test/" + caseGroup.filename, "utf-8");
+ var contract = {
+ "source": source,
+ "sourceType": caseGroup.type,
+ "args": ""
+ };
+
+ var tx = new Transaction(testnetConfig.ChainId, deploy, deploy, "0", 1, "10000000", "2000000", contract);
+ tx.signTransaction();
+ var rawTx = tx.toProtoString();
+
+ // console.log("contract:" + rawTx);
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("deploy contract " + caseGroup.groupname + " return: " + JSON.stringify(resp));
+
+ checkTransaction(resp.txhash, 0, (ret) => {
+ if (ret.status && ret.status === 1) {
+ done();
+ } else {
+ done(ret);
+ }
+ });
+ });
+ } catch (err) {
+ done(err);
+ };
+ });
+
+ }).catch (err => done(err));
+}
+
+function runTest(testInput, testExpect, done) {
+ var fromAcc = (typeof testInput.from === "undefined") ? from : testInput.from;
+ var to = (typeof testInput.to === "undefined") ? Account.fromAddress(contractAddr) : testInput.to;
+
+ var fromBalanceBefore, toBalanceBefore;
+
+ neb.api.getAccountState(to.getAddressString()).then(function (resp) {
+ console.log("contractAddr state before: " + JSON.stringify(resp));
+ toBalanceBefore = resp.balance;
+ return neb.api.getAccountState(from.getAddressString());
+ }).then(resp => {
+ fromState = resp;
+ fromBalanceBefore = resp.balanece;
+ console.log("from state before: ", JSON.stringify(resp));
+ return neb.api.getAccountState(coinbase);
+ }).then(function (resp) {
+ console.log("coin state before: ", JSON.stringify(resp));
+ coinState = resp;
+
+ var tx = new Transaction(ChainID, fromAcc, to, testInput.value, parseInt(fromState.nonce) + testInput.nonce, testInput.gasPrice, testInput.gasLimit, testInput.contract);
+ tx.from.address = fromAcc.address;
+ tx.to.address = to.address;
+ tx.gasPrice = new BigNumber(testInput.gasPrice);
+ tx.gasLimit = new BigNumber(testInput.gasLimit);
+ tx.signTransaction();
+ console.log("binary tx raw before send: ", tx.toString());
+ return neb.api.sendRawTransaction(tx.toProtoString());
+ }).then(function (rawResp) {
+ console.log("send Raw Tx return:" + JSON.stringify(rawResp));
+ expect(rawResp).to.be.have.property('txhash');
+
+ checkTransaction(rawResp.txhash, 0, function (receipt) {
+ console.log("tx receipt : " + JSON.stringify(receipt));
+ try {
+ expect(receipt).to.not.be.a('undefined');
+ if (true === testExpect.canExcuteTx) {
+ expect(receipt).to.be.have.property('status').equal(1);
+ } else {
+ expect(receipt).to.be.have.property('status').equal(0);
+ }
+
+ neb.api.getAccountState(receipt.from).then(function (state) {
+
+ console.log("from state after: " + JSON.stringify(state));
+ // expect(state.balance).to.equal(testExpect.fromBalanceAfterTx);
+ return neb.api.getAccountState(contractAddr);
+ }).then(function (state) {
+
+ console.log("contractAddr state after: " + JSON.stringify(state));
+ var change = new BigNumber(state.balance).minus(new BigNumber(toBalanceBefore));
+ // expect(change.toString()).to.equal(testExpect.toBalanceChange);
+ return neb.api.getAccountState(coinbase);
+ }).then(function (state) {
+
+ console.log("get coinbase account state before tx:" + JSON.stringify(coinState));
+ console.log("get coinbase account state after tx:" + JSON.stringify(state));
+ var reward = new BigNumber(state.balance).sub(coinState.balance);
+ reward = reward.mod(new BigNumber(1.42694).mul(new BigNumber(10).pow(18)));
+ // The transaction should be only
+ // expect(reward.toString()).to.equal(testExpect.transferReward);
+ console.log("coinbase reward: " + reward.toString());
+ if (receipt.gasUsed) {
+ var txCost = new BigNumber(receipt.gasUsed).mul(receipt.gasPrice).toString(10);
+ // expect(txCost).to.equal(testExpect.transferReward);
+ console.log("tx cost gas: " + txCost.toString());
+ }
+
+ return neb.api.getEventsByHash(receipt.hash);
+ }).then(function (events) {
+ for (var i = 0; i < events.events.length; i++) {
+ var event = events.events[i];
+ //console.log("tx event:", JSON.stringify(event,null,'\t'));
+ console.log("tx event:", event.data);
+ if (event.topic === "chain.transactionResult") {
+ var result = JSON.parse(event.data);
+ expect(result.status).to.equal(testExpect.status);
+
+ if (testExpect.hasOwnProperty("eventErr")){
+ console.log("Event error checked.");
+ expect(result.error).to.equal(testExpect.eventErr);
+ }
+ }
+ if (event.topic === "chain.contract.random") {
+ var result = JSON.parse(event.data);
+ expect(result.defaultSeedRandom1 == result.userSeedRandom).to.equal(testExpect.equalr1r2);
+ console.log("check equalr1r2 success");
+ }
+ }
+ done();
+ }).catch(function (err) {
+ console.log("exe tx err:", err);
+ done(err);
+ });
+ } catch (err) {
+ console.log("submit tx err:", err.message);
+ done(err);
+ }
+ });
+ }).catch(function (err) {
+ if (err.error && err.error.error && testExpect.eventErr) {
+ try {
+ expect(err.error.error).to.equal(testExpect.eventErr)
+ done();
+ } catch (err) {
+ done(err);
+ }
+ return;
+ }
+ done(err);
+ });
+}
+
+var testCaseGroups = [];
+var caseGroup = {
+ "filename": "contract_date_and_random.js",
+ "type": "js",
+ "groupname": "case group 0: Math.random",
+ "groupIndex": 0,
+
+ cases: [
+ {
+ "name": "0-1. test 'not define user seed'",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testRandom",
+ args: ""
+ }
+ },
+ "testExpect": {
+ canExcuteTx: false,
+ toBalanceChange: "0",
+ status: 0,
+ eventErr: "Call: Error: input seed must be a string"
+ }
+ },
+ {
+ "name": "0-2. test 'empty user seed('') == reset random seed'",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testRandom",
+ args: "[\"\"]"
+ }
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "0",
+ status: 1,
+ equalr1r2: true
+ }
+ },
+ {
+ "name": "0-3. test 'set user seed('abc')'",
+ "testInput": {
+ value: "0",
+ nonce: 1,
+ gasPrice: 1000000,
+ gasLimit: 2000000,
+ contract: {
+ function: "testRandom",
+ args: "[\"abc\"]"
+ }
+ },
+ "testExpect": {
+ canExcuteTx: true,
+ toBalanceChange: "0",
+ status: 1,
+ equalr1r2: false
+ }
+ }
+ ]
+};
+testCaseGroups.push(caseGroup);
+
+describe('Contract Math.random test', () => {
+
+ before(done => prepareSource(done));
+
+ for (var i = 0; i < testCaseGroups.length; i++) {
+
+ // if (i != 3) {continue;} // selectively run tests
+
+ let caseGroup = testCaseGroups[i];
+ describe(caseGroup.groupname, () => {
+ before(done => {
+ deployContract(done, caseGroup);
+ caseIndex = 0;
+ });
+
+
+ for (var j = 0; j < caseGroup.cases.length; j++) {
+ let testCase = caseGroup.cases[j];
+ it(testCase.name, done => {
+ console.log("===> running case: " + JSON.stringify(testCase));
+ runTest(testCase.testInput, testCase.testExpect, done);
+ });
+ }
+
+ afterEach(() => {
+ caseIndex++;
+ console.log("case group: " + caseGroup.groupIndex + ", index: " + caseIndex);
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/nebtestkit/cases/rpc/admin.SignTransactionWithPassphrase.test.js b/nebtestkit/cases/rpc/admin.SignTransactionWithPassphrase.test.js
index fa84d4e05..cbb600564 100644
--- a/nebtestkit/cases/rpc/admin.SignTransactionWithPassphrase.test.js
+++ b/nebtestkit/cases/rpc/admin.SignTransactionWithPassphrase.test.js
@@ -10,7 +10,7 @@ var coinbase,
server_address;
var env = process.env.NET || 'local';
-var env = 'maintest';
+var env = 'local';
if (env === 'testneb1') {
chain_id = 1001;
sourceAccount = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
@@ -450,11 +450,186 @@ describe("rpc: SignTransaction with passphrase", () => {
}
var testExpect = {
- hasError: false,
- errorMsg: "",
+ hasError: true,
+ errorMsg: "invalid contract",
}
testSignTransaction(testInput, testExpect, done)
});
+
+it('17. `invalid type`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ contract: {
+ "function": "save",
+ },
+ type: "invalid"
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: true,
+ errorMsg: "invalid transaction data payload type",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+
+it('18. `binary type`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "binary"
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: false,
+ errorMsg: "",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+
+it('19. `deploy type`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "deploy",
+ contract: {
+ "source": "var a = {}",
+ "source_type": "ts"
+ }
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: false,
+ errorMsg: "",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+
+it('20. `deploy type parse err`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "deploy",
+ contract: {
+ "source": "var a = {}"
+ }
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: true,
+ errorMsg: "invalid source type of deploy payload",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+
+it('21. `call type`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "call",
+ contract: {
+ "function": "save"
+ }
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: false,
+ errorMsg: "",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+it('22. `call type function err`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "call",
+ contract: {
+ "function": "_save"
+ }
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: true,
+ errorMsg: "invalid function of call payload",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
+it('23. `call type no function`', done => {
+ var testInput = {
+ transaction: {
+ from: address,
+ to: coinbase,
+ value: "123",
+ nonce: "10000",
+ gas_price: "1000000",
+ gas_limit: "1000000",
+ type: "call"
+ },
+ passphrase: 'passphrase'
+ }
+
+ var testExpect = {
+ hasError: true,
+ errorMsg: "invalid function of call payload",
+
+ }
+
+ testSignTransaction(testInput, testExpect, done)
+});
});
\ No newline at end of file
diff --git a/nebtestkit/cases/rpc/rpc_client/rpc.proto b/nebtestkit/cases/rpc/rpc_client/rpc.proto
index 52764eb0f..85bd138d3 100644
--- a/nebtestkit/cases/rpc/rpc_client/rpc.proto
+++ b/nebtestkit/cases/rpc/rpc_client/rpc.proto
@@ -342,6 +342,9 @@ message TransactionRequest {
// binary data for transaction
bytes binary = 10;
+
+ // transaction payload type, enum:binary, deploy, call
+ string type = 20;
}
message ContractRequest {
diff --git a/nebtestkit/cases/stress/contract.date.and.random.test.js b/nebtestkit/cases/stress/contract.date.and.random.test.js
new file mode 100644
index 000000000..5462f40f2
--- /dev/null
+++ b/nebtestkit/cases/stress/contract.date.and.random.test.js
@@ -0,0 +1,277 @@
+'use strict';
+
+var Wallet = require('nebulas');
+var sleep = require("system-sleep");
+var HttpRequest = require("../../node-request");
+
+var args = process.argv.splice(2);
+
+if (args.length != 3) {
+ console.log("please input args 0:env(local,testneb1,testneb2,testneb3) 1:address number(concurrency) 2:sendtimes");
+ return;
+}
+
+var env = args[0]; // local testneb1 testneb2
+
+const AddressNumber = parseInt(args[1]);
+const SendTimes = parseInt(args[2]);
+
+if (AddressNumber <= 0 || SendTimes <= 0) {
+
+ console.log("please input correct AddressNumber and SendTimes");
+ return;
+}
+
+var Neb = Wallet.Neb;
+var neb = new Neb();
+
+var ChainID;
+var from;
+
+//local
+if (env == 'local') {
+ neb.setRequest(new HttpRequest("http://127.0.0.1:8685")); //https://testnet.nebulas.io
+ ChainID = 100;
+ from = new Wallet.Account("a6e5eb290e1438fce79f5cb8774a72621637c2c9654c8b2525ed1d7e4e73653f");
+} else if (env == 'testneb1') {
+ neb.setRequest(new HttpRequest("http://35.182.48.19:8685"));
+ ChainID = 1001;
+ from = new Wallet.Account("43181d58178263837a9a6b08f06379a348a5b362bfab3631ac78d2ac771c5df3");
+} else if (env == "testneb2") {
+ neb.setRequest(new HttpRequest("http://34.205.26.12:8685"));
+ ChainID = 1002;
+ from = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+} else if (env == "testneb3") {
+ neb.setRequest(new HttpRequest("http://35.177.214.138:8685"));
+ ChainID = 1003;
+ from = new Wallet.Account("43181d58178263837a9a6b08f06379a348a5b362bfab3631ac78d2ac771c5df3");
+} else {
+ console.log("please input correct env local testneb1 testneb2 testneb3");
+ return;
+}
+
+var FS = require("fs");
+
+var lastnonce = 0;
+
+// new account to get address
+var accountArray = new Array();
+for (var i = 0; i < AddressNumber; i++) {
+ var account = Wallet.Account.NewAccount();
+ //var hash = account.getAddressString();
+ accountArray.push(account);
+}
+
+neb.api.getAccountState(from.getAddressString()).then(function (resp) {
+ console.log("master accountState resp:", JSON.stringify(resp), ", env: ", env);
+ lastnonce = parseInt(resp.nonce);
+ console.log("lastnonce:", lastnonce);
+});
+
+sleep(2000);
+
+cliamTokens();
+
+var ContractHash;
+var ContractAddress;
+
+var intervalAccount = setInterval(function () {
+ neb.api.getAccountState(from.getAddressString()).then(function (resp) {
+ console.log("master accountState resp:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+ console.log("lastnonce:", lastnonce, "resp_nonce:", nonce);
+
+ if (lastnonce <= nonce) {
+ clearInterval(intervalAccount);
+ deployContract();
+ }
+ });
+}, 2000);
+
+function cliamTokens() {
+ var nonce = lastnonce + 1;
+ for (var j = 0; j < AddressNumber; j++) {
+ sendTransaction(nonce, accountArray[j]);
+ ++nonce;
+ sleep(30);
+ }
+
+ lastnonce = nonce - 1;
+}
+
+function deployContract() {
+
+ var nonce = lastnonce;
+ console.log("nonce:" + nonce);
+ // create contract
+ var dateAndRand = FS.readFileSync("../../../nf/nvm/test/contract_date_and_random.js", "utf-8");
+ var contract = {
+ "source": dateAndRand,
+ "sourceType": "js",
+ "args": ""
+ };
+
+ var transaction = new Wallet.Transaction(ChainID, from, from, "0", ++nonce, "1000000", "20000000000", contract);
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+
+ // console.log("contract:" + rawTx);
+
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw contract transaction resp:" + JSON.stringify(resp));
+ if (resp.balance === "0") {
+ throw new Error("balance is 0");
+ }
+ ContractHash = resp.txhash;
+ ContractAddress = resp.contract_address;
+
+ checkContractDeployed();
+ });
+
+ ++lastnonce;
+}
+
+function checkContractDeployed() {
+
+ var retry = 0;
+
+ // contract status and get contract_address
+ var interval = setInterval(function () {
+ console.log("getTransactionReceipt hash:" + ContractHash);
+ neb.api.getTransactionReceipt(ContractHash).then(function (resp) {
+
+ console.log("tx receipt:" + resp.status);
+
+ if (resp.status && resp.status === 1) {
+ clearInterval(interval);
+ sendMutilContractTransaction(ContractAddress)
+ }
+ }).catch(function (err) {
+ retry++;
+ console.log("error!", JSON.stringify(err.error));
+ if (retry > 10) {
+ console.log(JSON.stringify(err.error));
+ clearInterval(interval);
+ }
+ });
+
+ }, 2000);
+}
+
+
+function sendTransaction(nonce, address) {
+ var transaction = new Wallet.Transaction(ChainID, from, address, neb.nasToBasic(1), nonce);
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw transaction resp:" + JSON.stringify(resp));
+ });
+}
+
+
+
+// get current height
+var BeginHeight;
+//
+function sendMutilContractTransaction(address) {
+
+ neb.api.getNebState().then(function (resp) {
+ BeginHeight = resp.height;
+ console.log("get NebState resp:" + JSON.stringify(resp));
+ });
+
+ sleep(1000);
+ var nonce = lastnonce;
+ var t1 = new Date().getTime();
+ for (var j = 0; j < AddressNumber; j++) {
+ nonce = 0;
+ sendContractTransaction(0, nonce, accountArray[j], address);
+ //nonce = nonce + SendTimes;
+ }
+
+ lastnonce = SendTimes;
+ sleep(1000 * SendTimes)
+ getTransactionNumberByHeight();
+}
+
+
+
+function sendContractTransaction(sendtimes, nonce, from_address, contract_address) {
+ if (sendtimes < SendTimes) {
+
+ var X = Math.floor(Math.random() * Math.floor(6));
+
+ var call = {
+ "function": X % 2 == 0 ? "testDate" : "testRandom",
+ "args": ""
+ }
+
+ console.log("send contract nonce:", nonce, ", call:", JSON.stringify(call));
+ var transaction = new Wallet.Transaction(ChainID, from_address, contract_address, "0", ++nonce, "1000000", "2000000000", call);
+ transaction.signTransaction();
+ var rawTx = transaction.toProtoString();
+ neb.api.sendRawTransaction(rawTx).then(function (resp) {
+ console.log("send raw contract transaction resp:" + JSON.stringify(resp));
+ sendtimes++;
+ if (resp.txhash) {
+ sendContractTransaction(sendtimes, nonce, from_address, contract_address);
+ }
+ });
+ }
+}
+
+function getTransactionNumberByHeight() {
+
+ var intervalHeight = setInterval(function () {
+ neb.api.getAccountState(accountArray[0].getAddressString()).then(function (resp) {
+ console.log("master accountState resp:" + JSON.stringify(resp));
+ var nonce = parseInt(resp.nonce);
+ console.log("lastnonce:", lastnonce, "resp_nonce:", nonce);
+
+ if (lastnonce <= nonce) {
+ clearInterval(intervalHeight)
+ sleep(2000)
+ neb.api.getNebState().then(function (resp) {
+ var EndHeight = resp.height
+ console.log("BeginHeight:" + BeginHeight + " EndHeight:" + EndHeight);
+ var sum = 0;
+ var max = 0;
+ var height = BeginHeight
+ var h = EndHeight - BeginHeight
+ for (; height <= EndHeight; height++) {
+ neb.api.getBlockByHeight(height, false).then(function (resp) {
+ if (resp.transactions) {
+ //console.log("master accountState resp:" + JSON.stringify(resp));
+ console.log(resp.height, resp.transactions.length)
+ sum += resp.transactions.length
+ max = resp.transactions.length > max ? resp.transactions.length : max
+ } else {
+ console.log(resp.height, 0)
+ }
+ --h;
+ });
+ sleep(10)
+ }
+
+ sleep(1000)
+ var intervalH = setInterval(function () {
+ if (h < 0) {
+ clearInterval(intervalH);
+ console.log("====================")
+ console.log("env is ", env)
+ console.log("concurrency number is ", AddressNumber)
+ console.log("total number is ", AddressNumber * SendTimes)
+ console.log("height from ", BeginHeight, " to ", EndHeight)
+ console.log("max of block is ", max)
+ console.log("avg of block is ", sum / (EndHeight - BeginHeight))
+ console.log("max of tps is ", max / 5)
+ console.log("avg of tps is ", sum / (5 * (EndHeight - BeginHeight)))
+ console.log("====================")
+ }
+ }, 2000);
+
+ });
+ }
+ })
+ }, 1000);
+}
\ No newline at end of file
diff --git a/nebtestkit/cases/stress/stress.test.dag.js b/nebtestkit/cases/stress/stress.test.dag.js
index c08c3125b..053bf5cd2 100644
--- a/nebtestkit/cases/stress/stress.test.dag.js
+++ b/nebtestkit/cases/stress/stress.test.dag.js
@@ -1,37 +1,23 @@
'use strict';
-var Wallet = require('../../../cmd/console/neb.js/lib/wallet.js');
-var HttpRequest = require("../../node-request");
+var Wallet = require("nebulas");
+//var HttpRequest = Wallet.HttpRequest
+var HttpRequest = require("../../node-request.js");
+var utils = Wallet.Utils;
var schedule = require('node-schedule');
var sleep = require("system-sleep");
-var env="testneb3"; // local testneb1 testneb2
-var AddressNumber = 100;
-var EachAccountSendTimes = 100;
-var ChainID = 1003;
+var env; // local testneb1 testneb2
+var AddressNumber = 300;
+var EachAccountSendTimes = 50;
var args = process.argv.splice(2);
-
-if (args.length != 3) {
- // give default config
- env = "testneb3";
- AddressNumber = 100;
-} else {
- env = args[0]; // local testneb1 testneb2
-
- AddressNumber = parseInt(args[1]);
- EachAccountSendTimes = parseInt(args[2]);
-}
-
-if (AddressNumber <= 0 || EachAccountSendTimes <= 0) {
-
- console.log("please input correct AddressNumber and SendTimes");
- return;
-}
+env = args[0];
var Neb = Wallet.Neb;
var neb = new Neb();
+var ChainID;
var from;
var accountArray;
// var to = Wallet.Account.NewAccount();
@@ -42,32 +28,141 @@ var startTime;
var nodes = new Array();
-neb.setRequest(new HttpRequest("http://35.177.214.138:8685"));
-ChainID = 1003;
-from = new Wallet.Account("43181d58178263837a9a6b08f06379a348a5b362bfab3631ac78d2ac771c5df3");
-nodes.push("http://35.177.214.138:8685");
+console.log(args);
+
+//local
+if (env === 'local') {
+ neb.setRequest(new HttpRequest("http://127.0.0.1:8685")); //https://testnet.nebulas.io
+ ChainID = 100;
+ from = new Wallet.Account("a6e5eb290e1438fce79f5cb8774a72621637c2c9654c8b2525ed1d7e4e73653f");
+ nodes.push("http://127.0.0.1:8685");
+} else if (env === 'testneb1') {
+ neb.setRequest(new HttpRequest("http://35.182.48.19:8685"));
+ ChainID = 1001;
+ from = new Wallet.Account("43181d58178263837a9a6b08f06379a348a5b362bfab3631ac78d2ac771c5df3");
+ nodes.push("http://35.182.48.19:8685");
+ nodes.push("http://13.57.245.249:8685");
+ nodes.push("http://54.219.151.126:8685");
+ nodes.push("http://18.218.165.90:8685");
+ nodes.push("http://18.219.28.97:8685");
+ nodes.push("http://13.58.44.3:8685");
+ nodes.push("http://35.177.214.138:8685");
+ nodes.push("http://35.176.94.224:8685");
+} else if (env === "testneb2") {
+ neb.setRequest(new HttpRequest("http://34.205.26.12:8685"));
+ ChainID = 1002;
+ from = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+ nodes.push("http://34.205.26.12:8685");
+ // nodes.push("http://54.206.9.246:8685");
+ // nodes.push("http://54.252.158.117:8685");
+ // nodes.push("http://34.206.53.244:8685");
+ // nodes.push("http://34.205.53.3:8685");
+ // nodes.push("http://52.3.226.40:8685");
+
+} else if (env === "testneb3") {
+
+ //neb.setRequest(new HttpRequest("http://52.47.199.42:8685"));
+ neb.setRequest(new HttpRequest("http://35.177.214.138:8685"));
+ //neb.setRequest(new HttpRequest("http://13.127.227.177:8685"));
+ ChainID = 1003;
+ from = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+ //nodes.push("http://13.127.227.177:8685");
+ nodes.push("http://35.177.214.138:8685");
+ //nodes.push("http://52.47.199.42:8685");
+
+} else if (env === "testneb4") {
+ neb.setRequest(new HttpRequest("http://34.208.233.164:8685"));
+ ChainID = 1004;
+ from = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+ nodes.push("http://34.208.233.164:8685");
+ nodes.push("http://54.245.29.152:8685");
+ nodes.push("http://52.34.73.0:8685");
+ nodes.push("http://54.71.175.99:8685");
+ nodes.push("http://34.213.130.120:8685");
+ nodes.push("http://18.197.107.228:8685");
+ nodes.push("http://18.197.106.150:8685");
+ nodes.push("http://54.93.121.146:8685");
+ nodes.push("http://18.195.159.210:8685");
+ nodes.push("http://18.197.157.46:8685");
+ nodes.push("http://18.228.3.118:8685");
+ nodes.push("http://18.231.173.99:8685");
+ nodes.push("http://18.231.124.140:8685");
+ nodes.push("http://18.231.183.193:8685");
+ nodes.push("http://18.231.162.23:8685");
+ nodes.push("http://34.253.237.122:8685");
+ nodes.push("http://34.244.129.30:8685");
+ nodes.push("http://54.229.241.235:8685");
+ nodes.push("http://54.229.177.109:8685");
+ nodes.push("http://34.250.18.201:8685");
+ nodes.push("http://13.127.227.177:8685");
+
+} else if (env === "liuliang") {
+ neb.setRequest(new HttpRequest("http://35.154.108.11:8685"));
+ ChainID = 1001;
+ from = new Wallet.Account("c75402f6ffe6edcc2c062134b5932151cb39b6486a7beb984792bb9da3f38b9f");
+ nodes.push("http://35.154.108.11:8685");
+
+} else if (env === "maintest"){
+ ChainID = 2;
+ from = new Wallet.Account("d2319a8a63b1abcb0cc6d4183198e5d7b264d271f97edf0c76cfdb1f2631848c");
+ neb.setRequest(new HttpRequest("http://54.149.15.132:8685"));
+ nodes.push("http://54.149.15.132:8685");
+ nodes.push("http://18.188.27.35:8685");
+ nodes.push("http://34.201.23.199:8685");
+ nodes.push("http://13.251.33.39:8685");
+ nodes.push("http://52.56.55.238:8685");
+
+} else if (env === "testnet_cal_super") {
+ neb.setRequest(new HttpRequest("http://13.57.96.40:8685"));
+ ChainID = 1001;
+ from = new Wallet.Account("25a3a441a34658e7a595a0eda222fa43ac51bd223017d17b420674fb6d0a4d52");
+ // from = new Wallet.Account("d2319a8a63b1abcb0cc6d4183198e5d7b264d271f97edf0c76cfdb1f2631848c");
+
+ nodes.push("http://52.60.150.236:8685");
+ nodes.push("http://13.57.96.40:8685");
+
+} else {
+ console.log("please input correct env local testneb1 testneb2");
+ return;
+}
+
+
+var count = AddressNumber * EachAccountSendTimes;
+
+var interval = setInterval(function () {
+
+ if (count >= AddressNumber * EachAccountSendTimes) {
+ count = 0;
+
+ console.log("sending request to ", env);
+ neb.api.getAccountState(from.getAddressString()).then(function (resp) {
+ console.log("master accountState resp:" + JSON.stringify(resp));
+ //lastnonce = parseInt(resp.result.nonce);
+ lastnonce = parseInt(resp.nonce);
+ console.log("lastnonce:", lastnonce);
+
+ claimTokens(lastnonce);
+ });
+ }
+
+}, 20000);
+
+
-neb.api.getAccountState(from.getAddressString()).then(function (resp) {
- console.log("master accountState resp:" + JSON.stringify(resp));
- lastnonce = parseInt(resp.nonce);
- console.log("lastnonce:", lastnonce);
- claimTokens(lastnonce);
-});
function claimTokens(nonce) {
console.log("initializing " + AddressNumber + " accounts with coins !!!")
+ console.log(from.getAddressString());
+
accountArray = new Array();
for (var i = 0; i < AddressNumber; i++) {
var account = Wallet.Account.NewAccount();
accountArray.push(account);
-
sendTransaction(0, 1, from, account, "1000000000000000", ++nonce);
-
- sleep(10);
+ sleep(5);
}
-
checkClaimTokens();
}
@@ -79,19 +174,33 @@ function sendTransaction(index, totalTimes, from, to, value, nonce, randomToAddr
to = accountArray[randomTo];
}
- var transaction = new Wallet.Transaction(1003, from, to, value, nonce);
+ var transaction = new Wallet.Transaction(ChainID, from, to, value, nonce);
transaction.signTransaction();
var rawTx = transaction.toProtoString();
+ var i = Math.floor((Math.random() * nodes.length));
+ var node = nodes[i];
+ neb.setRequest(new HttpRequest(node));
+ count ++;
neb.api.sendRawTransaction(rawTx).then(function (resp) {
- console.log("send raw transaction resp:" + JSON.stringify(resp));
+ console.log("send raw tx resp:" + JSON.stringify(resp) + " (" + index + "/" + totalTimes + ")");
+ //if (resp.result.txhash) {
if (resp.txhash) {
if (nonce % 10 === 0){
- sleep(10);
+ sleep(20);
}
sendTransaction(++index, totalTimes, from, to, value, ++nonce, randomToAddr);
}
});
+
+ // .catch(function (err) {
+ // console.log(err);
+ // console.log(JSON.stringify(err));
+ // console.log("send tx error, retry: " + "from:" + from.getAddressString() + " tx_index: (" + index + "/" + totalTimes + ")" + " node:" + node);
+ // sleep(10);
+ // sendTransaction(index, totalTimes, from, to, value, nonce, randomToAddr);
+ // }
+ // );
}
}
@@ -99,9 +208,9 @@ function checkClaimTokens() {
var interval = setInterval(function () {
neb.api.getAccountState(from.getAddressString()).then(function (resp) {
console.log("master accountState resp:" + JSON.stringify(resp));
+ //if (resp.result.nonce >= lastnonce + AddressNumber) {
if (resp.nonce >= lastnonce + AddressNumber) {
clearInterval(interval);
-
sendTransactionsForTps();
}
});
@@ -115,11 +224,10 @@ function sendTransactionsForTps() {
startTime = new Date().getTime();
for (var i = 0; i < AddressNumber; i++) {
-
var node = nodes[i % nodes.length];
neb.setRequest(new HttpRequest(node));
- var randomValue = Math.floor((Math.random() * 10));
+ var randomValue = Math.floor((Math.random() * 100));
sendTransaction(0, EachAccountSendTimes, accountArray[i], null, randomValue, 1, true /*random to addr*/);
- sleep(10);
+ sleep(5);
}
}
diff --git a/nebtestkit/cases/testnet_config.js b/nebtestkit/cases/testnet_config.js
index 09fafb10e..f53559abc 100644
--- a/nebtestkit/cases/testnet_config.js
+++ b/nebtestkit/cases/testnet_config.js
@@ -59,7 +59,7 @@ var TestNet = function (env) {
// throw new Error("invalid env (" + env + ").");
this.ChainId = 100;
- this.sourceAccount = new Wallet.Account("d80f115bdbba5ef215707a8d7053c16f4e65588fd50b0f83369ad142b99891b5");
+ this.sourceAccount = new Wallet.Account("1d3fe06a53919e728315e2ccca41d4aa5b190845a79007797517e62dbc0df454");
this.coinbase = "n1QZMXSZtW7BUerroSms4axNfyBGyFGkrh5";
this.apiEndPoint = "http://127.0.0.1:8685";
diff --git a/nebtestkit/package.json b/nebtestkit/package.json
index 9059f495a..2a6c52174 100644
--- a/nebtestkit/package.json
+++ b/nebtestkit/package.json
@@ -18,13 +18,13 @@
"grpc": "^1.10.0",
"lodash": "^4.17.5",
"minimist": "^1.2.0",
- "nebulas": "^0.3.7",
+ "nebulas": "^0.4.6",
"node-schedule": "^1.3.0",
"protobufjs": "^6.8.6",
+ "request": "^2.85.0",
+ "request-promise": "^4.2.2",
"shelljs": "^0.7.8",
"sync-request": "^4.1.0",
- "system-sleep": "^1.3.6",
- "request": "^2.85.0",
- "request-promise": "^4.2.2"
+ "system-sleep": "^1.3.6"
}
}
diff --git a/net/dispatcher.go b/net/dispatcher.go
index 2f16b6559..b5d4c94c4 100644
--- a/net/dispatcher.go
+++ b/net/dispatcher.go
@@ -102,6 +102,9 @@ func (dp *Dispatcher) loop() {
msgType := msg.MessageType()
v, _ := dp.subscribersMap.Load(msgType)
+ if v == nil {
+ continue
+ }
m, _ := v.(*sync.Map)
m.Range(func(key, value interface{}) bool {
diff --git a/net/neb_message.go b/net/neb_message.go
index 66173089a..f566cdf3f 100644
--- a/net/neb_message.go
+++ b/net/neb_message.go
@@ -76,12 +76,17 @@ const (
// Consider that a block is too large in sync.
MaxNebMessageDataLength = 512 * 1024 * 1024 // 512m.
MaxNebMessageNameLength = 24 - 12 // 12.
+
+ DefaultReservedFlag = 0x0
+ ReservedCompressionEnableFlag = 0x80
+ ReservedCompressionClientFlag = 0x1
)
// Error types
var (
MagicNumber = []byte{0x4e, 0x45, 0x42, 0x31}
- DefaultReserved = []byte{0x80, 0x0, 0x0}
+ DefaultReserved = []byte{DefaultReservedFlag, DefaultReservedFlag, DefaultReservedFlag}
+ CurrentReserved = []byte{DefaultReservedFlag | ReservedCompressionEnableFlag, DefaultReservedFlag, DefaultReservedFlag}
ErrInsufficientMessageHeaderLength = errors.New("insufficient message header length")
ErrInsufficientMessageDataLength = errors.New("insufficient message data length")
@@ -90,6 +95,7 @@ var (
ErrInvalidDataCheckSum = errors.New("invalid data checksum")
ErrExceedMaxDataLength = errors.New("exceed max data length")
ErrExceedMaxMessageNameLength = errors.New("exceed max message name length")
+ ErrUncompressMessageFailed = errors.New("uncompress message failed")
)
//NebMessage struct
@@ -157,7 +163,21 @@ func (message *NebMessage) HeaderWithoutCheckSum() []byte {
}
// Data return data
-func (message *NebMessage) Data() []byte {
+func (message *NebMessage) Data() ([]byte, error) {
+ reserved := message.Reserved()
+ data := message.content[NebMessageHeaderLength:]
+ if (reserved[0] & ReservedCompressionEnableFlag) > 0 {
+ var err error
+ data, err = snappy.Decode(nil, data)
+ if err != nil {
+ return nil, ErrUncompressMessageFailed
+ }
+ }
+ return data, nil
+}
+
+// OriginalData return original data
+func (message *NebMessage) OriginalData() []byte {
return message.content[NebMessageHeaderLength:]
}
@@ -172,15 +192,10 @@ func (message *NebMessage) Length() uint64 {
}
// NewNebMessage new neb message
-func NewNebMessage(s *Stream, reserved []byte, version byte, messageName string, data []byte) (*NebMessage, error) {
- chainID := s.node.config.ChainID
- // if remote peer version >= compress version, compress message data.
- if messageName != HELLO {
- if v, ok := s.compressFlag.Load(s.pid.Pretty()); ok {
- if (v.(byte) & 0x80) > 0 {
- data = snappy.Encode(nil, data)
- }
- }
+func NewNebMessage(chainID uint32, reserved []byte, version byte, messageName string, data []byte) (*NebMessage, error) {
+ // Process message compression
+ if (reserved[2] != ReservedCompressionClientFlag) && ((reserved[0] & ReservedCompressionEnableFlag) > 0) {
+ data = snappy.Encode(nil, data)
}
if len(data) > MaxNebMessageDataLength {
@@ -199,7 +214,6 @@ func NewNebMessage(s *Stream, reserved []byte, version byte, messageName string,
"limits": MaxNebMessageNameLength,
}).Debug("Exceeded max message name length.")
return nil, ErrExceedMaxMessageNameLength
-
}
dataCheckSum := crc32.ChecksumIEEE(data)
@@ -291,7 +305,7 @@ func (message *NebMessage) VerifyHeader() error {
// VerifyData verify message data
func (message *NebMessage) VerifyData() error {
- expectedCheckSum := crc32.ChecksumIEEE(message.Data())
+ expectedCheckSum := crc32.ChecksumIEEE(message.OriginalData())
if expectedCheckSum != message.DataCheckSum() {
logging.VLog().WithFields(logrus.Fields{
"expect": expectedCheckSum,
diff --git a/net/stream.go b/net/stream.go
index 758d4a022..83b35420e 100644
--- a/net/stream.go
+++ b/net/stream.go
@@ -21,12 +21,10 @@ package net
import (
"errors"
"fmt"
- "hash/crc32"
+ "strings"
"sync"
"time"
- "github.com/golang/snappy"
-
"github.com/gogo/protobuf/proto"
libnet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
@@ -38,14 +36,15 @@ import (
// Stream Message Type
const (
- ClientVersion = "0.3.0"
- NebProtocolID = "/neb/1.0.0"
- HELLO = "hello"
- OK = "ok"
- BYE = "bye"
- SYNCROUTE = "syncroute"
- ROUTETABLE = "routetable"
- RECVEDMSG = "recvedmsg"
+ ClientVersion = "0.3.0"
+ NebProtocolID = "/neb/1.0.0"
+ HELLO = "hello"
+ OK = "ok"
+ BYE = "bye"
+ SYNCROUTE = "syncroute"
+ ROUTETABLE = "routetable"
+ RECVEDMSG = "recvedmsg"
+ CurrentVersion = 0x0
)
// Stream Status
@@ -59,7 +58,6 @@ const (
var (
ErrShouldCloseConnectionAndExitLoop = errors.New("should close connection and exit loop")
ErrStreamIsNotConnected = errors.New("stream is not connected")
- ErrUncompressMessageFailed = errors.New("uncompress message failed")
)
// Stream define the structure of a stream in p2p network
@@ -80,7 +78,7 @@ type Stream struct {
latestReadAt int64
latestWriteAt int64
msgCount map[string]int
- compressFlag *sync.Map
+ reservedFlag []byte
}
// NewStream return a new Stream
@@ -110,7 +108,7 @@ func newStreamInstance(pid peer.ID, addr ma.Multiaddr, stream libnet.Stream, nod
latestReadAt: 0,
latestWriteAt: 0,
msgCount: make(map[string]int),
- compressFlag: new(sync.Map),
+ reservedFlag: DefaultReserved,
}
}
@@ -175,7 +173,7 @@ func (s *Stream) SendProtoMessage(messageName string, pb proto.Message, priority
// SendMessage send msg to buffer
func (s *Stream) SendMessage(messageName string, data []byte, priority int) error {
- message, err := NewNebMessage(s, DefaultReserved, 0, messageName, data)
+ message, err := NewNebMessage(s.node.config.ChainID, s.reservedFlag, CurrentVersion, messageName, data)
if err != nil {
return err
}
@@ -264,7 +262,7 @@ func (s *Stream) WriteNebMessage(message *NebMessage) error {
}
// WriteProtoMessage write proto msg in the stream
-func (s *Stream) WriteProtoMessage(messageName string, pb proto.Message) error {
+func (s *Stream) WriteProtoMessage(messageName string, pb proto.Message, reservedClientFlag byte) error {
data, err := proto.Marshal(pb)
if err != nil {
logging.VLog().WithFields(logrus.Fields{
@@ -275,12 +273,20 @@ func (s *Stream) WriteProtoMessage(messageName string, pb proto.Message) error {
return err
}
- return s.WriteMessage(messageName, data)
+ return s.WriteMessage(messageName, data, reservedClientFlag)
}
// WriteMessage write raw msg in the stream
-func (s *Stream) WriteMessage(messageName string, data []byte) error {
- message, err := NewNebMessage(s, DefaultReserved, 0, messageName, data)
+func (s *Stream) WriteMessage(messageName string, data []byte, reservedClientFlag byte) error {
+ // hello and ok messages come with the client flag bit.
+ var reserved = make([]byte, len(s.reservedFlag))
+ copy(reserved, s.reservedFlag)
+
+ if reservedClientFlag == ReservedCompressionClientFlag {
+ reserved[2] = s.reservedFlag[2] | reservedClientFlag
+ }
+
+ message, err := NewNebMessage(s.node.config.ChainID, reserved, CurrentVersion, messageName, data)
if err != nil {
return err
}
@@ -443,28 +449,13 @@ func (s *Stream) writeLoop() {
func (s *Stream) handleMessage(message *NebMessage) error {
messageName := message.MessageName()
- compressFlag := message.Reserved()[0] & 0x80
- s.compressFlag.Store(s.pid.Pretty(), compressFlag)
s.msgCount[messageName]++
- // Network data compression compatible with old clients.
- // uncompress message data.
- var data = message.Data()
- if messageName != HELLO {
- if compressFlag > 0 {
- var err error
- data, err = snappy.Decode(nil, message.Data())
- if err != nil {
- return ErrUncompressMessageFailed
- }
- }
- }
-
switch messageName {
case HELLO:
- return s.onHello(message, data)
+ return s.onHello(message)
case OK:
- return s.onOk(message, data)
+ return s.onOk(message)
case BYE:
return s.onBye(message)
}
@@ -478,12 +469,19 @@ func (s *Stream) handleMessage(message *NebMessage) error {
case SYNCROUTE:
return s.onSyncRoute(message)
case ROUTETABLE:
- return s.onRouteTable(message, data)
+ return s.onRouteTable(message)
default:
+ data, err := s.getData(message)
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "err": err,
+ "messageName": message.MessageName(),
+ }).Info("Handle message data occurs error.")
+ return err
+ }
s.node.netService.PutMessage(NewBaseMessage(message.MessageName(), s.pid.Pretty(), data))
// record recv message.
- dataCheckSum := crc32.ChecksumIEEE(data)
- RecordRecvMessage(s, dataCheckSum)
+ RecordRecvMessage(s, message.DataCheckSum())
}
return nil
@@ -520,7 +518,7 @@ func (s *Stream) close(reason error) {
// Bye say bye in the stream
func (s *Stream) Bye() {
- s.WriteMessage(BYE, []byte{})
+ s.WriteMessage(BYE, []byte{}, DefaultReservedFlag)
s.close(errors.New("bye: force close"))
}
@@ -537,11 +535,11 @@ func (s *Stream) Hello() error {
NodeId: s.node.id.String(),
ClientVersion: ClientVersion,
}
- return s.WriteProtoMessage(HELLO, msg)
+ return s.WriteProtoMessage(HELLO, msg, ReservedCompressionClientFlag)
}
-func (s *Stream) onHello(message *NebMessage, data []byte) error {
- msg, err := netpb.HelloMessageFromProto(data)
+func (s *Stream) onHello(message *NebMessage) error {
+ msg, err := netpb.HelloMessageFromProto(message.OriginalData())
if err != nil {
return ErrShouldCloseConnectionAndExitLoop
}
@@ -557,6 +555,10 @@ func (s *Stream) onHello(message *NebMessage, data []byte) error {
return ErrShouldCloseConnectionAndExitLoop
}
+ if (message.Reserved()[2] & ReservedCompressionClientFlag) > 0 {
+ s.reservedFlag = CurrentReserved
+ }
+
// add to route table.
s.node.routeTable.AddPeerStream(s)
@@ -574,11 +576,11 @@ func (s *Stream) Ok() error {
ClientVersion: ClientVersion,
}
- return s.WriteProtoMessage(OK, resp)
+ return s.WriteProtoMessage(OK, resp, ReservedCompressionClientFlag)
}
-func (s *Stream) onOk(message *NebMessage, data []byte) error {
- msg, err := netpb.OKMessageFromProto(data)
+func (s *Stream) onOk(message *NebMessage) error {
+ msg, err := netpb.OKMessageFromProto(message.OriginalData())
if err != nil {
return ErrShouldCloseConnectionAndExitLoop
}
@@ -594,6 +596,10 @@ func (s *Stream) onOk(message *NebMessage, data []byte) error {
return ErrShouldCloseConnectionAndExitLoop
}
+ if (message.Reserved()[2] & ReservedCompressionClientFlag) > 0 {
+ s.reservedFlag = CurrentReserved
+ }
+
// add to route table.
s.node.routeTable.AddPeerStream(s)
@@ -641,7 +647,12 @@ func (s *Stream) RouteTable() error {
return s.SendProtoMessage(ROUTETABLE, msg, MessagePriorityHigh)
}
-func (s *Stream) onRouteTable(message *NebMessage, data []byte) error {
+func (s *Stream) onRouteTable(message *NebMessage) error {
+ data, err := s.getData(message)
+ if err != nil {
+ return err
+ }
+
peers := new(netpb.Peers)
if err := proto.Unmarshal(data, peers); err != nil {
logging.VLog().WithFields(logrus.Fields{
@@ -664,7 +675,52 @@ func (s *Stream) finishHandshake() {
s.handshakeSucceedCh <- true
}
+func (s *Stream) getData(message *NebMessage) ([]byte, error) {
+ var data []byte
+ if ByteSliceEqualBCE(s.reservedFlag, CurrentReserved) {
+ var err error
+ data, err = message.Data()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ data = message.OriginalData()
+ }
+ return data, nil
+}
+
// CheckClientVersionCompatibility if two clients are compatible
+// If the clientVersion of node A is X.Y.Z, then node B must be X.Y.{} to be compatible with A.
func CheckClientVersionCompatibility(v1, v2 string) bool {
- return v1 == v2
+ s1 := strings.Split(v1, ".")
+ s2 := strings.Split(v1, ".")
+
+ if len(s1) != 3 || len(s2) != 3 {
+ return false
+ }
+
+ if s1[0] != s2[0] || s1[1] != s2[1] {
+ return false
+ }
+ return true
+}
+
+// ByteSliceEqualBCE determines whether two byte arrays are equal.
+func ByteSliceEqualBCE(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+
+ if (a == nil) != (b == nil) {
+ return false
+ }
+
+ b = b[:len(a)]
+ for i, v := range a {
+ if v != b[i] {
+ return false
+ }
+ }
+
+ return true
}
diff --git a/net/testing/test/main.go b/net/testing/test/main.go
deleted file mode 100644
index f53cbf100..000000000
--- a/net/testing/test/main.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "strings"
-)
-
-func main() {
- resp, err := http.Get("https://api.github.com/repos/btcsuite/btcd/commits?client_id=80386779008eea5dab41&client_secret=f2086aebf790729026fb209b803010029821d8a3")
-
- if err != nil {
- // handle error
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
-
- if err != nil {
- // handle error
- }
- var f interface{}
- json.Unmarshal(body, &f)
-
- for _, n := range f.([]interface{}) {
- for k, v := range n.(map[string]interface{}) {
- if k == "commit" {
- value := v.(map[string]interface{})["message"].(string)
- fmt.Println(value)
- if strings.Contains(value, "gx publish ") {
- url := v.(map[string]interface{})["url"].(string)
- fmt.Println(v.(map[string]interface{})["message"])
- temps := strings.Split(url, "/")
- fmt.Println(temps[len(temps)-1])
-
- str := "github.com/agl/ed25519"
- temps = strings.Split(str, "ghub.com")
- fmt.Println(len(temps))
- fmt.Println(temps)
- return
- }
- }
- }
- }
-
-}
diff --git a/nf/nvm/blockchain.go b/nf/nvm/blockchain.go
index 31e2f5baf..ce93099e0 100644
--- a/nf/nvm/blockchain.go
+++ b/nf/nvm/blockchain.go
@@ -26,6 +26,7 @@ import (
"encoding/json"
"github.com/nebulasio/go-nebulas/core"
+ "github.com/nebulasio/go-nebulas/core/state"
"github.com/nebulasio/go-nebulas/util"
"github.com/nebulasio/go-nebulas/util/byteutils"
"github.com/nebulasio/go-nebulas/util/logging"
@@ -180,6 +181,37 @@ func TransferFunc(handler unsafe.Pointer, to *C.char, v *C.char, gasCnt *C.size_
}
}
+ if engine.ctx.block.Height() >= core.TransferFromContractEventRecordableHeight {
+ cAddr, err := core.AddressParseFromBytes(engine.ctx.contract.Address())
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "txhash": engine.ctx.tx.Hash().String(),
+ "address": engine.ctx.contract.Address(),
+ "err": err,
+ }).Debug("failed to parse contract address")
+ return TransferRecordEventFailed
+ }
+
+ event := &TransferFromContractEvent{
+ Amount: amount.String(),
+ From: cAddr.String(),
+ To: addr.String(),
+ }
+
+ eData, err := json.Marshal(event)
+ if err != nil {
+ logging.VLog().WithFields(logrus.Fields{
+ "from": cAddr.String(),
+ "to": addr.String(),
+ "amount": amount.String(),
+ "err": err,
+ }).Debug("failed to marshal TransferFromContractEvent")
+ return TransferRecordEventFailed
+ }
+
+ engine.ctx.state.RecordEvent(engine.ctx.tx.Hash(), &state.Event{Topic: core.TopicTransferFromContract, Data: string(eData)})
+ }
+
return TransferFuncSuccess
}
diff --git a/nf/nvm/context.go b/nf/nvm/context.go
index e51d501d1..89136a3c0 100644
--- a/nf/nvm/context.go
+++ b/nf/nvm/context.go
@@ -35,6 +35,7 @@ type SerializableBlock struct {
Timestamp int64 `json:"timestamp"`
Hash string `json:"hash"`
Height uint64 `json:"height"`
+ Seed string `json:"seed,omitempty"`
}
// SerializableTransaction serializable transaction
@@ -85,6 +86,9 @@ func toSerializableBlock(block Block) *SerializableBlock {
Hash: "",
Height: block.Height(),
}
+ if block.RandomAvailable() {
+ sBlock.Seed = block.RandomSeed()
+ }
return sBlock
}
diff --git a/nf/nvm/engine_v8.go b/nf/nvm/engine_v8.go
index ba524ad6e..20dbd6aae 100644
--- a/nf/nvm/engine_v8.go
+++ b/nf/nvm/engine_v8.go
@@ -449,7 +449,6 @@ func (e *V8Engine) prepareRunnableContractScript(source, function, args string)
}
runnableSource = fmt.Sprintf(`Blockchain.blockParse("%s");
Blockchain.transactionParse("%s");
- Object.freeze(Blockchain);
var __contract = require("%s");
var __instance = new __contract();
__instance["%s"].apply(__instance, JSON.parse("%s"));`,
diff --git a/nf/nvm/engine_v8_test.go b/nf/nvm/engine_v8_test.go
index d96381ca4..f1b9e556e 100644
--- a/nf/nvm/engine_v8_test.go
+++ b/nf/nvm/engine_v8_test.go
@@ -28,8 +28,15 @@ import (
"strings"
"sync"
"testing"
+ "time"
+
+ "github.com/gogo/protobuf/proto"
+ "github.com/nebulasio/go-nebulas/account"
+ "github.com/nebulasio/go-nebulas/net"
"github.com/nebulasio/go-nebulas/consensus/dpos"
+ "github.com/nebulasio/go-nebulas/core/pb"
+ "github.com/nebulasio/go-nebulas/neblet/pb"
"encoding/json"
@@ -69,6 +76,21 @@ func (block *testBlock) Height() uint64 {
return 1
}
+// RandomSeed mock
+func (block *testBlock) RandomSeed() string {
+ return "59fc526072b09af8a8ca9732dae17132c4e9127e43cf2232"
+}
+
+// RandomAvailable mock
+func (block *testBlock) RandomAvailable() bool {
+ return true
+}
+
+// DateAvailable
+func (block *testBlock) DateAvailable() bool {
+ return true
+}
+
// GetTransaction mock
func (block *testBlock) GetTransaction(hash byteutils.Hash) (*core.Transaction, error) {
return nil, nil
@@ -123,9 +145,11 @@ func TestRunScriptSource(t *testing.T) {
{"test/test_storage_class.js", nil, "\"\""},
{"test/test_storage.js", nil, "\"\""},
{"test/test_eval.js", core.ErrExecutionFailed, "EvalError: Code generation from strings disallowed for this context"},
- {"test/test_date.js", core.ErrExecutionFailed, "TypeError: Date.now is not a function"},
+ {"test/test_date.js", nil, "\"\""},
{"test/test_bignumber_random.js", core.ErrExecutionFailed, "Error: BigNumber.random is not allowed in nvm."},
- {"test/test_random.js", core.ErrExecutionFailed, "Error: Math.random func is not allowed in nvm."},
+ {"test/test_random_enable.js", nil, "\"\""},
+ {"test/test_random_disable.js", core.ErrExecutionFailed, "Error: Math.random func is not allowed in nvm."},
+ {"test/test_random_seed.js", core.ErrExecutionFailed, "Error: input seed must be a string"},
}
for _, tt := range tests {
@@ -1229,3 +1253,342 @@ func TestRequireModule(t *testing.T) {
})
}
}
+
+type Neb struct {
+ config *nebletpb.Config
+ chain *core.BlockChain
+ ns net.Service
+ am *account.Manager
+ genesis *corepb.Genesis
+ storage storage.Storage
+ consensus core.Consensus
+ emitter *core.EventEmitter
+ nvm core.NVM
+}
+
+func mockNeb(t *testing.T) *Neb {
+ // storage, _ := storage.NewDiskStorage("test.db")
+ // storage, err := storage.NewRocksStorage("rocks.db")
+ // assert.Nil(t, err)
+ storage, _ := storage.NewMemoryStorage()
+ eventEmitter := core.NewEventEmitter(1024)
+ genesisConf := MockGenesisConf()
+ consensus := dpos.NewDpos()
+ nvm := NewNebulasVM()
+ neb := &Neb{
+ genesis: genesisConf,
+ storage: storage,
+ emitter: eventEmitter,
+ consensus: consensus,
+ nvm: nvm,
+ config: &nebletpb.Config{
+ Chain: &nebletpb.ChainConfig{
+ ChainId: genesisConf.Meta.ChainId,
+ Keydir: "keydir",
+ StartMine: true,
+ Coinbase: "n1dYu2BXgV3xgUh8LhZu8QDDNr15tz4hVDv",
+ Miner: "n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE",
+ Passphrase: "passphrase",
+ },
+ },
+ ns: mockNetService{},
+ }
+
+ am, _ := account.NewManager(neb)
+ neb.am = am
+
+ chain, err := core.NewBlockChain(neb)
+ assert.Nil(t, err)
+ neb.chain = chain
+ assert.Nil(t, consensus.Setup(neb))
+ assert.Nil(t, chain.Setup(neb))
+
+ var ns mockNetService
+ neb.ns = ns
+ neb.chain.BlockPool().RegisterInNetwork(ns)
+
+ eventEmitter.Start()
+ return neb
+}
+
+func (n *Neb) Config() *nebletpb.Config {
+ return n.config
+}
+
+func (n *Neb) BlockChain() *core.BlockChain {
+ return n.chain
+}
+
+func (n *Neb) NetService() net.Service {
+ return n.ns
+}
+
+func (n *Neb) IsActiveSyncing() bool {
+ return true
+}
+
+func (n *Neb) AccountManager() core.AccountManager {
+ return n.am
+}
+
+func (n *Neb) Genesis() *corepb.Genesis {
+ return n.genesis
+}
+
+func (n *Neb) Storage() storage.Storage {
+ return n.storage
+}
+
+func (n *Neb) EventEmitter() *core.EventEmitter {
+ return n.emitter
+}
+
+func (n *Neb) Consensus() core.Consensus {
+ return n.consensus
+}
+
+func (n *Neb) Nvm() core.NVM {
+ return n.nvm
+}
+
+func (n *Neb) StartActiveSync() {}
+
+func (n *Neb) StartPprof(string) error { return nil }
+
+func (n *Neb) SetGenesis(genesis *corepb.Genesis) {
+ n.genesis = genesis
+}
+
+var (
+ DefaultOpenDynasty = []string{
+ "n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE",
+ "n1GmkKH6nBMw4rrjt16RrJ9WcgvKUtAZP1s",
+ "n1H4MYms9F55ehcvygwWE71J8tJC4CRr2so",
+ "n1JAy4X6KKLCNiTd7MWMRsVBjgdVq5WCCpf",
+ "n1LkDi2gGMqPrjYcczUiweyP4RxTB6Go1qS",
+ "n1LmP9K8pFF33fgdgHZonFEMsqZinJ4EUqk",
+ "n1MNXBKm6uJ5d76nJTdRvkPNVq85n6CnXAi",
+ "n1NrMKTYESZRCwPFDLFKiKREzZKaN1nhQvz",
+ "n1NwoSCDFwFL2981k6j9DPooigW33hjAgTa",
+ "n1PfACnkcfJoNm1Pbuz55pQCwueW1BYs83m",
+ "n1Q8mxXp4PtHaXtebhY12BnHEwu4mryEkXH",
+ "n1RYagU8n3JSuV4R7q4Qs5gQJ3pEmrZd6cJ",
+ "n1SAQy3ix1pZj8MPzNeVqpAmu1nCVqb5w8c",
+ "n1SHufJdxt2vRWGKAxwPETYfEq3MCQXnEXE",
+ "n1SSda41zGr9FKF5DJNE2ryY1ToNrndMauN",
+ "n1TmQtaCn3PNpk4f4ycwrBxCZFSVKvwBtzc",
+ "n1UM7z6MqnGyKEPvUpwrfxZpM1eB7UpzmLJ",
+ "n1UnCsJZjQiKyQiPBr7qG27exqCLuWUf1d7",
+ "n1XkoVVjswb5Gek3rRufqjKNpwrDdsnQ7Hq",
+ "n1cYKNHTeVW9v1NQRWuhZZn9ETbqAYozckh",
+ "n1dYu2BXgV3xgUh8LhZu8QDDNr15tz4hVDv",
+ }
+)
+
+// MockGenesisConf return mock genesis conf
+func MockGenesisConf() *corepb.Genesis {
+ dynasty := []string{}
+ for _, v := range DefaultOpenDynasty {
+ dynasty = append(dynasty, v)
+ }
+ return &corepb.Genesis{
+ Meta: &corepb.GenesisMeta{ChainId: 0},
+ Consensus: &corepb.GenesisConsensus{
+ Dpos: &corepb.GenesisConsensusDpos{
+ Dynasty: dynasty,
+ },
+ },
+ TokenDistribution: []*corepb.GenesisTokenDistribution{
+ &corepb.GenesisTokenDistribution{
+ Address: "n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE",
+ Value: "5000000000000000000000000",
+ },
+ &corepb.GenesisTokenDistribution{
+ Address: "n1GmkKH6nBMw4rrjt16RrJ9WcgvKUtAZP1s",
+ Value: "5000000000000000000000000",
+ },
+ &corepb.GenesisTokenDistribution{
+ Address: "n1H4MYms9F55ehcvygwWE71J8tJC4CRr2so",
+ Value: "5000000000000000000000000",
+ },
+ &corepb.GenesisTokenDistribution{
+ Address: "n1JAy4X6KKLCNiTd7MWMRsVBjgdVq5WCCpf",
+ Value: "5000000000000000000000000",
+ },
+ &corepb.GenesisTokenDistribution{
+ Address: "n1LkDi2gGMqPrjYcczUiweyP4RxTB6Go1qS",
+ Value: "5000000000000000000000000",
+ },
+ &corepb.GenesisTokenDistribution{
+ Address: "n1LmP9K8pFF33fgdgHZonFEMsqZinJ4EUqk",
+ Value: "5000000000000000000000000",
+ },
+ },
+ }
+}
+
+var (
+ received = []byte{}
+)
+
+type mockNetService struct{}
+
+func (n mockNetService) Start() error { return nil }
+func (n mockNetService) Stop() {}
+
+func (n mockNetService) Node() *net.Node { return nil }
+
+func (n mockNetService) Sync(net.Serializable) error { return nil }
+
+func (n mockNetService) Register(...*net.Subscriber) {}
+func (n mockNetService) Deregister(...*net.Subscriber) {}
+
+func (n mockNetService) Broadcast(name string, msg net.Serializable, priority int) {
+ pb, _ := msg.ToProto()
+ bytes, _ := proto.Marshal(pb)
+ received = bytes
+}
+func (n mockNetService) Relay(name string, msg net.Serializable, priority int) {
+ pb, _ := msg.ToProto()
+ bytes, _ := proto.Marshal(pb)
+ received = bytes
+}
+func (n mockNetService) SendMsg(name string, msg []byte, target string, priority int) error {
+ received = msg
+ return nil
+}
+
+func (n mockNetService) SendMessageToPeers(messageName string, data []byte, priority int, filter net.PeerFilterAlgorithm) []string {
+ return make([]string, 0)
+}
+func (n mockNetService) SendMessageToPeer(messageName string, data []byte, priority int, peerID string) error {
+ return nil
+}
+
+func (n mockNetService) ClosePeer(peerID string, reason error) {}
+
+func (n mockNetService) BroadcastNetworkID([]byte) {}
+
+type contract struct {
+ contractPath string
+ sourceType string
+ initArgs string
+}
+
+type call struct {
+ function string
+ args string
+}
+
+func TestInnerTransactions(t *testing.T) {
+ tests := []struct {
+ name string
+ contracts []contract
+ call call
+ }{
+ {
+ "deploy test_require_module.js",
+ []contract{
+ contract{
+ "./test/bank_vault_contract.js",
+ "js",
+ "",
+ },
+ contract{
+ "./test/bank_vault_contract.js",
+ "js",
+ "",
+ },
+ },
+ call{
+ "save",
+ "[1]",
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ neb := mockNeb(t)
+ tail := neb.chain.TailBlock()
+ manager, err := account.NewManager(neb)
+ assert.Nil(t, err)
+
+ a, _ := core.AddressParse("n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE")
+ assert.Nil(t, manager.Unlock(a, []byte("passphrase"), keystore.YearUnlockDuration))
+ b, _ := core.AddressParse("n1GmkKH6nBMw4rrjt16RrJ9WcgvKUtAZP1s")
+ assert.Nil(t, manager.Unlock(b, []byte("passphrase"), keystore.YearUnlockDuration))
+ c, _ := core.AddressParse("n1H4MYms9F55ehcvygwWE71J8tJC4CRr2so")
+ assert.Nil(t, manager.Unlock(c, []byte("passphrase"), keystore.YearUnlockDuration))
+
+ elapsedSecond := dpos.BlockIntervalInMs / dpos.SecondInMs
+ consensusState, err := tail.WorldState().NextConsensusState(elapsedSecond)
+ assert.Nil(t, err)
+ block, err := core.NewBlock(neb.chain.ChainID(), b, tail)
+ assert.Nil(t, err)
+ block.WorldState().SetConsensusState(consensusState)
+ block.SetTimestamp(consensusState.TimeStamp())
+
+ contractsAddr := []string{}
+
+ t.Run(tt.name, func(t *testing.T) {
+ for k, v := range tt.contracts {
+ data, err := ioutil.ReadFile(v.contractPath)
+ assert.Nil(t, err, "contract path read error")
+ source := string(data)
+ sourceType := "js"
+ argsDeploy := ""
+ deploy, _ := core.NewDeployPayload(source, sourceType, argsDeploy)
+ payloadDeploy, _ := deploy.ToBytes()
+
+ value, _ := util.NewUint128FromInt(0)
+ gasLimit, _ := util.NewUint128FromInt(200000)
+ txDeploy, err := core.NewTransaction(neb.chain.ChainID(), a, a, value, uint64(k+1), core.TxPayloadDeployType, payloadDeploy, core.TransactionGasPrice, gasLimit)
+ assert.Nil(t, err)
+ assert.Nil(t, manager.SignTransaction(a, txDeploy))
+ assert.Nil(t, neb.chain.TransactionPool().Push(txDeploy))
+
+ contractAddr, err := txDeploy.GenerateContractAddress()
+ assert.Nil(t, err)
+ contractsAddr = append(contractsAddr, contractAddr.String())
+ }
+ })
+
+ block.CollectTransactions((time.Now().Unix() + 1) * dpos.SecondInMs)
+ assert.Nil(t, block.Seal())
+ assert.Nil(t, manager.SignBlock(b, block))
+ assert.Nil(t, neb.chain.BlockPool().Push(block))
+
+ for _, v := range contractsAddr {
+ contract, err := core.AddressParse(v)
+ assert.Nil(t, err)
+ _, err = neb.chain.TailBlock().CheckContract(contract)
+ assert.Nil(t, err)
+ }
+
+ elapsedSecond = dpos.BlockIntervalInMs / dpos.SecondInMs
+ tail = neb.chain.TailBlock()
+ consensusState, err = tail.WorldState().NextConsensusState(elapsedSecond)
+ assert.Nil(t, err)
+ block, err = core.NewBlock(neb.chain.ChainID(), c, tail)
+ assert.Nil(t, err)
+ block.WorldState().SetConsensusState(consensusState)
+ block.SetTimestamp(consensusState.TimeStamp())
+
+ callPayload, _ := core.NewCallPayload(tt.call.function, tt.call.args)
+ payloadCall, _ := callPayload.ToBytes()
+
+ value, _ := util.NewUint128FromInt(0)
+ gasLimit, _ := util.NewUint128FromInt(200000)
+ txCall, err := core.NewTransaction(neb.chain.ChainID(), a, a, value, uint64(len(contractsAddr)+1), core.TxPayloadCallType, payloadCall, core.TransactionGasPrice, gasLimit)
+ assert.Nil(t, err)
+ assert.Nil(t, manager.SignTransaction(a, txCall))
+ assert.Nil(t, neb.chain.TransactionPool().Push(txCall))
+
+ block.CollectTransactions((time.Now().Unix() + 1) * dpos.SecondInMs)
+ assert.Nil(t, block.Seal())
+ assert.Nil(t, manager.SignBlock(c, block))
+ assert.Nil(t, neb.chain.BlockPool().Push(block))
+
+ // check
+ }
+}
diff --git a/nf/nvm/event.go b/nf/nvm/event.go
index 25fdb587f..3f3bac940 100644
--- a/nf/nvm/event.go
+++ b/nf/nvm/event.go
@@ -32,6 +32,13 @@ const (
EventBaseGasCount = 20
)
+// TransferFromContractEvent event for transfer in contract
+type TransferFromContractEvent struct {
+ Amount string `json:"amount"`
+ From string `json:"from"`
+ To string `json:"to"`
+}
+
// EventTriggerFunc export EventTriggerFunc
//export EventTriggerFunc
func EventTriggerFunc(handler unsafe.Pointer, topic, data *C.char, gasCnt *C.size_t) {
diff --git a/nf/nvm/keydir b/nf/nvm/keydir
new file mode 120000
index 000000000..188b3b5d4
--- /dev/null
+++ b/nf/nvm/keydir
@@ -0,0 +1 @@
+../../keydir/
\ No newline at end of file
diff --git a/nf/nvm/lib/date.js b/nf/nvm/lib/date.js
new file mode 120000
index 000000000..b2d62a9aa
--- /dev/null
+++ b/nf/nvm/lib/date.js
@@ -0,0 +1 @@
+../v8/lib/date.js
\ No newline at end of file
diff --git a/nf/nvm/lib/random.js b/nf/nvm/lib/random.js
new file mode 120000
index 000000000..6d184e127
--- /dev/null
+++ b/nf/nvm/lib/random.js
@@ -0,0 +1 @@
+../v8/lib/random.js
\ No newline at end of file
diff --git a/nf/nvm/test/contract_accept_func_standard.js b/nf/nvm/test/contract_accept_func_standard.js
new file mode 100644
index 000000000..c5ca72a81
--- /dev/null
+++ b/nf/nvm/test/contract_accept_func_standard.js
@@ -0,0 +1,107 @@
+
+"use strict";
+
+var DepositeContent = function (text) {
+ if (text) {
+ var o = JSON.parse(text);
+ this.balance = new BigNumber(o.balance);
+ this.expiryHeight = new BigNumber(o.expiryHeight);
+ } else {
+ this.balance = new BigNumber(0);
+ this.expiryHeight = new BigNumber(0);
+ }
+};
+
+DepositeContent.prototype = {
+ toString: function () {
+ return JSON.stringify(this);
+ }
+};
+
+var BankVaultContract = function () {
+ LocalContractStorage.defineMapProperty(this, "bankVault", {
+ parse: function (text) {
+ return new DepositeContent(text);
+ },
+ stringify: function (o) {
+ return o.toString();
+ }
+ });
+};
+
+// save value to contract, only after height of block, users can takeout
+BankVaultContract.prototype = {
+ init: function () {
+ //TODO:
+ },
+
+ // enables accepting NAS via 'binary'
+ accept: function() {},
+
+ save: function (height) {
+ var from = Blockchain.transaction.from;
+ var value = Blockchain.transaction.value;
+ var bk_height = new BigNumber(Blockchain.block.height);
+
+ var orig_deposit = this.bankVault.get(from);
+ if (orig_deposit) {
+ value = value.plus(orig_deposit.balance);
+ }
+
+ var deposit = new DepositeContent();
+ deposit.balance = value;
+ deposit.expiryHeight = bk_height.plus(height);
+
+ this.bankVault.put(from, deposit);
+ },
+
+ takeout: function (value) {
+ var from = Blockchain.transaction.from;
+ var bk_height = new BigNumber(Blockchain.block.height);
+ var amount = new BigNumber(value);
+
+ var deposit = this.bankVault.get(from);
+ if (!deposit) {
+ throw new Error("No deposit before.");
+ }
+
+ if (bk_height.lt(deposit.expiryHeight)) {
+ throw new Error("Can not takeout before expiryHeight.");
+ }
+
+ if (amount.gt(deposit.balance)) {
+ throw new Error("Insufficient balance.");
+ }
+
+ var result = Blockchain.transfer(from, amount);
+ if (!result) {
+ throw new Error("transfer failed.");
+ }
+ Event.Trigger("BankVault", {
+ Transfer: {
+ from: Blockchain.transaction.to,
+ to: from,
+ value: amount.toString()
+ }
+ });
+
+ deposit.balance = deposit.balance.sub(amount);
+ this.bankVault.put(from, deposit);
+ },
+
+ balanceOf: function () {
+ var from = Blockchain.transaction.from;
+ return this.bankVault.get(from);
+ },
+
+ verifyAddress: function (address) {
+ // 1-valid, 0-invalid
+ var result = Blockchain.verifyAddress(address);
+ return {
+ valid: result == 0 ? false : true
+ };
+ }
+};
+
+module.exports = BankVaultContract;
+
diff --git a/nf/nvm/test/contract_accept_func_with_args.js b/nf/nvm/test/contract_accept_func_with_args.js
new file mode 100644
index 000000000..87dcb602a
--- /dev/null
+++ b/nf/nvm/test/contract_accept_func_with_args.js
@@ -0,0 +1,58 @@
+
+"use strict";
+
+var DepositeContent = function (text) {
+ if (text) {
+ var o = JSON.parse(text);
+ this.balance = new BigNumber(o.balance);
+ this.expiryHeight = new BigNumber(o.expiryHeight);
+ } else {
+ this.balance = new BigNumber(0);
+ this.expiryHeight = new BigNumber(0);
+ }
+};
+
+DepositeContent.prototype = {
+ toString: function () {
+ return JSON.stringify(this);
+ }
+};
+
+var BankVaultContract = function () {
+ LocalContractStorage.defineMapProperty(this, "bankVault", {
+ parse: function (text) {
+ return new DepositeContent(text);
+ },
+ stringify: function (o) {
+ return o.toString();
+ }
+ });
+};
+
+// save value to contract, only after height of block, users can takeout
+BankVaultContract.prototype = {
+ init: function () {
+ //TODO:
+ },
+
+ // enables accepting NAS via 'binary'
+ accept: function (height) {
+ var from = Blockchain.transaction.from;
+ var value = Blockchain.transaction.value;
+ var bk_height = new BigNumber(Blockchain.block.height);
+
+ var orig_deposit = this.bankVault.get(from);
+ if (orig_deposit) {
+ value = value.plus(orig_deposit.balance);
+ }
+
+ var deposit = new DepositeContent();
+ deposit.balance = value;
+ deposit.expiryHeight = bk_height.plus(height);
+
+ this.bankVault.put(from, deposit);
+ }
+};
+
+module.exports = BankVaultContract;
+
diff --git a/nf/nvm/test/contract_accept_func_with_args_2.js b/nf/nvm/test/contract_accept_func_with_args_2.js
new file mode 100644
index 000000000..83c2026c5
--- /dev/null
+++ b/nf/nvm/test/contract_accept_func_with_args_2.js
@@ -0,0 +1,56 @@
+
+"use strict";
+
+var DepositeContent = function (text) {
+ if (text) {
+ var o = JSON.parse(text);
+ this.balance = new BigNumber(o.balance);
+ this.expiryHeight = new BigNumber(o.expiryHeight);
+ } else {
+ this.balance = new BigNumber(0);
+ this.expiryHeight = new BigNumber(0);
+ }
+};
+
+DepositeContent.prototype = {
+ toString: function () {
+ return JSON.stringify(this);
+ }
+};
+
+var BankVaultContract = function () {
+ LocalContractStorage.defineMapProperty(this, "bankVault", {
+ parse: function (text) {
+ return new DepositeContent(text);
+ },
+ stringify: function (o) {
+ return o.toString();
+ }
+ });
+};
+
+// save value to contract, only after height of block, users can takeout
+BankVaultContract.prototype = {
+ init: function () {
+ //TODO:
+ },
+
+ // enables accepting NAS via 'binary'
+ accept: function (height) {
+ var from = Blockchain.transaction.from;
+ var value = Blockchain.transaction.value;
+ var bk_height = new BigNumber(Blockchain.block.height);
+
+ console.log("accept height: " + height);
+
+ return {
+ height: height,
+ from: from,
+ value: value,
+ bk_height: bk_height
+ };
+ }
+};
+
+module.exports = BankVaultContract;
+
diff --git a/nf/nvm/test/contract_date_and_random.js b/nf/nvm/test/contract_date_and_random.js
new file mode 100644
index 000000000..1e2a7c45b
--- /dev/null
+++ b/nf/nvm/test/contract_date_and_random.js
@@ -0,0 +1,79 @@
+"use strict";
+
+var Contract = function() {
+
+};
+
+Contract.prototype = {
+ init: function(){},
+ accept: function(){},
+
+ testDate: function() {
+
+ Event.Trigger("testDate.arguments", {
+ args: arguments
+ });
+
+ var date = arguments.length == 0 ? new Date() : new Date(arguments[0]);
+ var date2 = new Date();
+ date2.setFullYear(1988);
+ var data = {
+ UTC: Date.UTC(),
+ now: Date.now(),
+ parse: Date.parse('04 Dec 1995 00:12:00 GMT'),
+ getUTCDate: date.getUTCDate(),
+ toJSON: date.toJSON(),
+ setFullYear: date2.toString(),
+ height: Blockchain.block.height,
+ timestamp: Blockchain.block.timestamp,
+ valueOf: date.valueOf(),
+ date_toString: date.toString(),
+ date_getTime: date.getTime(),
+ date_getFullYear: date.getFullYear(),
+ equalBlockTime: Blockchain.block.timestamp == (date.getTime() / 1000)
+ };
+ Event.Trigger("Date", {
+ data: data
+ });
+
+ date.setFullYear(2000);
+ Event.Trigger("Date.modi", {
+ data: {
+ valueOf: date.valueOf(),
+ date_toString: date.toString(),
+ date_getTime: date.getTime(),
+ date_getFullYear: date.getFullYear(),
+ equalBlockTime: Blockchain.block.timestamp == (date.getTime() / 1000)
+ }
+ });
+
+ return data;
+ },
+
+ testDate2: function() {
+ var date = new Date();
+
+ Event.Trigger("Date.TZ", {
+ timezone: date.getTimezoneOffset()
+ });
+ },
+
+ testRandom: function(userseed) {
+ var r1 = Math.random();
+ var r12 = Math.random();
+ var r13 = Math.random();
+ // equivalent to reset seed
+ Math.random.seed(userseed);
+ var r2 = Math.random();
+
+ Event.Trigger("random", {
+ "seed": Blockchain.block.seed,
+ "defaultSeedRandom1": r1,
+ "defaultSeedRandom2": r12,
+ "defaultSeedRandom3": r13,
+ "userSeedRandom": r2
+ });
+ }
+};
+
+module.exports = Contract;
\ No newline at end of file
diff --git a/nf/nvm/test/test_date.js b/nf/nvm/test/test_date.js
index 9572371a4..4ed43720c 100644
--- a/nf/nvm/test/test_date.js
+++ b/nf/nvm/test/test_date.js
@@ -16,9 +16,126 @@
// along with the go-nebulas library. If not, see .
//
+Blockchain.blockParse("{\"timestamp\":20000000000,\"seed\":\"\"}");
console.log(Date.now());
console.log(Date.UTC());
+console.log(Date.parse('01 Jan 1970 00:00:00 GMT'));
-var date = new Date();
-console.log(date.getTime());
\ No newline at end of file
+var date = new Date('August 19, 2017 23:15:30');
+var date2 = new Date('August 19, 2017 23:15:30');
+console.log(date.getTime());
+eq(date.getDate(), date.getUTCDate());
+eq(date.getDay(), date.getUTCDay());
+eq(date.getFullYear(), date.getUTCFullYear());
+eq(date.getHours(), date.getUTCHours());
+eq(date.getMilliseconds(), date.getUTCMilliseconds());
+eq(date.getMinutes(), date.getUTCMinutes());
+eq(date.getMonth(), date.getUTCMonth());
+eq(date.getSeconds(), date.getUTCSeconds());
+eq(date.toString(), date.toUTCString());
+
+try {
+ date.getTimezoneOffset();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+try {
+ date.getYear();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Deprecated!") {
+ throw err;
+ }
+}
+try {
+ date.setYear(1999);
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Deprecated!") {
+ throw err;
+ }
+}
+try {
+ date.toDateString();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+try {
+ date.toTimeString();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+
+var tmp = new Date('August 19, 1975 23:15:30 UTC');
+if (tmp.toJSON() !== "1975-08-19T23:15:30.000Z") {
+ throw new Error("toJSON is not equal.")
+}
+try {
+ date.toLocaleDateString();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+try {
+ date.toLocaleTimeString();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+
+try {
+ date.toLocaleString();
+ throw new Error("should not be here.");
+} catch(err) {
+ if (err != "Error: Unsupported method!") {
+ throw err;
+ }
+}
+
+date.setDate(12);
+date2.setUTCDate(12);
+eq(date - date2, 0);
+
+date.setMonth(1);
+date2.setUTCMonth(1);
+eq(date - date2, 0);
+
+date.setFullYear(1999);
+date2.setUTCFullYear(1999);
+eq(date - date2, 0);
+
+date.setHours(22);
+date2.setUTCHours(22);
+eq(date - date2, 0);
+
+date.setMilliseconds(420);
+date2.setUTCMilliseconds(420);
+eq(date - date2, 0);
+
+date.setMinutes(12);
+date2.setUTCMinutes(12);
+eq(date - date2, 0);
+
+date.setSeconds(12);
+date2.setUTCSeconds(12);
+eq(date - date2, 0);
+
+function eq(a, b) {
+ if (a !== b) {
+ throw new Error("Not equal.");
+ }
+}
\ No newline at end of file
diff --git a/nf/nvm/test/test_random_disable.js b/nf/nvm/test/test_random_disable.js
new file mode 100644
index 000000000..c80bf29a0
--- /dev/null
+++ b/nf/nvm/test/test_random_disable.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 go-nebulas
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+Blockchain.blockParse("{}");
+
+console.log(Math.random());
\ No newline at end of file
diff --git a/nf/nvm/test/test_random.js b/nf/nvm/test/test_random_enable.js
similarity index 94%
rename from nf/nvm/test/test_random.js
rename to nf/nvm/test/test_random_enable.js
index 75895f922..890f9eedb 100644
--- a/nf/nvm/test/test_random.js
+++ b/nf/nvm/test/test_random_enable.js
@@ -16,4 +16,6 @@
// along with the go-nebulas library. If not, see .
//
+Blockchain.blockParse("{\"seed\":\"seed\"}");
+
console.log(Math.random());
diff --git a/nf/nvm/test/test_random_seed.js b/nf/nvm/test/test_random_seed.js
new file mode 100644
index 000000000..b07416b3e
--- /dev/null
+++ b/nf/nvm/test/test_random_seed.js
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 go-nebulas
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+Blockchain.blockParse("{\"seed\":\"null\"}");
+console.log(Math.random.seed());
\ No newline at end of file
diff --git a/nf/nvm/types.go b/nf/nvm/types.go
index ead9b4634..5571fe802 100644
--- a/nf/nvm/types.go
+++ b/nf/nvm/types.go
@@ -48,6 +48,7 @@ const (
TransferStringToBigIntErr
TransferSubBalance
TransferAddBalance
+ TransferRecordEventFailed
)
// Block interface breaks cycle import dependency and hides unused services.
@@ -55,6 +56,9 @@ type Block interface {
Hash() byteutils.Hash
Height() uint64 // ToAdd: timestamp interface
Timestamp() int64
+ RandomSeed() string
+ RandomAvailable() bool
+ DateAvailable() bool
}
// Transaction interface breaks cycle import dependency and hides unused services.
@@ -71,6 +75,7 @@ type Transaction interface {
// Account interface breaks cycle import dependency and hides unused services.
type Account interface {
+ Address() byteutils.Hash
Balance() *util.Uint128
Nonce() uint64
AddBalance(value *util.Uint128) error
diff --git a/nf/nvm/v8/lib/blockchain.js b/nf/nvm/v8/lib/blockchain.js
index d515dee86..529d1be22 100644
--- a/nf/nvm/v8/lib/blockchain.js
+++ b/nf/nvm/v8/lib/blockchain.js
@@ -19,7 +19,13 @@
'use strict';
var Blockchain = function () {
- this.nativeBlockchain = _native_blockchain;
+ Object.defineProperty(this, "nativeBlockchain", {
+ configurable: false,
+ enumerable: false,
+ get: function(){
+ return _native_blockchain;
+ }
+ });
};
Blockchain.prototype = {
@@ -29,7 +35,14 @@ Blockchain.prototype = {
blockParse: function (str) {
var block = JSON.parse(str);
if (block != null) {
- this.block = Object.freeze(block);
+ var fb = Object.freeze(block);
+ Object.defineProperty(this, "block", {
+ configurable: false,
+ enumerable: false,
+ get: function(){
+ return fb;
+ }
+ });
}
},
transactionParse: function (str) {
@@ -41,7 +54,15 @@ Blockchain.prototype = {
tx.gasPrice = new BigNumber(gasPrice);
var gasLimit = tx.gasLimit === undefined || tx.gasLimit.length === 0 ? "0" : tx.gasLimit;
tx.gasLimit = new BigNumber(gasLimit);
- this.transaction = Object.freeze(tx);
+
+ var ft = Object.freeze(tx);
+ Object.defineProperty(this, "transaction", {
+ configurable: false,
+ enumerable: false,
+ get: function(){
+ return ft;
+ }
+ });
}
},
transfer: function (address, value) {
@@ -55,5 +76,4 @@ Blockchain.prototype = {
return this.nativeBlockchain.verifyAddress(address);
}
};
-
module.exports = new Blockchain();
diff --git a/nf/nvm/v8/lib/date.js b/nf/nvm/v8/lib/date.js
new file mode 100644
index 000000000..d7ed998cb
--- /dev/null
+++ b/nf/nvm/v8/lib/date.js
@@ -0,0 +1,143 @@
+// Copyright (C) 2018 go-nebulas authors
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+
+var NebDate = (function(ProtoDate) {
+ // compatibility
+ var Date = function() {
+ throw new Error("Date is not allowed in nvm.");
+ }
+
+ function allow() {
+ return Blockchain.block.seed != null && typeof(Blockchain.block.seed) !== 'undefined';
+ }
+
+ function NebDate() {
+ if (!Blockchain) {
+ throw new Error("'Blockchain' is not defined.");
+ }
+ if (!Blockchain.block) {
+ throw new Error("'Blockchain.block' is not defined.");
+ }
+ if (!allow()) {
+ throw new Error("Date is not allowed in nvm.");
+ }
+
+ var date = new(Function.prototype.bind.apply(ProtoDate, [ProtoDate].concat(Array.prototype.slice.call(arguments))))();
+ if (arguments.length == 0) {
+ // unit of timestamp is second
+ date.setTime(Blockchain.block.timestamp * 1000);
+ }
+ Object.setPrototypeOf(date, NebDate.prototype);
+ return date;
+ }
+ NebDate.now = function() {
+ if (!allow()) {
+ Date.now();
+ }
+ return new NebDate().getTime();
+ }
+ NebDate.UTC = function() {
+ if (!allow()) {
+ Date.UTC();
+ }
+ return ProtoDate.UTC.apply(null, arguments);
+ }
+ NebDate.parse = function(dateString) {
+ if (!allow()) {
+ Date.parse(dateString);
+ }
+ return ProtoDate.parse(dateString);
+ }
+
+ NebDate.prototype.getTimezoneOffset = function() {
+ throw new Error("Unsupported method!");
+ }
+ NebDate.prototype.getDate = function() {
+ return this.getUTCDate();
+ }
+ NebDate.prototype.getDay = function() {
+ return this.getUTCDay();
+ }
+ NebDate.prototype.getFullYear = function() {
+ return this.getUTCFullYear();
+ }
+ NebDate.prototype.getHours = function() {
+ return this.getUTCHours();
+ }
+ NebDate.prototype.getMilliseconds = function() {
+ return this.getUTCMilliseconds();
+ }
+ NebDate.prototype.getMinutes = function() {
+ return this.getUTCMinutes();
+ }
+ NebDate.prototype.getMonth = function() {
+ return this.getUTCMonth();
+ }
+ NebDate.prototype.getSeconds = function() {
+ return this.getUTCSeconds();
+ },
+ NebDate.prototype.getYear = function() {
+ throw new Error("Deprecated!");
+ }
+ NebDate.prototype.setYear = function() {
+ throw new Error("Deprecated!");
+ }
+ NebDate.prototype.setDate = function() {
+ return this.setUTCDate.apply(this, arguments);
+ }
+ NebDate.prototype.setFullYear = function() {
+ return this.setUTCFullYear.apply(this, arguments);
+ }
+ NebDate.prototype.setHours = function() {
+ return this.setUTCHours.apply(this, arguments);
+ }
+ NebDate.prototype.setMilliseconds = function() {
+ return this.setUTCMilliseconds.apply(this, arguments);
+ }
+ NebDate.prototype.setMinutes = function() {
+ return this.setUTCMinutes.apply(this, arguments);
+ }
+ NebDate.prototype.setMonth = function() {
+ return this.setUTCMonth.apply(this, arguments);
+ }
+ NebDate.prototype.setSeconds = function() {
+ return this.setUTCSeconds.apply(this, arguments);
+ }
+ NebDate.prototype.toString = function() {
+ // return UTC string
+ return this.toUTCString.apply(this, arguments);
+ }
+ NebDate.prototype.toDateString = function() {
+ throw new Error("Unsupported method!");
+ }
+ NebDate.prototype.toTimeString = function() {
+ throw new Error("Unsupported method!");
+ }
+
+ NebDate.prototype = new Proxy(NebDate.prototype, {
+ getPrototypeOf: function(target) {
+ throw new Error("Unsupported method!");
+ },
+ });
+
+ Object.setPrototypeOf(NebDate.prototype, ProtoDate.prototype);
+ return NebDate;
+})(Date);
+
+module.exports = NebDate;
\ No newline at end of file
diff --git a/nf/nvm/v8/lib/event.js b/nf/nvm/v8/lib/event.js
index 791830999..13bdb68c1 100644
--- a/nf/nvm/v8/lib/event.js
+++ b/nf/nvm/v8/lib/event.js
@@ -20,4 +20,4 @@
exports["Trigger"] = function (topic, data) {
_native_event_trigger(topic, JSON.stringify(data));
-};
+};
\ No newline at end of file
diff --git a/nf/nvm/v8/lib/execution_env.js b/nf/nvm/v8/lib/execution_env.js
index d9fbf5ce5..27a23767c 100644
--- a/nf/nvm/v8/lib/execution_env.js
+++ b/nf/nvm/v8/lib/execution_env.js
@@ -16,13 +16,7 @@
// along with the go-nebulas library. If not, see .
//
-const Date = function () {
- throw new Error("Date is not allowed in nvm.");
-};
-
-Math.random = function () {
- throw new Error("Math.random func is not allowed in nvm.");
-};
+Function.prototype.toString = function(){return "";};
const require = (function (global) {
var PathRegexForNotLibFile = /^\.{0,2}\//;
@@ -116,3 +110,6 @@ const GlobalContractStorage = ContractStorage.gcs;
const BigNumber = require('bignumber.js');
const Blockchain = require('blockchain.js');
const Event = require('event.js');
+
+var Date = require('date.js');
+Math.random = require('random.js');
\ No newline at end of file
diff --git a/nf/nvm/v8/lib/random.js b/nf/nvm/v8/lib/random.js
new file mode 100644
index 000000000..26bb975e1
--- /dev/null
+++ b/nf/nvm/v8/lib/random.js
@@ -0,0 +1,131 @@
+// Copyright (C) 2018 go-nebulas
+//
+// This file is part of the go-nebulas library.
+//
+// the go-nebulas library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// the go-nebulas library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with the go-nebulas library. If not, see .
+//
+
+// A port of an algorithm by Johannes Baagøe , 2010
+// http://baagoe.com/en/RandomMusings/javascript/
+// https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
+// Original work is under MIT license -
+
+// Other seeded random number generators for JavaScript, see https://github.com/davidbau/seedrandom.
+
+
+'use strict';
+
+function Alea(seed) {
+ var me = this, mash = Mash();
+
+ me.next = function () {
+ var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
+ me.s0 = me.s1;
+ me.s1 = me.s2;
+ return me.s2 = t - (me.c = t | 0);
+ };
+
+ // Apply the seeding algorithm from Baagoe.
+ me.c = 1;
+ me.s0 = mash(' ');
+ me.s1 = mash(' ');
+ me.s2 = mash(' ');
+ me.s0 -= mash(seed);
+ if (me.s0 < 0) { me.s0 += 1; }
+ me.s1 -= mash(seed);
+ if (me.s1 < 0) { me.s1 += 1; }
+ me.s2 -= mash(seed);
+ if (me.s2 < 0) { me.s2 += 1; }
+ mash = null;
+}
+
+function copy(f, t) {
+ t.c = f.c;
+ t.s0 = f.s0;
+ t.s1 = f.s1;
+ t.s2 = f.s2;
+ return t;
+}
+
+function impl(seed, opts) {
+ var xg = new Alea(seed),
+ state = opts && opts.state,
+ prng = xg.next;
+ prng.int32 = function () { return (xg.next() * 0x100000000) | 0; }
+ prng.double = function () {
+ return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
+ };
+ prng.quick = prng;
+ if (state) {
+ if (typeof (state) == 'object') copy(state, xg);
+ prng.state = function () { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+function Mash() {
+ var n = 0xefc8249d;
+
+ var mash = function (data) {
+ data = data.toString();
+ for (var i = 0; i < data.length; i++) {
+ n += data.charCodeAt(i);
+ var h = 0.02519603282416938 * n;
+ n = h >>> 0;
+ h -= n;
+ h *= n;
+ n = h >>> 0;
+ h -= n;
+ n += h * 0x100000000; // 2^32
+ }
+ return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
+ };
+
+ return mash;
+}
+
+module.exports = (function(){
+
+ var arng = null;
+
+ function checkCtx() {
+ if (!Blockchain) {
+ throw new Error("'Blockchain' is undefined.");
+ }
+ if (!Blockchain.block) {
+ throw new Error("'Blockchain.block' is undefined.");
+ }
+
+ if (Blockchain.block.seed == null || typeof(Blockchain.block.seed) === 'undefined') {
+ throw new Error("Math.random func is not allowed in nvm.");
+ }
+ }
+
+ function rand() {
+ if (arng == null) {
+ checkCtx();
+ arng = new impl(Blockchain.block.seed);
+ }
+ return arng();
+ }
+ rand.seed = function(userseed) {
+ if (typeof(userseed) !== 'string') {
+ throw new Error("input seed must be a string")
+ }
+ checkCtx();
+ arng = new impl(Blockchain.block.seed + userseed);
+ }
+
+ return rand;
+})();
\ No newline at end of file
diff --git a/nf/nvm/v8/lib/storage.js b/nf/nvm/v8/lib/storage.js
index c0f57ce7f..f4f7deaa4 100644
--- a/nf/nvm/v8/lib/storage.js
+++ b/nf/nvm/v8/lib/storage.js
@@ -79,7 +79,14 @@ var applyFieldDescriptor = function (obj, fieldName, descriptor) {
};
var ContractStorage = function (handler) {
- this.nativeStorage = new NativeStorage(handler);
+ var ns = new NativeStorage(handler);
+ Object.defineProperty(this, "nativeStorage", {
+ configurable: false,
+ enumerable: false,
+ get: function () {
+ return ns;
+ }
+ });
};
var StorageMap = function (contractStorage, fieldName, descriptor) {
@@ -221,8 +228,23 @@ ContractStorage.prototype = {
ContractStorage.prototype.put = ContractStorage.prototype.set;
ContractStorage.prototype.delete = ContractStorage.prototype.del;
-module.exports = Object.freeze({
- ContractStorage: ContractStorage,
- lcs: new ContractStorage(_native_storage_handlers.lcs),
- gcs: new ContractStorage(_native_storage_handlers.gcs)
+var lcs = new ContractStorage(_native_storage_handlers.lcs);
+var gcs = new ContractStorage(_native_storage_handlers.gcs);
+var obj = {ContractStorage: ContractStorage};
+Object.defineProperty(obj, "lcs", {
+ configurable: false,
+ enumerable: false,
+ get: function () {
+ return lcs;
+ }
});
+
+Object.defineProperty(obj, "gcs", {
+ configurable: false,
+ enumerable: false,
+ get: function () {
+ return gcs;
+ }
+});
+
+module.exports = Object.freeze(obj);
\ No newline at end of file
diff --git a/rpc/admin_service.go b/rpc/admin_service.go
index e97f13154..20d7ef6aa 100644
--- a/rpc/admin_service.go
+++ b/rpc/admin_service.go
@@ -136,6 +136,30 @@ func (s *AdminService) SignHash(ctx context.Context, req *rpcpb.SignHashRequest)
return &rpcpb.SignHashResponse{Data: data}, nil
}
+// GenerateRandomSeed generate block's rand info
+func (s *AdminService) GenerateRandomSeed(ctx context.Context, req *rpcpb.GenerateRandomSeedRequest) (*rpcpb.GenerateRandomSeedResponse, error) {
+ neb := s.server.Neblet()
+ inputs, err := neb.BlockChain().GetInputForVRFSigner(req.ParentHash, req.Height)
+ if err != nil {
+ return nil, err
+ }
+
+ addr, err := core.AddressParse(req.Address)
+ if err != nil {
+ return nil, err
+ }
+
+ vrfSeed, vrfProof, err := neb.AccountManager().GenerateRandomSeed(addr, inputs...)
+ if err != nil {
+ return nil, err
+ }
+
+ return &rpcpb.GenerateRandomSeedResponse{
+ VrfSeed: vrfSeed,
+ VrfProof: vrfProof,
+ }, nil
+}
+
// SignTransactionWithPassphrase sign transaction with the from addr passphrase
func (s *AdminService) SignTransactionWithPassphrase(ctx context.Context, req *rpcpb.SignTransactionPassphraseRequest) (*rpcpb.SignTransactionPassphraseResponse, error) {
diff --git a/rpc/api_service.go b/rpc/api_service.go
index 23631a782..e29e1464f 100644
--- a/rpc/api_service.go
+++ b/rpc/api_service.go
@@ -141,46 +141,94 @@ func parseTransaction(neb core.Neblet, reqTx *rpcpb.TransactionRequest) (*core.T
if err != nil {
return nil, errors.New("invalid gasLimit")
}
- var (
- payloadType string
- payload []byte
- )
- if reqTx.Contract != nil {
- if len(reqTx.Contract.Source) > 0 && len(reqTx.Contract.Function) == 0 { // TODO: reqTx.DeployContract, reqTx.CallContract
- payloadType = core.TxPayloadDeployType
- payloadObj, err := core.NewDeployPayload(reqTx.Contract.Source, reqTx.Contract.SourceType, reqTx.Contract.Args)
- if err != nil {
- return nil, err
+ payloadType, payload, err := parseTransactionPayload(reqTx)
+ if err != nil {
+ return nil, err
+ }
+
+ tx, err := core.NewTransaction(neb.BlockChain().ChainID(), fromAddr, toAddr, value, reqTx.Nonce, payloadType, payload, gasPrice, gasLimit)
+ if err != nil {
+ return nil, err
+ }
+ return tx, nil
+}
+
+func parseTransactionPayload(reqTx *rpcpb.TransactionRequest) (payloadType string, payload []byte, err error) {
+ if len(reqTx.Type) > 0 {
+ switch reqTx.Type {
+ case core.TxPayloadBinaryType:
+ {
+ if payload, err = core.NewBinaryPayload(reqTx.Binary).ToBytes(); err != nil {
+ return "", nil, err
+ }
}
- if payload, err = payloadObj.ToBytes(); err != nil {
- return nil, err
+ case core.TxPayloadDeployType:
+ {
+ if reqTx.Contract == nil {
+ return "", nil, core.ErrInvalidDeploySource
+ }
+ deployPayload, err := core.NewDeployPayload(reqTx.Contract.Source, reqTx.Contract.SourceType, reqTx.Contract.Args)
+ if err != nil {
+ return "", nil, err
+ }
+ if payload, err = deployPayload.ToBytes(); err != nil {
+ return "", nil, err
+ }
}
- } else if len(reqTx.Contract.Source) == 0 && len(reqTx.Contract.Function) > 0 {
- payloadType = core.TxPayloadCallType
- callpayload, err := core.NewCallPayload(reqTx.Contract.Function, reqTx.Contract.Args)
+ case core.TxPayloadCallType:
+ {
+ if reqTx.Contract == nil {
+ return "", nil, core.ErrInvalidCallFunction
+ }
+ callpayload, err := core.NewCallPayload(reqTx.Contract.Function, reqTx.Contract.Args)
+ if err != nil {
+ return "", nil, err
+ }
+
+ if payload, err = callpayload.ToBytes(); err != nil {
+ return "", nil, err
+ }
+ }
+ default:
+ return "", nil, core.ErrInvalidTxPayloadType
+ }
+ } else {
+ if reqTx.Contract != nil {
+ toAddr, err := core.AddressParse(reqTx.To)
if err != nil {
- return nil, err
+ return "", nil, err
}
-
- if payload, err = callpayload.ToBytes(); err != nil {
- return nil, err
+ if len(reqTx.Contract.Source) > 0 && len(reqTx.Contract.Function) == 0 && reqTx.From == reqTx.To {
+ payloadType = core.TxPayloadDeployType
+ payloadObj, err := core.NewDeployPayload(reqTx.Contract.Source, reqTx.Contract.SourceType, reqTx.Contract.Args)
+ if err != nil {
+ return "", nil, err
+ }
+ if payload, err = payloadObj.ToBytes(); err != nil {
+ return "", nil, err
+ }
+ } else if len(reqTx.Contract.Source) == 0 && len(reqTx.Contract.Function) > 0 && toAddr.Type() == core.ContractAddress {
+ payloadType = core.TxPayloadCallType
+ callpayload, err := core.NewCallPayload(reqTx.Contract.Function, reqTx.Contract.Args)
+ if err != nil {
+ return "", nil, err
+ }
+
+ if payload, err = callpayload.ToBytes(); err != nil {
+ return "", nil, err
+ }
+ } else {
+ return "", nil, errors.New("invalid contract")
}
} else {
- return nil, errors.New("invalid contract")
- }
- } else {
- payloadType = core.TxPayloadBinaryType
- if payload, err = core.NewBinaryPayload(reqTx.Binary).ToBytes(); err != nil {
- return nil, err
+ payloadType = core.TxPayloadBinaryType
+ if payload, err = core.NewBinaryPayload(reqTx.Binary).ToBytes(); err != nil {
+ return "", nil, err
+ }
}
}
-
- tx, err := core.NewTransaction(neb.BlockChain().ChainID(), fromAddr, toAddr, value, reqTx.Nonce, payloadType, payload, gasPrice, gasLimit)
- if err != nil {
- return nil, err
- }
- return tx, nil
+ return payloadType, payload, nil
}
func handleTransactionResponse(neb core.Neblet, tx *core.Transaction) (resp *rpcpb.SendTransactionResponse, err error) {
@@ -192,11 +240,6 @@ func handleTransactionResponse(neb core.Neblet, tx *core.Transaction) (resp *rpc
}
}()
- err = tx.VerifyIntegrity(neb.BlockChain().ChainID())
- if err != nil {
- return nil, err
- }
-
tailBlock := neb.BlockChain().TailBlock()
acc, err := tailBlock.GetAccount(tx.From().Bytes())
if err != nil {
@@ -207,6 +250,18 @@ func handleTransactionResponse(neb core.Neblet, tx *core.Transaction) (resp *rpc
return nil, errors.New("transaction's nonce is invalid, should bigger than the from's nonce")
}
+ // check Balance Simulate
+ if tx.Nonce() == (acc.Nonce() + 1) {
+ result, err := neb.BlockChain().SimulateTransactionExecution(tx)
+ if err != nil {
+ return nil, err
+ }
+
+ if result.Err != nil {
+ return nil, result.Err
+ }
+ }
+
if tx.Type() == core.TxPayloadDeployType {
if !tx.From().Equals(tx.To()) {
return nil, core.ErrContractTransactionAddressNotEqual
@@ -355,8 +410,10 @@ func (s *APIService) GetTransactionReceipt(ctx context.Context, req *rpcpb.GetTr
func (s *APIService) toTransactionResponse(tx *core.Transaction) (*rpcpb.TransactionResponse, error) {
var (
- status int32
- gasUsed string
+ status int32
+ gasUsed string
+ execute_error string
+ execute_result string
)
neb := s.server.Neblet()
event, err := neb.BlockChain().TailBlock().FetchExecutionResultEvent(tx.Hash())
@@ -365,31 +422,48 @@ func (s *APIService) toTransactionResponse(tx *core.Transaction) (*rpcpb.Transac
}
if event != nil {
- txEvent := core.TransactionEvent{}
- err := json.Unmarshal([]byte(event.Data), &txEvent)
- if err != nil {
- return nil, err
+ h := neb.BlockChain().TailBlock().Height()
+ if h >= core.RecordCallContractResultHeight {
+ txEvent2 := core.TransactionEventV2{}
+
+ err := json.Unmarshal([]byte(event.Data), &txEvent2)
+ if err != nil {
+ return nil, err
+ }
+ status = int32(txEvent2.Status)
+ gasUsed = txEvent2.GasUsed
+ execute_error = txEvent2.Error
+ execute_result = txEvent2.ExecuteResult
+ } else {
+ txEvent := core.TransactionEvent{}
+ err := json.Unmarshal([]byte(event.Data), &txEvent)
+ if err != nil {
+ return nil, err
+ }
+ status = int32(txEvent.Status)
+ gasUsed = txEvent.GasUsed
+ execute_error = txEvent.Error
}
- status = int32(txEvent.Status)
- gasUsed = txEvent.GasUsed
} else {
status = core.TxExecutionPendding
}
resp := &rpcpb.TransactionResponse{
- ChainId: tx.ChainID(),
- Hash: tx.Hash().String(),
- From: tx.From().String(),
- To: tx.To().String(),
- Value: tx.Value().String(),
- Nonce: tx.Nonce(),
- Timestamp: tx.Timestamp(),
- Type: tx.Type(),
- Data: tx.Data(),
- GasPrice: tx.GasPrice().String(),
- GasLimit: tx.GasLimit().String(),
- Status: status,
- GasUsed: gasUsed,
+ ChainId: tx.ChainID(),
+ Hash: tx.Hash().String(),
+ From: tx.From().String(),
+ To: tx.To().String(),
+ Value: tx.Value().String(),
+ Nonce: tx.Nonce(),
+ Timestamp: tx.Timestamp(),
+ Type: tx.Type(),
+ Data: tx.Data(),
+ GasPrice: tx.GasPrice().String(),
+ GasLimit: tx.GasLimit().String(),
+ Status: status,
+ GasUsed: gasUsed,
+ ExecuteError: execute_error,
+ ExecuteResult: execute_result,
}
if tx.Type() == core.TxPayloadDeployType {
diff --git a/rpc/pb/rpc.pb.go b/rpc/pb/rpc.pb.go
index ed29b0d89..7f1464351 100644
--- a/rpc/pb/rpc.pb.go
+++ b/rpc/pb/rpc.pb.go
@@ -37,6 +37,8 @@ It has these top-level messages:
LockAccountResponse
SignHashRequest
SignHashResponse
+ GenerateRandomSeedRequest
+ GenerateRandomSeedResponse
SignTransactionPassphraseRequest
SignTransactionPassphraseResponse
SendTransactionPassphraseRequest
@@ -58,10 +60,8 @@ import _ "google.golang.org/genproto/googleapis/api/annotations"
import consensuspb "github.com/nebulasio/go-nebulas/consensus/pb"
import nebletpb "github.com/nebulasio/go-nebulas/neblet/pb"
-import (
- context "golang.org/x/net/context"
- grpc "google.golang.org/grpc"
-)
+import context "golang.org/x/net/context"
+import grpc "google.golang.org/grpc"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -470,6 +470,8 @@ type TransactionRequest struct {
Contract *ContractRequest `protobuf:"bytes,7,opt,name=contract" json:"contract,omitempty"`
// binary data for transaction
Binary []byte `protobuf:"bytes,10,opt,name=binary,proto3" json:"binary,omitempty"`
+ // transaction payload type, enum:binary, deploy, call
+ Type string `protobuf:"bytes,20,opt,name=type,proto3" json:"type,omitempty"`
}
func (m *TransactionRequest) Reset() { *m = TransactionRequest{} }
@@ -533,6 +535,13 @@ func (m *TransactionRequest) GetBinary() []byte {
return nil
}
+func (m *TransactionRequest) GetType() string {
+ if m != nil {
+ return m.Type
+ }
+ return ""
+}
+
type ContractRequest struct {
// contract source code.
Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"`
@@ -851,6 +860,10 @@ type TransactionResponse struct {
Status int32 `protobuf:"varint,13,opt,name=status,proto3" json:"status,omitempty"`
// transaction gas used
GasUsed string `protobuf:"bytes,14,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
+ // contract execute error
+ ExecuteError string `protobuf:"bytes,15,opt,name=execute_error,json=executeError,proto3" json:"execute_error,omitempty"`
+ // contract execute result
+ ExecuteResult string `protobuf:"bytes,16,opt,name=execute_result,json=executeResult,proto3" json:"execute_result,omitempty"`
}
func (m *TransactionResponse) Reset() { *m = TransactionResponse{} }
@@ -956,6 +969,20 @@ func (m *TransactionResponse) GetGasUsed() string {
return ""
}
+func (m *TransactionResponse) GetExecuteError() string {
+ if m != nil {
+ return m.ExecuteError
+ }
+ return ""
+}
+
+func (m *TransactionResponse) GetExecuteResult() string {
+ if m != nil {
+ return m.ExecuteResult
+ }
+ return ""
+}
+
type NewAccountRequest struct {
Passphrase string `protobuf:"bytes,1,opt,name=passphrase,proto3" json:"passphrase,omitempty"`
}
@@ -1119,6 +1146,65 @@ func (m *SignHashResponse) GetData() []byte {
return nil
}
+type GenerateRandomSeedRequest struct {
+ // miner address
+ Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+ // parent hash of new block
+ ParentHash []byte `protobuf:"bytes,2,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"`
+ // height of new block
+ Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
+}
+
+func (m *GenerateRandomSeedRequest) Reset() { *m = GenerateRandomSeedRequest{} }
+func (m *GenerateRandomSeedRequest) String() string { return proto.CompactTextString(m) }
+func (*GenerateRandomSeedRequest) ProtoMessage() {}
+func (*GenerateRandomSeedRequest) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{29} }
+
+func (m *GenerateRandomSeedRequest) GetAddress() string {
+ if m != nil {
+ return m.Address
+ }
+ return ""
+}
+
+func (m *GenerateRandomSeedRequest) GetParentHash() []byte {
+ if m != nil {
+ return m.ParentHash
+ }
+ return nil
+}
+
+func (m *GenerateRandomSeedRequest) GetHeight() uint64 {
+ if m != nil {
+ return m.Height
+ }
+ return 0
+}
+
+type GenerateRandomSeedResponse struct {
+ VrfSeed []byte `protobuf:"bytes,1,opt,name=vrf_seed,json=vrfSeed,proto3" json:"vrf_seed,omitempty"`
+ VrfProof []byte `protobuf:"bytes,2,opt,name=vrf_proof,json=vrfProof,proto3" json:"vrf_proof,omitempty"`
+}
+
+func (m *GenerateRandomSeedResponse) Reset() { *m = GenerateRandomSeedResponse{} }
+func (m *GenerateRandomSeedResponse) String() string { return proto.CompactTextString(m) }
+func (*GenerateRandomSeedResponse) ProtoMessage() {}
+func (*GenerateRandomSeedResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{30} }
+
+func (m *GenerateRandomSeedResponse) GetVrfSeed() []byte {
+ if m != nil {
+ return m.VrfSeed
+ }
+ return nil
+}
+
+func (m *GenerateRandomSeedResponse) GetVrfProof() []byte {
+ if m != nil {
+ return m.VrfProof
+ }
+ return nil
+}
+
type SignTransactionPassphraseRequest struct {
// transaction struct
Transaction *TransactionRequest `protobuf:"bytes,1,opt,name=transaction" json:"transaction,omitempty"`
@@ -1130,7 +1216,7 @@ func (m *SignTransactionPassphraseRequest) Reset() { *m = SignTransactio
func (m *SignTransactionPassphraseRequest) String() string { return proto.CompactTextString(m) }
func (*SignTransactionPassphraseRequest) ProtoMessage() {}
func (*SignTransactionPassphraseRequest) Descriptor() ([]byte, []int) {
- return fileDescriptorRpc, []int{29}
+ return fileDescriptorRpc, []int{31}
}
func (m *SignTransactionPassphraseRequest) GetTransaction() *TransactionRequest {
@@ -1155,7 +1241,7 @@ func (m *SignTransactionPassphraseResponse) Reset() { *m = SignTransacti
func (m *SignTransactionPassphraseResponse) String() string { return proto.CompactTextString(m) }
func (*SignTransactionPassphraseResponse) ProtoMessage() {}
func (*SignTransactionPassphraseResponse) Descriptor() ([]byte, []int) {
- return fileDescriptorRpc, []int{30}
+ return fileDescriptorRpc, []int{32}
}
func (m *SignTransactionPassphraseResponse) GetData() []byte {
@@ -1176,7 +1262,7 @@ func (m *SendTransactionPassphraseRequest) Reset() { *m = SendTransactio
func (m *SendTransactionPassphraseRequest) String() string { return proto.CompactTextString(m) }
func (*SendTransactionPassphraseRequest) ProtoMessage() {}
func (*SendTransactionPassphraseRequest) Descriptor() ([]byte, []int) {
- return fileDescriptorRpc, []int{31}
+ return fileDescriptorRpc, []int{33}
}
func (m *SendTransactionPassphraseRequest) GetTransaction() *TransactionRequest {
@@ -1200,7 +1286,7 @@ type GasPriceResponse struct {
func (m *GasPriceResponse) Reset() { *m = GasPriceResponse{} }
func (m *GasPriceResponse) String() string { return proto.CompactTextString(m) }
func (*GasPriceResponse) ProtoMessage() {}
-func (*GasPriceResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{32} }
+func (*GasPriceResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{34} }
func (m *GasPriceResponse) GetGasPrice() string {
if m != nil {
@@ -1218,7 +1304,7 @@ type HashRequest struct {
func (m *HashRequest) Reset() { *m = HashRequest{} }
func (m *HashRequest) String() string { return proto.CompactTextString(m) }
func (*HashRequest) ProtoMessage() {}
-func (*HashRequest) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{33} }
+func (*HashRequest) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{35} }
func (m *HashRequest) GetHash() string {
if m != nil {
@@ -1235,7 +1321,7 @@ type GasResponse struct {
func (m *GasResponse) Reset() { *m = GasResponse{} }
func (m *GasResponse) String() string { return proto.CompactTextString(m) }
func (*GasResponse) ProtoMessage() {}
-func (*GasResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{34} }
+func (*GasResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{36} }
func (m *GasResponse) GetGas() string {
if m != nil {
@@ -1258,7 +1344,7 @@ type EventsResponse struct {
func (m *EventsResponse) Reset() { *m = EventsResponse{} }
func (m *EventsResponse) String() string { return proto.CompactTextString(m) }
func (*EventsResponse) ProtoMessage() {}
-func (*EventsResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{35} }
+func (*EventsResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{37} }
func (m *EventsResponse) GetEvents() []*Event {
if m != nil {
@@ -1275,7 +1361,7 @@ type Event struct {
func (m *Event) Reset() { *m = Event{} }
func (m *Event) String() string { return proto.CompactTextString(m) }
func (*Event) ProtoMessage() {}
-func (*Event) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{36} }
+func (*Event) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{38} }
func (m *Event) GetTopic() string {
if m != nil {
@@ -1298,7 +1384,7 @@ type PprofRequest struct {
func (m *PprofRequest) Reset() { *m = PprofRequest{} }
func (m *PprofRequest) String() string { return proto.CompactTextString(m) }
func (*PprofRequest) ProtoMessage() {}
-func (*PprofRequest) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{37} }
+func (*PprofRequest) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{39} }
func (m *PprofRequest) GetListen() string {
if m != nil {
@@ -1314,7 +1400,7 @@ type PprofResponse struct {
func (m *PprofResponse) Reset() { *m = PprofResponse{} }
func (m *PprofResponse) String() string { return proto.CompactTextString(m) }
func (*PprofResponse) ProtoMessage() {}
-func (*PprofResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{38} }
+func (*PprofResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{40} }
func (m *PprofResponse) GetResult() bool {
if m != nil {
@@ -1331,7 +1417,7 @@ type GetConfigResponse struct {
func (m *GetConfigResponse) Reset() { *m = GetConfigResponse{} }
func (m *GetConfigResponse) String() string { return proto.CompactTextString(m) }
func (*GetConfigResponse) ProtoMessage() {}
-func (*GetConfigResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{39} }
+func (*GetConfigResponse) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{41} }
func (m *GetConfigResponse) GetConfig() *nebletpb.Config {
if m != nil {
@@ -1370,6 +1456,8 @@ func init() {
proto.RegisterType((*LockAccountResponse)(nil), "rpcpb.LockAccountResponse")
proto.RegisterType((*SignHashRequest)(nil), "rpcpb.SignHashRequest")
proto.RegisterType((*SignHashResponse)(nil), "rpcpb.SignHashResponse")
+ proto.RegisterType((*GenerateRandomSeedRequest)(nil), "rpcpb.GenerateRandomSeedRequest")
+ proto.RegisterType((*GenerateRandomSeedResponse)(nil), "rpcpb.GenerateRandomSeedResponse")
proto.RegisterType((*SignTransactionPassphraseRequest)(nil), "rpcpb.SignTransactionPassphraseRequest")
proto.RegisterType((*SignTransactionPassphraseResponse)(nil), "rpcpb.SignTransactionPassphraseResponse")
proto.RegisterType((*SendTransactionPassphraseRequest)(nil), "rpcpb.SendTransactionPassphraseRequest")
@@ -1916,6 +2004,7 @@ type AdminServiceClient interface {
SendTransaction(ctx context.Context, in *TransactionRequest, opts ...grpc.CallOption) (*SendTransactionResponse, error)
// Sign sign msg
SignHash(ctx context.Context, in *SignHashRequest, opts ...grpc.CallOption) (*SignHashResponse, error)
+ GenerateRandomSeed(ctx context.Context, in *GenerateRandomSeedRequest, opts ...grpc.CallOption) (*GenerateRandomSeedResponse, error)
// Sign sign transaction
SignTransactionWithPassphrase(ctx context.Context, in *SignTransactionPassphraseRequest, opts ...grpc.CallOption) (*SignTransactionPassphraseResponse, error)
// SendTransactionWithPassphrase send transaction with passphrase
@@ -1989,6 +2078,15 @@ func (c *adminServiceClient) SignHash(ctx context.Context, in *SignHashRequest,
return out, nil
}
+func (c *adminServiceClient) GenerateRandomSeed(ctx context.Context, in *GenerateRandomSeedRequest, opts ...grpc.CallOption) (*GenerateRandomSeedResponse, error) {
+ out := new(GenerateRandomSeedResponse)
+ err := grpc.Invoke(ctx, "/rpcpb.AdminService/GenerateRandomSeed", in, out, c.cc, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
func (c *adminServiceClient) SignTransactionWithPassphrase(ctx context.Context, in *SignTransactionPassphraseRequest, opts ...grpc.CallOption) (*SignTransactionPassphraseResponse, error) {
out := new(SignTransactionPassphraseResponse)
err := grpc.Invoke(ctx, "/rpcpb.AdminService/SignTransactionWithPassphrase", in, out, c.cc, opts...)
@@ -2049,6 +2147,7 @@ type AdminServiceServer interface {
SendTransaction(context.Context, *TransactionRequest) (*SendTransactionResponse, error)
// Sign sign msg
SignHash(context.Context, *SignHashRequest) (*SignHashResponse, error)
+ GenerateRandomSeed(context.Context, *GenerateRandomSeedRequest) (*GenerateRandomSeedResponse, error)
// Sign sign transaction
SignTransactionWithPassphrase(context.Context, *SignTransactionPassphraseRequest) (*SignTransactionPassphraseResponse, error)
// SendTransactionWithPassphrase send transaction with passphrase
@@ -2172,6 +2271,24 @@ func _AdminService_SignHash_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
+func _AdminService_GenerateRandomSeed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GenerateRandomSeedRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AdminServiceServer).GenerateRandomSeed(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/rpcpb.AdminService/GenerateRandomSeed",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AdminServiceServer).GenerateRandomSeed(ctx, req.(*GenerateRandomSeedRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
func _AdminService_SignTransactionWithPassphrase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SignTransactionPassphraseRequest)
if err := dec(in); err != nil {
@@ -2290,6 +2407,10 @@ var _AdminService_serviceDesc = grpc.ServiceDesc{
MethodName: "SignHash",
Handler: _AdminService_SignHash_Handler,
},
+ {
+ MethodName: "GenerateRandomSeed",
+ Handler: _AdminService_GenerateRandomSeed_Handler,
+ },
{
MethodName: "SignTransactionWithPassphrase",
Handler: _AdminService_SignTransactionWithPassphrase_Handler,
@@ -2318,142 +2439,150 @@ var _AdminService_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("rpc.proto", fileDescriptorRpc) }
var fileDescriptorRpc = []byte{
- // 2190 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x4b, 0x6f, 0x1b, 0xc9,
- 0x11, 0x06, 0x49, 0x3d, 0xc8, 0x22, 0x25, 0xd1, 0xad, 0xd7, 0x88, 0x96, 0x64, 0xb9, 0xbd, 0xd8,
- 0xd5, 0x1a, 0x59, 0x71, 0xad, 0x05, 0x9c, 0xc0, 0xc1, 0x06, 0xb0, 0x1d, 0xaf, 0xd6, 0x81, 0x61,
- 0x38, 0x23, 0x6f, 0xb2, 0x40, 0xe2, 0x10, 0xcd, 0x61, 0x8b, 0xec, 0xec, 0x68, 0x66, 0x32, 0xdd,
- 0xb4, 0x2d, 0x5d, 0x02, 0xec, 0x3d, 0xa7, 0x5c, 0x72, 0xc8, 0x3f, 0xc8, 0xaf, 0x09, 0x72, 0xc8,
- 0x25, 0xc7, 0x9c, 0x72, 0xcb, 0x3f, 0x08, 0xba, 0xa6, 0x7b, 0x5e, 0x1c, 0x8a, 0x71, 0x0e, 0xb9,
- 0x4d, 0x55, 0x77, 0x57, 0x55, 0xd7, 0xe3, 0xab, 0x6a, 0x12, 0x5a, 0x71, 0xe4, 0x9d, 0x44, 0x71,
- 0xa8, 0x42, 0xb2, 0x1c, 0x47, 0x5e, 0x34, 0xec, 0xed, 0x8f, 0xc3, 0x70, 0xec, 0xf3, 0x3e, 0x8b,
- 0x44, 0x9f, 0x05, 0x41, 0xa8, 0x98, 0x12, 0x61, 0x20, 0x93, 0x4d, 0xbd, 0x1f, 0x8d, 0x85, 0x9a,
- 0x4c, 0x87, 0x27, 0x5e, 0x78, 0xd9, 0x0f, 0xf8, 0x70, 0xea, 0x33, 0x29, 0xc2, 0xfe, 0x38, 0xfc,
- 0xcc, 0x10, 0x7d, 0x2f, 0x0c, 0x24, 0x0f, 0xe4, 0x54, 0xf6, 0xa3, 0x61, 0x5f, 0x2a, 0xa6, 0xb8,
- 0x39, 0xf9, 0x70, 0xd1, 0xc9, 0x80, 0x0f, 0x7d, 0xae, 0xf4, 0x31, 0x2f, 0x0c, 0x2e, 0xc4, 0x38,
- 0x39, 0x47, 0xef, 0x43, 0xf7, 0x7c, 0x3a, 0x94, 0x5e, 0x2c, 0x86, 0xdc, 0xe5, 0xbf, 0x9b, 0x72,
- 0xa9, 0xc8, 0x0e, 0xac, 0xa8, 0x30, 0x12, 0x9e, 0x74, 0x6a, 0x47, 0x8d, 0xe3, 0x96, 0x6b, 0x28,
- 0xfa, 0x25, 0xdc, 0xca, 0xed, 0x95, 0x91, 0xb6, 0x85, 0x6c, 0xc1, 0x32, 0x2e, 0x3b, 0xb5, 0xa3,
- 0xda, 0x71, 0xcb, 0x4d, 0x08, 0x42, 0x60, 0x69, 0xc4, 0x14, 0x73, 0xea, 0xc8, 0xc4, 0x6f, 0x4a,
- 0xa0, 0xfb, 0x32, 0x0c, 0x5e, 0xb1, 0x98, 0x5d, 0x4a, 0xa3, 0x8a, 0xfe, 0xb9, 0xae, 0x99, 0x23,
- 0xfe, 0x3c, 0xb8, 0x08, 0x53, 0x91, 0xeb, 0x50, 0x17, 0x23, 0x23, 0xaf, 0x2e, 0x46, 0x64, 0x0f,
- 0x9a, 0xde, 0x84, 0x89, 0x60, 0x20, 0x46, 0x28, 0x70, 0xcd, 0x5d, 0x45, 0xfa, 0xf9, 0x88, 0xf4,
- 0xa0, 0xe9, 0x85, 0x22, 0x18, 0x32, 0xc9, 0x9d, 0x06, 0x1e, 0x48, 0x69, 0x72, 0x00, 0x10, 0x71,
- 0x1e, 0x0f, 0xbc, 0x70, 0x1a, 0x28, 0x67, 0x09, 0x0f, 0xb6, 0x34, 0xe7, 0xa9, 0x66, 0x10, 0x0a,
- 0x1d, 0x79, 0x15, 0x78, 0x93, 0x38, 0x0c, 0xc4, 0x35, 0x1f, 0x39, 0xcb, 0x47, 0xb5, 0xe3, 0xa6,
- 0x5b, 0xe0, 0x91, 0x3b, 0xd0, 0x1e, 0x4e, 0xbd, 0xef, 0xb8, 0x1a, 0x48, 0x71, 0xcd, 0x9d, 0x95,
- 0xa3, 0xda, 0xf1, 0xb2, 0x0b, 0x09, 0xeb, 0x5c, 0x5c, 0x73, 0xf2, 0x29, 0x74, 0xd1, 0x8f, 0x5e,
- 0xe8, 0x0f, 0xde, 0xf2, 0x58, 0x8a, 0x30, 0x70, 0x00, 0xed, 0xd8, 0xb0, 0xfc, 0x5f, 0x24, 0x6c,
- 0x72, 0x0a, 0xed, 0x38, 0x9c, 0x2a, 0x3e, 0x50, 0x6c, 0xe8, 0x73, 0xa7, 0x7d, 0xd4, 0x38, 0x6e,
- 0x9f, 0xde, 0x3a, 0xc1, 0xb4, 0x38, 0x71, 0xf5, 0xca, 0x6b, 0xbd, 0xe0, 0x42, 0x9c, 0x7e, 0xd3,
- 0x87, 0x00, 0xd9, 0xca, 0x8c, 0x5f, 0x1c, 0x58, 0x65, 0xa3, 0x51, 0xcc, 0xa5, 0x74, 0xea, 0x18,
- 0x28, 0x4b, 0xd2, 0xbf, 0xd7, 0x60, 0xf3, 0x8c, 0xab, 0x97, 0x7c, 0x78, 0xae, 0x73, 0x24, 0xf5,
- 0x6c, 0xde, 0x93, 0xb5, 0xa2, 0x27, 0x09, 0x2c, 0x29, 0x26, 0x7c, 0x1b, 0x31, 0xfd, 0x4d, 0xba,
- 0xd0, 0xf0, 0xc5, 0xd0, 0x38, 0x56, 0x7f, 0xea, 0xd4, 0x98, 0x70, 0x31, 0x9e, 0x24, 0xfe, 0x5c,
- 0x72, 0x0d, 0x55, 0xe9, 0x87, 0x95, 0x6a, 0x3f, 0x94, 0xfd, 0xbe, 0x5a, 0xe1, 0x77, 0x07, 0x56,
- 0xad, 0x94, 0x26, 0x4a, 0xb1, 0x24, 0xfd, 0x1c, 0xba, 0x8f, 0x3d, 0x8c, 0xa8, 0x4c, 0x6f, 0xb5,
- 0x0f, 0x2d, 0x73, 0x71, 0x6e, 0x53, 0x36, 0x63, 0xd0, 0x9f, 0xc1, 0xce, 0x19, 0x57, 0xe6, 0x90,
- 0x71, 0x47, 0x92, 0xe7, 0x39, 0xff, 0x25, 0x4e, 0xb5, 0x64, 0xee, 0x9a, 0xf5, 0xfc, 0x35, 0xe9,
- 0x1b, 0xd8, 0x9d, 0x91, 0x65, 0x8c, 0x70, 0x60, 0x75, 0xc8, 0x7c, 0x16, 0x78, 0xdc, 0x0a, 0x33,
- 0xa4, 0xae, 0x90, 0x20, 0xd4, 0xfc, 0x44, 0x56, 0x42, 0xa0, 0xbf, 0xaf, 0xa2, 0x24, 0x6b, 0xd7,
- 0x5c, 0xfc, 0xa6, 0xbf, 0x85, 0xce, 0x53, 0xe6, 0xfb, 0xa9, 0xcc, 0x1d, 0x58, 0x89, 0xb9, 0x9c,
- 0xfa, 0xca, 0x88, 0x34, 0x94, 0x4e, 0x4b, 0xfe, 0x9e, 0x7b, 0x3a, 0x99, 0x78, 0x1c, 0x9b, 0x90,
- 0x81, 0x61, 0x3d, 0x8b, 0x63, 0x72, 0x17, 0x3a, 0x5c, 0x2a, 0x71, 0xc9, 0x14, 0x1f, 0x8c, 0x99,
- 0x34, 0x11, 0x6c, 0x5b, 0xde, 0x19, 0x93, 0xf4, 0x04, 0xb6, 0x9e, 0x5c, 0x3d, 0xf1, 0x43, 0xef,
- 0xbb, 0xaf, 0xf1, 0x6e, 0xb9, 0xe2, 0x37, 0x57, 0xaf, 0x15, 0xae, 0xfe, 0x03, 0x20, 0x67, 0x5c,
- 0xfd, 0xf4, 0x2a, 0x60, 0x52, 0x5d, 0xe5, 0x2d, 0xbc, 0x14, 0x01, 0x8f, 0x53, 0xa8, 0x48, 0x28,
- 0xfa, 0xaf, 0x1a, 0x90, 0xd7, 0x31, 0x0b, 0x24, 0xf3, 0x34, 0xbe, 0x59, 0xe1, 0x04, 0x96, 0x2e,
- 0xe2, 0xf0, 0xd2, 0x5c, 0x07, 0xbf, 0x75, 0x56, 0xab, 0xd0, 0xdc, 0xa1, 0xae, 0x42, 0xed, 0xae,
- 0xb7, 0xcc, 0x9f, 0xda, 0x7a, 0x4e, 0x88, 0xcc, 0x89, 0x4b, 0x79, 0x27, 0xde, 0x86, 0xd6, 0x98,
- 0xc9, 0x41, 0x14, 0x0b, 0x8f, 0x63, 0x01, 0xb7, 0xdc, 0xe6, 0x98, 0xc9, 0x57, 0x9a, 0xb6, 0x8b,
- 0xbe, 0xb8, 0x14, 0xca, 0x24, 0xa3, 0x5e, 0x7c, 0xa1, 0x69, 0x72, 0xaa, 0x81, 0x23, 0x50, 0x31,
- 0xf3, 0x14, 0x66, 0x60, 0xfb, 0x74, 0xc7, 0x94, 0xe2, 0x53, 0xc3, 0x36, 0x36, 0xbb, 0xe9, 0x3e,
- 0x7d, 0xd9, 0xa1, 0x08, 0x58, 0x7c, 0x85, 0x25, 0xde, 0x71, 0x0d, 0x45, 0xaf, 0x61, 0xa3, 0x74,
- 0x48, 0x6f, 0x95, 0xe1, 0x34, 0x4e, 0x93, 0xc1, 0x50, 0x3a, 0x72, 0xc9, 0xd7, 0x00, 0x83, 0x6f,
- 0x22, 0x97, 0xb0, 0x5e, 0x5f, 0x45, 0x5c, 0x03, 0xda, 0xc5, 0x34, 0x40, 0xa7, 0x59, 0x40, 0xb3,
- 0xb4, 0xf6, 0x1e, 0x8b, 0xc7, 0x12, 0x5d, 0xd0, 0x72, 0xf1, 0x9b, 0xf6, 0x61, 0xef, 0x9c, 0x07,
- 0x23, 0x97, 0xbd, 0xab, 0x76, 0x37, 0xa2, 0x70, 0x0d, 0xcd, 0x4d, 0x50, 0xf8, 0xd7, 0xb0, 0xab,
- 0x0f, 0x14, 0x76, 0x67, 0xc1, 0x54, 0xef, 0x27, 0x4c, 0x4e, 0xac, 0xd1, 0x09, 0xa5, 0x8b, 0xdb,
- 0xfa, 0x60, 0x90, 0x01, 0x0e, 0x16, 0xb7, 0xe5, 0x3f, 0x36, 0xc0, 0x33, 0x80, 0xed, 0x33, 0xae,
- 0x30, 0xad, 0x9e, 0x5c, 0x7d, 0xcd, 0xe4, 0x24, 0x67, 0x4a, 0x4e, 0x32, 0x7e, 0x93, 0x53, 0xd8,
- 0xbe, 0x98, 0xfa, 0xfe, 0xe0, 0x42, 0xf8, 0xfe, 0x40, 0x65, 0x06, 0xa1, 0xf0, 0xa6, 0xbb, 0xa9,
- 0x17, 0xbf, 0x12, 0xbe, 0x9f, 0xb3, 0x95, 0x72, 0xac, 0x40, 0xab, 0xe0, 0xbf, 0xc9, 0xdc, 0xff,
- 0x49, 0xcd, 0x03, 0xb8, 0x7d, 0xc6, 0x55, 0x8e, 0xb3, 0xf0, 0x36, 0xf4, 0x1f, 0x0d, 0x58, 0x43,
- 0xbb, 0x52, 0x7f, 0x56, 0xdd, 0xf9, 0x0e, 0xb4, 0x23, 0x16, 0xf3, 0x40, 0x0d, 0x70, 0xc9, 0x24,
- 0x40, 0xc2, 0xd2, 0x1a, 0x72, 0xb7, 0x68, 0x14, 0x6e, 0x51, 0x5d, 0x00, 0xf9, 0xfe, 0xb7, 0x5c,
- 0xea, 0x7f, 0xfb, 0xd0, 0x52, 0xe2, 0x92, 0x4b, 0xc5, 0x2e, 0x23, 0xcc, 0xff, 0x86, 0x9b, 0x31,
- 0x0a, 0xad, 0x60, 0xb5, 0xd8, 0x0a, 0x0e, 0x00, 0x70, 0xb4, 0x18, 0xc4, 0x61, 0xa8, 0x0c, 0x00,
- 0xb7, 0x90, 0xe3, 0x86, 0xa1, 0xd2, 0x27, 0xd5, 0x7b, 0x99, 0x2c, 0xb6, 0x12, 0xa8, 0x53, 0xef,
- 0x25, 0x2e, 0x69, 0x60, 0x7a, 0xcb, 0x03, 0x65, 0x56, 0xc1, 0x00, 0x13, 0xb2, 0x70, 0xc3, 0x63,
- 0x58, 0x4f, 0x47, 0x98, 0x64, 0x4f, 0x1b, 0x8b, 0xaf, 0x77, 0x92, 0xb2, 0x93, 0x12, 0x4c, 0xbe,
- 0xf5, 0x19, 0x77, 0xcd, 0xcb, 0x93, 0xda, 0x11, 0x08, 0x32, 0x4e, 0x27, 0xc1, 0x07, 0x24, 0xb4,
- 0x66, 0x21, 0x07, 0x17, 0x22, 0x60, 0xbe, 0x50, 0x57, 0xce, 0x1a, 0x86, 0x16, 0x84, 0xfc, 0xca,
- 0x70, 0xc8, 0x4f, 0xa0, 0x93, 0x8b, 0xbd, 0x74, 0x46, 0xd8, 0x7f, 0x7b, 0xa6, 0xe8, 0x2b, 0xca,
- 0xc1, 0x2d, 0xec, 0xa7, 0xff, 0xae, 0xc3, 0x66, 0x55, 0xd1, 0x54, 0x05, 0xd9, 0x01, 0xeb, 0xcb,
- 0xf2, 0xbc, 0x62, 0x01, 0xb0, 0x31, 0x03, 0x80, 0x4b, 0xb3, 0x00, 0xb8, 0x5c, 0x09, 0x80, 0x2b,
- 0xf9, 0xf8, 0x17, 0x62, 0xbc, 0x5a, 0x8e, 0xb1, 0xed, 0x31, 0x4d, 0xd3, 0xd3, 0x35, 0xc0, 0x58,
- 0x4c, 0x68, 0x65, 0x98, 0x50, 0x84, 0x51, 0xb8, 0x09, 0x46, 0xdb, 0x25, 0x18, 0xad, 0x82, 0x86,
- 0x4e, 0x25, 0x34, 0x20, 0x24, 0x2a, 0xa6, 0xa6, 0x12, 0x83, 0xb3, 0xec, 0x1a, 0x4a, 0xa7, 0x93,
- 0x96, 0x3f, 0x95, 0x7c, 0xe4, 0xac, 0x27, 0xe9, 0x34, 0x66, 0xf2, 0x1b, 0xc9, 0x47, 0xf4, 0x0b,
- 0xb8, 0xf5, 0x92, 0xbf, 0x33, 0xed, 0xd6, 0xd6, 0xde, 0x21, 0x40, 0xc4, 0xa4, 0x8c, 0x26, 0xb1,
- 0x4e, 0xfa, 0x9a, 0x2d, 0x20, 0xcb, 0xa1, 0x27, 0x40, 0xf2, 0x87, 0xb2, 0xf6, 0x5c, 0xdd, 0xeb,
- 0xa9, 0x0f, 0x5b, 0xdf, 0x04, 0xba, 0x6e, 0x4b, 0x7a, 0xe6, 0x4f, 0x07, 0x45, 0x0b, 0xea, 0x65,
- 0x0b, 0x74, 0x51, 0x8e, 0xa6, 0x31, 0x4b, 0x31, 0x7c, 0xc9, 0x4d, 0x69, 0xda, 0x87, 0xed, 0x92,
- 0xb6, 0xca, 0x5e, 0xdf, 0xb4, 0xbd, 0x5e, 0x5f, 0xe7, 0xc5, 0x07, 0x18, 0x47, 0x3f, 0x83, 0xcd,
- 0x17, 0x1f, 0x20, 0xfe, 0xe7, 0xb0, 0x71, 0x2e, 0xc6, 0x41, 0x1e, 0xdc, 0xe6, 0x5f, 0xdc, 0xe6,
- 0x7a, 0x3d, 0xc9, 0x1d, 0xcc, 0xf5, 0x2e, 0x34, 0x98, 0x3f, 0x36, 0x63, 0x8c, 0xfe, 0xa4, 0x1f,
- 0x43, 0x37, 0x13, 0x99, 0x55, 0xc9, 0x4c, 0x27, 0xfa, 0x3d, 0x1c, 0xe9, 0x7d, 0xb9, 0xa2, 0x7a,
- 0x95, 0xfa, 0xd0, 0xda, 0xf2, 0x63, 0x68, 0xe7, 0x11, 0xbb, 0x86, 0x60, 0xb1, 0x57, 0x55, 0xb4,
- 0x49, 0xb3, 0xce, 0xef, 0x5e, 0x14, 0x27, 0xfa, 0x43, 0xb8, 0x7b, 0x83, 0x01, 0x0b, 0x2c, 0x2f,
- 0xf6, 0xd0, 0xff, 0xb3, 0xe5, 0x7d, 0xe8, 0x9e, 0x99, 0xfa, 0x4c, 0x0d, 0x2d, 0x14, 0x71, 0xad,
- 0x58, 0xc4, 0xf4, 0x2e, 0xb4, 0x17, 0xf5, 0xaf, 0x07, 0xd0, 0x3e, 0x63, 0xd9, 0x50, 0xdd, 0x85,
- 0x86, 0x9e, 0x1c, 0x93, 0x1d, 0xfa, 0x53, 0x73, 0xb2, 0x69, 0x53, 0x7f, 0xd2, 0x87, 0xb0, 0xfe,
- 0x2c, 0xc1, 0x76, 0x7b, 0xea, 0x23, 0x58, 0x49, 0xd0, 0x1e, 0xe7, 0xc1, 0xf6, 0x69, 0xc7, 0x5c,
- 0x18, 0xb7, 0xb9, 0x66, 0x8d, 0x3e, 0x80, 0x65, 0x64, 0x7c, 0xc0, 0xe3, 0xf1, 0x63, 0xe8, 0xbc,
- 0x8a, 0xe2, 0xf0, 0x22, 0xd7, 0xec, 0x7d, 0x21, 0x15, 0x0f, 0xec, 0xac, 0x92, 0x50, 0xf4, 0x13,
- 0x58, 0x33, 0xfb, 0x16, 0x24, 0xfe, 0x97, 0x70, 0xeb, 0x8c, 0xab, 0xa7, 0xf8, 0x16, 0x4e, 0x37,
- 0x1f, 0xc3, 0x4a, 0xf2, 0x3a, 0x36, 0xf1, 0xea, 0x9e, 0x24, 0xcf, 0xe6, 0xa4, 0x27, 0xe9, 0x9d,
- 0x66, 0xfd, 0xf4, 0xaf, 0x00, 0xf0, 0x38, 0x12, 0xe7, 0x3c, 0x7e, 0xab, 0x41, 0xf2, 0x0d, 0xb4,
- 0x73, 0xef, 0x2d, 0xb2, 0x6b, 0xae, 0x5d, 0x7e, 0xef, 0xf6, 0x6c, 0xbf, 0xa9, 0x78, 0x9c, 0xd1,
- 0xbd, 0xef, 0xff, 0xf6, 0xcf, 0x3f, 0xd6, 0x37, 0xc9, 0xad, 0xfe, 0xdb, 0x07, 0xfd, 0xa9, 0xe4,
- 0xb1, 0x7e, 0xb3, 0x63, 0xdb, 0x25, 0xbf, 0x81, 0xdd, 0x17, 0x4c, 0x71, 0xa9, 0x9e, 0xc7, 0x31,
- 0xc7, 0xa7, 0xd0, 0xd0, 0xe7, 0x38, 0x6c, 0xcc, 0x57, 0xb5, 0x65, 0x16, 0x0a, 0x33, 0x09, 0xdd,
- 0x42, 0x25, 0xeb, 0xa4, 0x93, 0x2a, 0xd1, 0xcf, 0xba, 0x18, 0x36, 0x4a, 0xef, 0x1a, 0x72, 0x90,
- 0x59, 0x5a, 0xf1, 0x76, 0xea, 0x1d, 0xce, 0x5b, 0x36, 0x7a, 0x8e, 0x50, 0x4f, 0x8f, 0x6e, 0xa7,
- 0x7a, 0x98, 0x79, 0xb6, 0xe9, 0x6d, 0x8f, 0x6a, 0xf7, 0xc9, 0x2b, 0x58, 0xd2, 0x8f, 0x1d, 0x32,
- 0xbf, 0x26, 0x7a, 0x9b, 0x76, 0x24, 0xcf, 0x3d, 0x8a, 0xa8, 0x83, 0x92, 0x09, 0x5d, 0x4b, 0x25,
- 0x7b, 0xcc, 0xf7, 0xb5, 0xc4, 0x6b, 0x20, 0xb3, 0xb3, 0x30, 0x39, 0x32, 0x42, 0xe6, 0x8e, 0xc9,
- 0xe9, 0x5d, 0xe6, 0xcc, 0xc5, 0x94, 0xa2, 0xc6, 0x7d, 0xba, 0x9b, 0x6a, 0x8c, 0xd9, 0xbb, 0x5c,
- 0xb9, 0x6a, 0xdd, 0x13, 0x58, 0x2f, 0x0e, 0xbe, 0x64, 0x3f, 0xf3, 0xd0, 0xec, 0x3c, 0x3c, 0x27,
- 0x3a, 0xb3, 0x9a, 0xc6, 0x85, 0xd3, 0x5a, 0x53, 0x00, 0xdd, 0xf2, 0x04, 0x4c, 0x0e, 0x67, 0x75,
- 0xe5, 0x47, 0xe3, 0x39, 0xda, 0x3e, 0x42, 0x6d, 0x87, 0x74, 0xaf, 0x4a, 0x1b, 0x9e, 0xd7, 0xfa,
- 0xbe, 0xaf, 0xe1, 0x4c, 0x5f, 0x70, 0x8c, 0xc7, 0x45, 0xa4, 0x08, 0xcd, 0xb4, 0xce, 0x9b, 0x94,
- 0x7b, 0x37, 0x0c, 0x58, 0xf4, 0x53, 0xd4, 0x7f, 0x8f, 0x1e, 0xe6, 0xf5, 0xcf, 0xea, 0xd1, 0x46,
- 0x0c, 0xa0, 0x95, 0xfe, 0xf4, 0x94, 0xa6, 0x7c, 0xf9, 0x87, 0xab, 0x9e, 0x33, 0xbb, 0x60, 0x54,
- 0x1d, 0xa0, 0xaa, 0x5d, 0x4a, 0x52, 0x55, 0xd2, 0xee, 0x79, 0x54, 0xbb, 0xff, 0x79, 0xcd, 0x14,
- 0xb0, 0x05, 0xd5, 0xf9, 0x55, 0x65, 0x17, 0xca, 0xf0, 0x4b, 0xf7, 0x51, 0xc3, 0x0e, 0xd9, 0xca,
- 0x5f, 0x26, 0x95, 0xf7, 0x06, 0xda, 0xcf, 0xb2, 0xc7, 0xf7, 0x4d, 0x39, 0x4f, 0x32, 0x05, 0xa9,
- 0xec, 0x3b, 0x28, 0x7b, 0x8f, 0x66, 0xb2, 0x73, 0x2f, 0x79, 0xed, 0x1e, 0x86, 0xf5, 0x9b, 0x60,
- 0xb1, 0x49, 0x3f, 0x2b, 0x27, 0x1f, 0x8c, 0xed, 0x3c, 0x1a, 0x67, 0xe2, 0xef, 0xa1, 0xf8, 0x03,
- 0xea, 0xe4, 0x4d, 0xcf, 0x0b, 0x4b, 0x54, 0x40, 0xf6, 0xfe, 0x27, 0xb7, 0x6d, 0x42, 0x55, 0xfc,
- 0x84, 0xd0, 0xdb, 0xcb, 0xf2, 0xa2, 0xf4, 0x7b, 0x01, 0xbd, 0x8d, 0xaa, 0xb6, 0x69, 0x37, 0x55,
- 0x35, 0x4a, 0x76, 0x3c, 0xaa, 0xdd, 0x3f, 0xfd, 0x4b, 0x0b, 0x3a, 0x8f, 0x47, 0x97, 0x22, 0xb0,
- 0xa8, 0xfa, 0x2d, 0x34, 0xed, 0x8f, 0x3d, 0x8b, 0x23, 0x52, 0xfe, 0x59, 0x88, 0xf6, 0x50, 0xd7,
- 0x16, 0xc1, 0x98, 0x33, 0x2d, 0x37, 0xc5, 0x20, 0xe2, 0x01, 0x64, 0x43, 0x22, 0xb1, 0x79, 0x33,
- 0x33, 0x6c, 0xa6, 0x57, 0x99, 0x9d, 0x28, 0x8b, 0x08, 0x57, 0x10, 0xdf, 0x0f, 0xf8, 0x3b, 0xed,
- 0xb2, 0x10, 0xd6, 0x0a, 0xb3, 0x5e, 0xea, 0xb5, 0xaa, 0x79, 0xb3, 0xb7, 0x5f, 0xbd, 0x58, 0x15,
- 0xa3, 0xa2, 0xb6, 0x29, 0x1e, 0xd0, 0x0a, 0xc7, 0xd0, 0xce, 0xcd, 0x7e, 0x69, 0x96, 0xcd, 0xce,
- 0x8f, 0x69, 0x59, 0x56, 0x8c, 0x8a, 0xf4, 0x2e, 0xaa, 0xba, 0x4d, 0x77, 0x66, 0x55, 0x59, 0x45,
- 0x01, 0x6c, 0x94, 0xc0, 0xf2, 0xa6, 0x94, 0x5e, 0x84, 0xaf, 0x15, 0x9e, 0x2c, 0xa1, 0xeb, 0xaf,
- 0xa0, 0x69, 0x47, 0x4a, 0x62, 0x7f, 0xa7, 0x29, 0x8d, 0xad, 0x69, 0x1e, 0x94, 0x67, 0x4f, 0x7a,
- 0x88, 0xe2, 0x1d, 0xba, 0x99, 0x89, 0x97, 0x62, 0x1c, 0xf4, 0x27, 0x26, 0xb3, 0xff, 0x50, 0x83,
- 0x83, 0xd2, 0x1c, 0xf8, 0x4b, 0xa1, 0x26, 0xd9, 0x48, 0x47, 0x3e, 0xc9, 0x89, 0xbe, 0x69, 0xe8,
- 0xeb, 0x1d, 0x2f, 0xde, 0x58, 0x6c, 0xf6, 0x74, 0xbd, 0x68, 0x94, 0xb6, 0xe7, 0x4f, 0xda, 0x9e,
- 0xa2, 0xab, 0xe6, 0xd9, 0xb3, 0x60, 0x08, 0x5d, 0xe8, 0xf9, 0x13, 0xb4, 0xe2, 0x98, 0xde, 0xab,
- 0xf4, 0x7c, 0x51, 0xab, 0x36, 0xed, 0x1c, 0xe0, 0x5c, 0xb1, 0x58, 0xe1, 0x88, 0x45, 0x6c, 0x7b,
- 0xce, 0x0f, 0x66, 0x69, 0xab, 0x29, 0x4c, 0x61, 0xb6, 0x16, 0xe9, 0x46, 0xa6, 0x28, 0xd2, 0x1b,
- 0x92, 0xe0, 0xb6, 0xd2, 0x49, 0x6c, 0x7e, 0x99, 0x3b, 0x19, 0xa8, 0x14, 0x87, 0x36, 0x8b, 0x29,
- 0x24, 0x17, 0xdf, 0x71, 0x2a, 0xef, 0x5b, 0x68, 0xda, 0xff, 0x17, 0x16, 0x43, 0x48, 0xf9, 0x9f,
- 0x88, 0x2a, 0x08, 0x09, 0xc2, 0x11, 0x17, 0xc1, 0x45, 0x38, 0x5c, 0xc1, 0x1f, 0xb6, 0xbf, 0xf8,
- 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0x9c, 0x43, 0x6f, 0xe4, 0x19, 0x00, 0x00,
+ // 2320 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x4f, 0x6f, 0x1b, 0xb9,
+ 0x15, 0x87, 0x2c, 0xff, 0x91, 0x9e, 0x64, 0x5b, 0xa1, 0xff, 0x8d, 0x15, 0xdb, 0x6b, 0x33, 0xdb,
+ 0x8d, 0x37, 0xe8, 0x5a, 0x1b, 0x2f, 0x90, 0x16, 0x29, 0xb6, 0x40, 0x92, 0x66, 0xbd, 0x29, 0x82,
+ 0xc0, 0x1d, 0x67, 0xdb, 0x05, 0xda, 0x54, 0xa0, 0x66, 0x28, 0x69, 0xba, 0x63, 0xce, 0x94, 0xa4,
+ 0x9c, 0xd8, 0x97, 0x02, 0xb9, 0xf7, 0xd4, 0x4b, 0x0f, 0xfd, 0x10, 0xfd, 0x02, 0xfd, 0x10, 0x45,
+ 0x0f, 0xbd, 0xf4, 0xd8, 0xcf, 0x51, 0x14, 0xe4, 0x90, 0xf3, 0x4f, 0x23, 0x6b, 0xd3, 0x43, 0x6f,
+ 0xf3, 0x1e, 0xc9, 0xf7, 0x1e, 0xdf, 0x9f, 0x1f, 0x1f, 0x39, 0xd0, 0xe4, 0xb1, 0x77, 0x12, 0xf3,
+ 0x48, 0x46, 0x68, 0x89, 0xc7, 0x5e, 0x3c, 0xe8, 0xee, 0x8d, 0xa2, 0x68, 0x14, 0xd2, 0x1e, 0x89,
+ 0x83, 0x1e, 0x61, 0x2c, 0x92, 0x44, 0x06, 0x11, 0x13, 0xc9, 0xa4, 0xee, 0x8f, 0x47, 0x81, 0x1c,
+ 0x4f, 0x06, 0x27, 0x5e, 0x74, 0xd9, 0x63, 0x74, 0x30, 0x09, 0x89, 0x08, 0xa2, 0xde, 0x28, 0xfa,
+ 0xcc, 0x10, 0x3d, 0x2f, 0x62, 0x82, 0x32, 0x31, 0x11, 0xbd, 0x78, 0xd0, 0x13, 0x92, 0x48, 0x6a,
+ 0x56, 0x3e, 0x9a, 0xb7, 0x92, 0xd1, 0x41, 0x48, 0xa5, 0x5a, 0xe6, 0x45, 0x6c, 0x18, 0x8c, 0x92,
+ 0x75, 0xf8, 0x01, 0x74, 0x2e, 0x26, 0x03, 0xe1, 0xf1, 0x60, 0x40, 0x5d, 0xfa, 0xfb, 0x09, 0x15,
+ 0x12, 0x6d, 0xc3, 0xb2, 0x8c, 0xe2, 0xc0, 0x13, 0x4e, 0xed, 0xb0, 0x7e, 0xdc, 0x74, 0x0d, 0x85,
+ 0xbf, 0x84, 0x3b, 0xb9, 0xb9, 0x22, 0x56, 0xb6, 0xa0, 0x4d, 0x58, 0xd2, 0xc3, 0x4e, 0xed, 0xb0,
+ 0x76, 0xdc, 0x74, 0x13, 0x02, 0x21, 0x58, 0xf4, 0x89, 0x24, 0xce, 0x82, 0x66, 0xea, 0x6f, 0x8c,
+ 0xa0, 0xf3, 0x2a, 0x62, 0xe7, 0x84, 0x93, 0x4b, 0x61, 0x54, 0xe1, 0xbf, 0x2c, 0x28, 0xa6, 0x4f,
+ 0x5f, 0xb0, 0x61, 0x94, 0x8a, 0x5c, 0x83, 0x85, 0xc0, 0x37, 0xf2, 0x16, 0x02, 0x1f, 0xed, 0x42,
+ 0xc3, 0x1b, 0x93, 0x80, 0xf5, 0x03, 0x5f, 0x0b, 0x5c, 0x75, 0x57, 0x34, 0xfd, 0xc2, 0x47, 0x5d,
+ 0x68, 0x78, 0x51, 0xc0, 0x06, 0x44, 0x50, 0xa7, 0xae, 0x17, 0xa4, 0x34, 0xda, 0x07, 0x88, 0x29,
+ 0xe5, 0x7d, 0x2f, 0x9a, 0x30, 0xe9, 0x2c, 0xea, 0x85, 0x4d, 0xc5, 0x79, 0xa6, 0x18, 0x08, 0x43,
+ 0x5b, 0x5c, 0x33, 0x6f, 0xcc, 0x23, 0x16, 0xdc, 0x50, 0xdf, 0x59, 0x3a, 0xac, 0x1d, 0x37, 0xdc,
+ 0x02, 0x0f, 0x7d, 0x04, 0xad, 0xc1, 0xc4, 0xfb, 0x8e, 0xca, 0xbe, 0x08, 0x6e, 0xa8, 0xb3, 0x7c,
+ 0x58, 0x3b, 0x5e, 0x72, 0x21, 0x61, 0x5d, 0x04, 0x37, 0x14, 0x7d, 0x0a, 0x1d, 0xed, 0x47, 0x2f,
+ 0x0a, 0xfb, 0x57, 0x94, 0x8b, 0x20, 0x62, 0x0e, 0x68, 0x3b, 0xd6, 0x2d, 0xff, 0x97, 0x09, 0x1b,
+ 0x9d, 0x42, 0x8b, 0x47, 0x13, 0x49, 0xfb, 0x92, 0x0c, 0x42, 0xea, 0xb4, 0x0e, 0xeb, 0xc7, 0xad,
+ 0xd3, 0x3b, 0x27, 0x3a, 0x2d, 0x4e, 0x5c, 0x35, 0xf2, 0x5a, 0x0d, 0xb8, 0xc0, 0xd3, 0x6f, 0xfc,
+ 0x08, 0x20, 0x1b, 0x99, 0xf2, 0x8b, 0x03, 0x2b, 0xc4, 0xf7, 0x39, 0x15, 0xc2, 0x59, 0xd0, 0x81,
+ 0xb2, 0x24, 0xfe, 0x67, 0x0d, 0x36, 0xce, 0xa8, 0x7c, 0x45, 0x07, 0x17, 0x2a, 0x47, 0x52, 0xcf,
+ 0xe6, 0x3d, 0x59, 0x2b, 0x7a, 0x12, 0xc1, 0xa2, 0x24, 0x41, 0x68, 0x23, 0xa6, 0xbe, 0x51, 0x07,
+ 0xea, 0x61, 0x30, 0x30, 0x8e, 0x55, 0x9f, 0x2a, 0x35, 0xc6, 0x34, 0x18, 0x8d, 0x13, 0x7f, 0x2e,
+ 0xba, 0x86, 0xaa, 0xf4, 0xc3, 0x72, 0xb5, 0x1f, 0xca, 0x7e, 0x5f, 0xa9, 0xf0, 0xbb, 0x03, 0x2b,
+ 0x56, 0x4a, 0x43, 0x4b, 0xb1, 0x24, 0xfe, 0x1c, 0x3a, 0x4f, 0x3c, 0x1d, 0x51, 0x91, 0xee, 0x6a,
+ 0x0f, 0x9a, 0x66, 0xe3, 0xd4, 0xa6, 0x6c, 0xc6, 0xc0, 0x3f, 0x87, 0xed, 0x33, 0x2a, 0xcd, 0x22,
+ 0xe3, 0x8e, 0x24, 0xcf, 0x73, 0xfe, 0x4b, 0x9c, 0x6a, 0xc9, 0xdc, 0x36, 0x17, 0xf2, 0xdb, 0xc4,
+ 0x6f, 0x60, 0x67, 0x4a, 0x96, 0x31, 0xc2, 0x81, 0x95, 0x01, 0x09, 0x09, 0xf3, 0xa8, 0x15, 0x66,
+ 0x48, 0x55, 0x21, 0x2c, 0x52, 0xfc, 0x44, 0x56, 0x42, 0x68, 0x7f, 0x5f, 0xc7, 0x49, 0xd6, 0xae,
+ 0xba, 0xfa, 0x1b, 0xff, 0x0e, 0xda, 0xcf, 0x48, 0x18, 0xa6, 0x32, 0xb7, 0x61, 0x99, 0x53, 0x31,
+ 0x09, 0xa5, 0x11, 0x69, 0x28, 0x95, 0x96, 0xf4, 0x1d, 0xf5, 0x54, 0x32, 0x51, 0xce, 0x4d, 0xc8,
+ 0xc0, 0xb0, 0x9e, 0x73, 0x8e, 0x8e, 0xa0, 0x4d, 0x85, 0x0c, 0x2e, 0x89, 0xa4, 0xfd, 0x11, 0x11,
+ 0x26, 0x82, 0x2d, 0xcb, 0x3b, 0x23, 0x02, 0x9f, 0xc0, 0xe6, 0xd3, 0xeb, 0xa7, 0x61, 0xe4, 0x7d,
+ 0xf7, 0xb5, 0xde, 0x5b, 0xae, 0xf8, 0xcd, 0xd6, 0x6b, 0x85, 0xad, 0xff, 0x10, 0xd0, 0x19, 0x95,
+ 0x3f, 0xbb, 0x66, 0x44, 0xc8, 0xeb, 0xbc, 0x85, 0x97, 0x01, 0xa3, 0x3c, 0x85, 0x8a, 0x84, 0xc2,
+ 0xff, 0xa9, 0x01, 0x7a, 0xcd, 0x09, 0x13, 0xc4, 0x53, 0xf8, 0x66, 0x85, 0x23, 0x58, 0x1c, 0xf2,
+ 0xe8, 0xd2, 0x6c, 0x47, 0x7f, 0xab, 0xac, 0x96, 0x91, 0xd9, 0xc3, 0x82, 0x8c, 0x94, 0xbb, 0xae,
+ 0x48, 0x38, 0xb1, 0xf5, 0x9c, 0x10, 0x99, 0x13, 0x17, 0xf3, 0x4e, 0xbc, 0x0b, 0xcd, 0x11, 0x11,
+ 0xfd, 0x98, 0x07, 0x1e, 0xd5, 0x05, 0xdc, 0x74, 0x1b, 0x23, 0x22, 0xce, 0x15, 0x6d, 0x07, 0xc3,
+ 0xe0, 0x32, 0x90, 0x26, 0x19, 0xd5, 0xe0, 0x4b, 0x45, 0xa3, 0x53, 0x05, 0x1c, 0x4c, 0x72, 0xe2,
+ 0x49, 0x9d, 0x81, 0xad, 0xd3, 0x6d, 0x53, 0x8a, 0xcf, 0x0c, 0xdb, 0xd8, 0xec, 0xa6, 0xf3, 0xd4,
+ 0x66, 0x07, 0x01, 0x23, 0xfc, 0x5a, 0x97, 0x78, 0xdb, 0x35, 0x54, 0x1a, 0xca, 0x4d, 0x53, 0x3a,
+ 0x2a, 0x94, 0x37, 0xb0, 0x5e, 0x12, 0xa4, 0x96, 0x8b, 0x68, 0xc2, 0xd3, 0x04, 0x31, 0x94, 0x8a,
+ 0x66, 0xf2, 0xd5, 0xd7, 0x52, 0x4c, 0x34, 0x13, 0xd6, 0xeb, 0xeb, 0x98, 0x2a, 0x90, 0x1b, 0x4e,
+ 0x98, 0x76, 0xa4, 0x05, 0x39, 0x4b, 0x2b, 0xdd, 0x84, 0x8f, 0x84, 0x76, 0x4b, 0xd3, 0xd5, 0xdf,
+ 0xb8, 0x07, 0xbb, 0x17, 0x94, 0xf9, 0x2e, 0x79, 0x5b, 0x1d, 0x02, 0x8d, 0xcc, 0x35, 0xbd, 0x85,
+ 0x04, 0x99, 0x7f, 0x03, 0x3b, 0x6a, 0x41, 0x61, 0x76, 0x16, 0x60, 0xf9, 0x6e, 0x4c, 0xc4, 0xd8,
+ 0x1a, 0x9d, 0x50, 0xaa, 0xe0, 0xad, 0x5f, 0xfa, 0x19, 0x08, 0xe9, 0x82, 0xb7, 0xfc, 0x27, 0x06,
+ 0x8c, 0xfa, 0xb0, 0x75, 0x46, 0xa5, 0x4e, 0xb5, 0xa7, 0xd7, 0x5f, 0x13, 0x31, 0xce, 0x99, 0x92,
+ 0x93, 0xac, 0xbf, 0xd1, 0x29, 0x6c, 0x0d, 0x27, 0x61, 0xd8, 0x1f, 0x06, 0x61, 0xd8, 0x97, 0x99,
+ 0x41, 0x5a, 0x78, 0xc3, 0xdd, 0x50, 0x83, 0x5f, 0x05, 0x61, 0x98, 0xb3, 0x15, 0x53, 0x5d, 0x95,
+ 0x56, 0xc1, 0xf7, 0xc9, 0xe6, 0xff, 0x49, 0xcd, 0x43, 0xb8, 0x7b, 0x46, 0x65, 0x8e, 0x33, 0x77,
+ 0x37, 0xf8, 0x5f, 0x75, 0x58, 0xd5, 0x76, 0xa5, 0xfe, 0xac, 0xda, 0xf3, 0x47, 0xd0, 0x8a, 0x09,
+ 0xa7, 0x4c, 0xf6, 0xf5, 0x90, 0x49, 0x80, 0x84, 0xa5, 0x34, 0xe4, 0x76, 0x51, 0x2f, 0xec, 0xa2,
+ 0xba, 0x28, 0xf2, 0x67, 0xe2, 0x52, 0xe9, 0x4c, 0xdc, 0x83, 0xa6, 0x0c, 0x2e, 0xa9, 0x90, 0xe4,
+ 0x32, 0xd6, 0x35, 0x51, 0x77, 0x33, 0x46, 0xe1, 0x78, 0x58, 0x29, 0x1e, 0x0f, 0xfb, 0x00, 0xba,
+ 0xdd, 0xe8, 0xf3, 0x28, 0x92, 0x06, 0x94, 0x9b, 0x9a, 0xe3, 0x46, 0x91, 0x54, 0x2b, 0xe5, 0x3b,
+ 0x91, 0x0c, 0x36, 0x13, 0xf8, 0x93, 0xef, 0x84, 0x1e, 0x52, 0x60, 0x75, 0x45, 0x99, 0x34, 0xa3,
+ 0x60, 0xc0, 0x4a, 0xb3, 0xf4, 0x84, 0x27, 0xb0, 0x96, 0xb6, 0x35, 0xc9, 0x9c, 0x96, 0x2e, 0xc8,
+ 0xee, 0x49, 0xca, 0x4e, 0xca, 0x32, 0xf9, 0x56, 0x6b, 0xdc, 0x55, 0x2f, 0x4f, 0x2a, 0x47, 0x68,
+ 0xe0, 0x71, 0xda, 0x09, 0x66, 0x68, 0x42, 0x69, 0x0e, 0x44, 0x7f, 0x18, 0x30, 0x12, 0x06, 0xf2,
+ 0xda, 0x59, 0xd5, 0xa1, 0x85, 0x40, 0x7c, 0x65, 0x38, 0xe8, 0xa7, 0xd0, 0xce, 0xc5, 0x5e, 0x38,
+ 0xbe, 0x3e, 0x93, 0xbb, 0x06, 0x08, 0x2a, 0xca, 0xc1, 0x2d, 0xcc, 0xc7, 0x7f, 0xab, 0xc3, 0x46,
+ 0x55, 0xd1, 0x54, 0x05, 0xd9, 0x01, 0xeb, 0xcb, 0x72, 0x0f, 0x63, 0x41, 0xb1, 0x3e, 0x05, 0x8a,
+ 0x8b, 0xd3, 0xa0, 0xb8, 0x54, 0x09, 0x8a, 0xcb, 0xf9, 0xf8, 0x17, 0x62, 0xbc, 0x52, 0x8e, 0xb1,
+ 0x05, 0xab, 0x46, 0x06, 0x56, 0x29, 0x26, 0x34, 0x33, 0x4c, 0x28, 0x42, 0x2b, 0xdc, 0x06, 0xad,
+ 0xad, 0x12, 0xb4, 0x56, 0x41, 0x43, 0xbb, 0x12, 0x1a, 0x34, 0x24, 0x4a, 0x22, 0x27, 0x42, 0x07,
+ 0x67, 0xc9, 0x35, 0x94, 0x4a, 0x27, 0x25, 0x7f, 0x22, 0xa8, 0xef, 0xac, 0x25, 0xe9, 0x34, 0x22,
+ 0xe2, 0x1b, 0x41, 0x7d, 0x74, 0x0f, 0x56, 0x73, 0x67, 0x5f, 0xc4, 0x9d, 0x75, 0x3d, 0xde, 0xce,
+ 0x4e, 0xbf, 0x88, 0xa3, 0x1f, 0xc0, 0x9a, 0x9d, 0x64, 0x0e, 0xd0, 0x8e, 0x9e, 0x65, 0x97, 0xba,
+ 0x9a, 0x89, 0xbf, 0x80, 0x3b, 0xaf, 0xe8, 0x5b, 0x73, 0x9c, 0xdb, 0x3a, 0x3e, 0x00, 0x88, 0x89,
+ 0x10, 0xf1, 0x98, 0xab, 0x02, 0xaa, 0xd9, 0x62, 0xb4, 0x1c, 0x7c, 0x02, 0x28, 0xbf, 0x28, 0x3b,
+ 0xfe, 0xab, 0x7b, 0x09, 0x1c, 0xc2, 0xe6, 0x37, 0x4c, 0x61, 0x40, 0x49, 0xcf, 0xec, 0xee, 0xa3,
+ 0x68, 0xc1, 0x42, 0xd9, 0x02, 0x55, 0xe0, 0xfe, 0x84, 0x93, 0xf4, 0x3c, 0x58, 0x74, 0x53, 0x1a,
+ 0xf7, 0x60, 0xab, 0xa4, 0xad, 0xb2, 0x97, 0x68, 0xd8, 0x5e, 0x42, 0x6d, 0xe7, 0xe5, 0x07, 0x18,
+ 0x87, 0x3f, 0x83, 0x8d, 0x97, 0x1f, 0x20, 0xfe, 0x17, 0xb0, 0x7e, 0x11, 0x8c, 0x58, 0x1e, 0x28,
+ 0x67, 0x6f, 0xdc, 0xd6, 0xcd, 0x42, 0x92, 0x87, 0xba, 0x6e, 0x3a, 0x50, 0x27, 0xe1, 0xc8, 0xb4,
+ 0x49, 0xea, 0x13, 0x7f, 0x02, 0x9d, 0x4c, 0x64, 0x56, 0x71, 0x53, 0xa7, 0x1a, 0x83, 0xdd, 0x33,
+ 0xca, 0x28, 0x57, 0x18, 0x45, 0x98, 0x1f, 0x5d, 0x5e, 0x50, 0xea, 0xcf, 0x37, 0xa2, 0x02, 0x8d,
+ 0xdb, 0xdf, 0x07, 0x8d, 0xf1, 0x6b, 0xe8, 0x56, 0xe9, 0xcb, 0x5a, 0xef, 0x2b, 0x3e, 0xec, 0x0b,
+ 0x4a, 0x7d, 0x63, 0xe5, 0xca, 0x15, 0x1f, 0xaa, 0x29, 0xaa, 0x9a, 0xd4, 0x50, 0xcc, 0xa3, 0x68,
+ 0x68, 0xf4, 0xa9, 0xb9, 0xe7, 0x8a, 0xc6, 0x7f, 0x80, 0x43, 0xb5, 0xdb, 0x1c, 0xcc, 0x9c, 0xa7,
+ 0x99, 0x60, 0x37, 0xf3, 0x13, 0x68, 0xe5, 0xcf, 0xb0, 0x9a, 0x86, 0xcf, 0xdd, 0x2a, 0x18, 0x4b,
+ 0x5a, 0x9a, 0xfc, 0xec, 0x79, 0xd9, 0x86, 0x7f, 0x04, 0x47, 0xb7, 0x18, 0x70, 0x8b, 0xff, 0x95,
+ 0xe5, 0xc5, 0xae, 0xe2, 0xff, 0x6c, 0x79, 0x0f, 0x3a, 0x67, 0x06, 0xb1, 0x52, 0x43, 0x0b, 0xb0,
+ 0x56, 0x2b, 0xc2, 0x1a, 0x3e, 0x82, 0xd6, 0xbc, 0x13, 0xfd, 0x21, 0xb4, 0xce, 0x48, 0x76, 0xf5,
+ 0xe8, 0x40, 0x5d, 0xf5, 0xd7, 0xc9, 0x0c, 0xf5, 0xa9, 0x38, 0x59, 0x4f, 0xae, 0x3e, 0xf1, 0x23,
+ 0x58, 0x7b, 0x9e, 0x9c, 0x76, 0x76, 0xd5, 0xc7, 0xb0, 0x9c, 0x9c, 0x7f, 0xba, 0x6b, 0x6e, 0x9d,
+ 0xb6, 0xcd, 0x86, 0xf5, 0x34, 0xd7, 0x8c, 0xe1, 0x87, 0xb0, 0xa4, 0x19, 0x1f, 0x70, 0xc5, 0xfe,
+ 0x04, 0xda, 0xe7, 0x31, 0x8f, 0x86, 0xb9, 0xf6, 0x27, 0x0c, 0x84, 0xa4, 0xcc, 0x76, 0x6f, 0x09,
+ 0x85, 0xef, 0xc3, 0xaa, 0x99, 0x37, 0xa7, 0x7c, 0xbf, 0x84, 0x3b, 0x67, 0x54, 0x3e, 0xd3, 0x2f,
+ 0x06, 0xe9, 0xe4, 0x63, 0x58, 0x4e, 0xde, 0x10, 0x4c, 0xbc, 0x3a, 0x27, 0xc9, 0xe3, 0x42, 0x72,
+ 0x4a, 0xab, 0x99, 0x66, 0xfc, 0xf4, 0xef, 0x00, 0xf0, 0x24, 0x0e, 0x2e, 0x28, 0xbf, 0x52, 0xc7,
+ 0xc6, 0x1b, 0x68, 0xe5, 0x6e, 0xa5, 0x68, 0xc7, 0x6c, 0xbb, 0xfc, 0x2a, 0xd0, 0xb5, 0x27, 0x70,
+ 0xc5, 0x15, 0x16, 0xef, 0xbe, 0xff, 0xc7, 0xbf, 0xff, 0xb4, 0xb0, 0x81, 0xee, 0xf4, 0xae, 0x1e,
+ 0xf6, 0x26, 0x82, 0xf2, 0x1e, 0xa3, 0x03, 0xdd, 0x88, 0xa0, 0xdf, 0xc2, 0xce, 0x4b, 0x22, 0xa9,
+ 0x90, 0x2f, 0x38, 0xa7, 0xfa, 0xc2, 0x38, 0x08, 0xa9, 0x6e, 0xbf, 0x66, 0xab, 0xda, 0x34, 0x03,
+ 0x85, 0x2e, 0x0d, 0x6f, 0x6a, 0x25, 0x6b, 0xa8, 0x9d, 0x2a, 0x51, 0x97, 0x5f, 0x0e, 0xeb, 0xa5,
+ 0xdb, 0x1f, 0xda, 0xcf, 0x2c, 0xad, 0xb8, 0x61, 0x76, 0x0f, 0x66, 0x0d, 0x1b, 0x3d, 0x87, 0x5a,
+ 0x4f, 0x17, 0x6f, 0xa5, 0x7a, 0x88, 0xb9, 0xdc, 0xaa, 0x69, 0x8f, 0x6b, 0x0f, 0xd0, 0x39, 0x2c,
+ 0xaa, 0x2b, 0x21, 0x9a, 0x5d, 0x13, 0xdd, 0x0d, 0x7b, 0x71, 0xc9, 0x5d, 0x1d, 0xb1, 0xa3, 0x25,
+ 0x23, 0xbc, 0x9a, 0x4a, 0xf6, 0x48, 0x18, 0x2a, 0x89, 0x37, 0x80, 0xa6, 0x6f, 0x07, 0xe8, 0xd0,
+ 0x08, 0x99, 0x79, 0x71, 0x48, 0xf7, 0x32, 0xe3, 0xa6, 0x80, 0xb1, 0xd6, 0xb8, 0x87, 0x77, 0x52,
+ 0x8d, 0x9c, 0xbc, 0xcd, 0x95, 0xab, 0xd2, 0x3d, 0x86, 0xb5, 0xe2, 0x55, 0x00, 0xed, 0x65, 0x1e,
+ 0x9a, 0xbe, 0x21, 0xcc, 0x88, 0xce, 0xb4, 0xa6, 0x51, 0x61, 0xb5, 0xd2, 0xc4, 0xa0, 0x53, 0xbe,
+ 0x13, 0xa0, 0x83, 0x69, 0x5d, 0xf9, 0xcb, 0xc2, 0x0c, 0x6d, 0x1f, 0x6b, 0x6d, 0x07, 0x78, 0xb7,
+ 0x4a, 0x9b, 0x5e, 0xaf, 0xf4, 0xbd, 0xaf, 0xe9, 0x5b, 0x4e, 0xc1, 0x31, 0x1e, 0x0d, 0x62, 0x89,
+ 0x70, 0xa6, 0x75, 0xd6, 0xdd, 0xa1, 0x7b, 0x4b, 0xcb, 0x89, 0x3f, 0xd5, 0xfa, 0xef, 0xe1, 0x83,
+ 0xbc, 0xfe, 0x69, 0x3d, 0xca, 0x88, 0x3e, 0x34, 0xd3, 0x07, 0xba, 0x34, 0xe5, 0xcb, 0xcf, 0x7b,
+ 0x5d, 0x67, 0x7a, 0xc0, 0xa8, 0xda, 0xd7, 0xaa, 0x76, 0x30, 0x4a, 0x55, 0x09, 0x3b, 0xe7, 0x71,
+ 0xed, 0xc1, 0xe7, 0x35, 0x53, 0xc0, 0x16, 0x54, 0x67, 0x57, 0x95, 0x1d, 0x28, 0xc3, 0x2f, 0xde,
+ 0xd3, 0x1a, 0xb6, 0xd1, 0x66, 0x7e, 0x33, 0xa9, 0xbc, 0x37, 0xd0, 0x7a, 0x9e, 0x3d, 0x51, 0xdc,
+ 0x96, 0xf3, 0x28, 0x53, 0x90, 0xca, 0xfe, 0x48, 0xcb, 0xde, 0xc5, 0x99, 0xec, 0xdc, 0x7b, 0x87,
+ 0x72, 0x0f, 0xd1, 0xf5, 0x9b, 0x60, 0xb1, 0x49, 0x3f, 0x2b, 0x27, 0x1f, 0x8c, 0xad, 0x3c, 0x1a,
+ 0x67, 0xe2, 0xef, 0x69, 0xf1, 0xfb, 0xd8, 0xc9, 0x9b, 0x9e, 0x17, 0x96, 0xa8, 0x80, 0xec, 0x95,
+ 0x04, 0xdd, 0xb5, 0x09, 0x55, 0xf1, 0xd0, 0xd2, 0xdd, 0xcd, 0xf2, 0xa2, 0xf4, 0xaa, 0x82, 0xef,
+ 0x6a, 0x55, 0x5b, 0xb8, 0x93, 0xaa, 0xf2, 0x93, 0x19, 0x8f, 0x6b, 0x0f, 0x4e, 0xff, 0x0a, 0xd0,
+ 0x7e, 0xe2, 0x5f, 0x06, 0xcc, 0xa2, 0xea, 0xb7, 0xd0, 0xb0, 0x4f, 0x62, 0xf3, 0x23, 0x52, 0x7e,
+ 0x3c, 0xc3, 0x5d, 0xad, 0x6b, 0x13, 0xe9, 0x98, 0x13, 0x25, 0x37, 0xc5, 0x20, 0xe4, 0x01, 0x64,
+ 0xad, 0x2e, 0xb2, 0x79, 0x33, 0xd5, 0x32, 0xa7, 0x5b, 0x99, 0xee, 0x8b, 0x8b, 0x08, 0x57, 0x10,
+ 0xdf, 0x63, 0xf4, 0xad, 0x72, 0x59, 0x04, 0xab, 0x85, 0x8e, 0x35, 0xf5, 0x5a, 0x55, 0xd7, 0xdc,
+ 0xdd, 0xab, 0x1e, 0xac, 0x8a, 0x51, 0x51, 0xdb, 0x44, 0x2f, 0x50, 0x0a, 0x47, 0xd0, 0xca, 0x75,
+ 0xb0, 0x69, 0x96, 0x4d, 0x77, 0xc1, 0x69, 0x59, 0x56, 0x34, 0xbc, 0xf8, 0x48, 0xab, 0xba, 0x8b,
+ 0xb7, 0xa7, 0x55, 0x59, 0x45, 0x0c, 0xd6, 0x4b, 0x60, 0x79, 0x5b, 0x4a, 0xcf, 0xc3, 0xd7, 0x0a,
+ 0x4f, 0x96, 0xd0, 0xf5, 0xd7, 0xd0, 0xb0, 0x8d, 0x31, 0xb2, 0xaf, 0x59, 0xa5, 0xe6, 0x3b, 0xcd,
+ 0x83, 0x72, 0x07, 0x8d, 0x0f, 0xb4, 0x78, 0x07, 0x6f, 0x64, 0xe2, 0x45, 0x30, 0x62, 0xbd, 0xb1,
+ 0xc9, 0xec, 0xf7, 0x35, 0x40, 0xd3, 0xed, 0x6d, 0x7a, 0x6e, 0xcc, 0xec, 0xb4, 0xbb, 0x47, 0xb7,
+ 0xcc, 0x30, 0xba, 0xef, 0x6b, 0xdd, 0x47, 0x78, 0x2f, 0xd3, 0x3d, 0x9a, 0x9a, 0xad, 0x8c, 0xf8,
+ 0x63, 0x0d, 0xf6, 0x4b, 0xcd, 0xe8, 0xaf, 0x02, 0x39, 0xce, 0xfa, 0x4a, 0x74, 0x3f, 0xb7, 0xbf,
+ 0xdb, 0x3a, 0xcf, 0xee, 0xf1, 0xfc, 0x89, 0xc5, 0x8e, 0x03, 0xaf, 0x15, 0x3d, 0xa3, 0xec, 0xf9,
+ 0xb3, 0xb2, 0xa7, 0x18, 0xaf, 0x59, 0xf6, 0xcc, 0xe9, 0x84, 0xe7, 0x86, 0xff, 0x44, 0x5b, 0x71,
+ 0x8c, 0xef, 0x55, 0x86, 0xbf, 0xa8, 0x55, 0x99, 0x76, 0x01, 0x70, 0x21, 0x09, 0x97, 0xba, 0xcf,
+ 0x43, 0xb6, 0x47, 0xc8, 0x77, 0x87, 0xe9, 0x79, 0x57, 0x68, 0x05, 0x2d, 0x20, 0xe0, 0xf5, 0x4c,
+ 0x51, 0xac, 0x26, 0x24, 0x19, 0xd6, 0x4c, 0xdb, 0xc1, 0xd9, 0x58, 0xe3, 0x64, 0xc8, 0x56, 0xec,
+ 0x1c, 0x2d, 0xb0, 0xa1, 0x8d, 0x7c, 0xa0, 0xad, 0xbc, 0x6f, 0xa1, 0x61, 0x7f, 0x05, 0xcd, 0xc7,
+ 0xb1, 0xf2, 0x4f, 0xa3, 0x2a, 0x1c, 0x63, 0x91, 0x4f, 0x03, 0x36, 0x8c, 0x06, 0xcb, 0xfa, 0x1f,
+ 0xc4, 0x17, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x42, 0xe3, 0x2b, 0x72, 0x8f, 0x1b, 0x00, 0x00,
}
diff --git a/rpc/pb/rpc.pb.gw.go b/rpc/pb/rpc.pb.gw.go
index 882c34d70..25755278a 100644
--- a/rpc/pb/rpc.pb.gw.go
+++ b/rpc/pb/rpc.pb.gw.go
@@ -50,7 +50,7 @@ func request_ApiService_GetAccountState_0(ctx context.Context, marshaler runtime
var protoReq GetAccountStateRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -63,7 +63,7 @@ func request_ApiService_Call_0(ctx context.Context, marshaler runtime.Marshaler,
var protoReq TransactionRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -76,7 +76,7 @@ func request_ApiService_SendRawTransaction_0(ctx context.Context, marshaler runt
var protoReq SendRawTransactionRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -89,7 +89,7 @@ func request_ApiService_GetBlockByHash_0(ctx context.Context, marshaler runtime.
var protoReq GetBlockByHashRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -102,7 +102,7 @@ func request_ApiService_GetBlockByHeight_0(ctx context.Context, marshaler runtim
var protoReq GetBlockByHeightRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -115,7 +115,7 @@ func request_ApiService_GetTransactionReceipt_0(ctx context.Context, marshaler r
var protoReq GetTransactionByHashRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -128,7 +128,7 @@ func request_ApiService_Subscribe_0(ctx context.Context, marshaler runtime.Marsh
var protoReq SubscribeRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -158,7 +158,7 @@ func request_ApiService_EstimateGas_0(ctx context.Context, marshaler runtime.Mar
var protoReq TransactionRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -171,7 +171,7 @@ func request_ApiService_GetEventsByHash_0(ctx context.Context, marshaler runtime
var protoReq HashRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -184,7 +184,7 @@ func request_ApiService_GetDynasty_0(ctx context.Context, marshaler runtime.Mars
var protoReq ByBlockHeightRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -206,7 +206,7 @@ func request_AdminService_NewAccount_0(ctx context.Context, marshaler runtime.Ma
var protoReq NewAccountRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -219,7 +219,7 @@ func request_AdminService_UnlockAccount_0(ctx context.Context, marshaler runtime
var protoReq UnlockAccountRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -232,7 +232,7 @@ func request_AdminService_LockAccount_0(ctx context.Context, marshaler runtime.M
var protoReq LockAccountRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -245,7 +245,7 @@ func request_AdminService_SendTransaction_0(ctx context.Context, marshaler runti
var protoReq TransactionRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -258,7 +258,7 @@ func request_AdminService_SignHash_0(ctx context.Context, marshaler runtime.Mars
var protoReq SignHashRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -267,11 +267,24 @@ func request_AdminService_SignHash_0(ctx context.Context, marshaler runtime.Mars
}
+func request_AdminService_GenerateRandomSeed_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq GenerateRandomSeedRequest
+ var metadata runtime.ServerMetadata
+
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.GenerateRandomSeed(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
func request_AdminService_SignTransactionWithPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SignTransactionPassphraseRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -284,7 +297,7 @@ func request_AdminService_SendTransactionWithPassphrase_0(ctx context.Context, m
var protoReq SendTransactionPassphraseRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -297,7 +310,7 @@ func request_AdminService_StartPprof_0(ctx context.Context, marshaler runtime.Ma
var protoReq PprofRequest
var metadata runtime.ServerMetadata
- if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+ if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -1010,6 +1023,35 @@ func RegisterAdminServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
})
+ mux.Handle("POST", pattern_AdminService_GenerateRandomSeed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ if cn, ok := w.(http.CloseNotifier); ok {
+ go func(done <-chan struct{}, closed <-chan bool) {
+ select {
+ case <-done:
+ case <-closed:
+ cancel()
+ }
+ }(ctx.Done(), cn.CloseNotify())
+ }
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_AdminService_GenerateRandomSeed_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_AdminService_GenerateRandomSeed_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
mux.Handle("POST", pattern_AdminService_SignTransactionWithPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -1171,6 +1213,8 @@ var (
pattern_AdminService_SignHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "admin", "sign", "hash"}, ""))
+ pattern_AdminService_GenerateRandomSeed_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "admin", "generateRandomSeed"}, ""))
+
pattern_AdminService_SignTransactionWithPassphrase_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "admin", "sign"}, ""))
pattern_AdminService_SendTransactionWithPassphrase_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "admin", "transactionWithPassphrase"}, ""))
@@ -1195,6 +1239,8 @@ var (
forward_AdminService_SignHash_0 = runtime.ForwardResponseMessage
+ forward_AdminService_GenerateRandomSeed_0 = runtime.ForwardResponseMessage
+
forward_AdminService_SignTransactionWithPassphrase_0 = runtime.ForwardResponseMessage
forward_AdminService_SendTransactionWithPassphrase_0 = runtime.ForwardResponseMessage
diff --git a/rpc/pb/rpc.proto b/rpc/pb/rpc.proto
index 08d54d7cb..b04d78f24 100644
--- a/rpc/pb/rpc.proto
+++ b/rpc/pb/rpc.proto
@@ -174,6 +174,13 @@ service AdminService {
};
}
+ rpc GenerateRandomSeed(GenerateRandomSeedRequest) returns (GenerateRandomSeedResponse) {
+ option (google.api.http) = {
+ post: "/v1/admin/generateRandomSeed"
+ body: "*"
+ };
+ }
+
// Sign sign transaction
rpc SignTransactionWithPassphrase(SignTransactionPassphraseRequest) returns (SignTransactionPassphraseResponse) {
option (google.api.http) = {
@@ -359,6 +366,9 @@ message TransactionRequest {
// binary data for transaction
bytes binary = 10;
+
+ // transaction payload type, enum:binary, deploy, call
+ string type = 20;
}
message ContractRequest {
@@ -497,6 +507,12 @@ message TransactionResponse {
// transaction gas used
string gas_used = 14;
+
+ // contract execute error
+ string execute_error = 15;
+
+ // contract execute result
+ string execute_result = 16;
}
message NewAccountRequest {
@@ -541,6 +557,20 @@ message SignHashResponse {
bytes data = 1;
}
+message GenerateRandomSeedRequest {
+ // miner address
+ string address = 1;
+ // parent hash of new block
+ bytes parent_hash = 2;
+ // height of new block
+ uint64 height = 3;
+}
+
+message GenerateRandomSeedResponse {
+ bytes vrf_seed = 1;
+ bytes vrf_proof = 2;
+}
+
message SignTransactionPassphraseRequest {
// transaction struct
TransactionRequest transaction = 1;
diff --git a/storage/metrics.go b/storage/metrics.go
index 2187ef7f9..d7761ee7e 100644
--- a/storage/metrics.go
+++ b/storage/metrics.go
@@ -27,4 +27,9 @@ var (
// rocksdb metrics
metricsRocksdbFlushTime = metrics.NewGauge("neb.rocksdb.flushtime")
metricsRocksdbFlushLen = metrics.NewGauge("neb.rocksdb.flushlen")
+
+ metricsBlocksdbCacheSize = metrics.NewGauge("neb.rocksdb.cache.size") //block_cache->GetUsage()
+ metricsBlocksdbCachePinnedSize = metrics.NewGauge("neb.rocksdb.cachepinned.size") //block_cache->GetPinnedUsage()
+ metricsBlocksdbTableReaderMem = metrics.NewGauge("neb.rocksdb.tablereader.mem") //estimate-table-readers-mem
+ metricsBlocksdbAllMemTables = metrics.NewGauge("neb.rocksdb.alltables.mem") //cur-size-all-mem-tables
)
diff --git a/storage/rocks_storage.go b/storage/rocks_storage.go
index 7d7105fed..92ec584c4 100644
--- a/storage/rocks_storage.go
+++ b/storage/rocks_storage.go
@@ -1,6 +1,7 @@
package storage
import (
+ "strconv"
"sync"
"time"
@@ -18,6 +19,8 @@ type RocksStorage struct {
ro *gorocksdb.ReadOptions
wo *gorocksdb.WriteOptions
+
+ cache *gorocksdb.Cache
}
// NewRocksStorage init a storage
@@ -26,7 +29,9 @@ func NewRocksStorage(path string) (*RocksStorage, error) {
filter := gorocksdb.NewBloomFilter(10)
bbto := gorocksdb.NewDefaultBlockBasedTableOptions()
bbto.SetFilterPolicy(filter)
- bbto.SetBlockCache(gorocksdb.NewLRUCache(512 << 20))
+
+ cache := gorocksdb.NewLRUCache(512 << 20)
+ bbto.SetBlockCache(cache)
opts := gorocksdb.NewDefaultOptions()
opts.SetBlockBasedTableFactory(bbto)
opts.SetCreateIfMissing(true)
@@ -39,13 +44,18 @@ func NewRocksStorage(path string) (*RocksStorage, error) {
return nil, err
}
- return &RocksStorage{
+ storage := &RocksStorage{
db: db,
+ cache: cache,
enableBatch: false,
batchOpts: make(map[string]*batchOpt),
ro: gorocksdb.NewDefaultReadOptions(),
wo: gorocksdb.NewDefaultWriteOptions(),
- }, nil
+ }
+
+ //go RecordMetrics(storage)
+
+ return storage, nil
}
// Get return value to the key in Storage
@@ -151,3 +161,33 @@ func (storage *RocksStorage) DisableBatch() {
storage.enableBatch = false
}
+
+// RecordMetrics record rocksdb metrics
+func RecordMetrics(storage *RocksStorage) {
+ metricsUpdateChan := time.NewTicker(5 * time.Second).C
+
+ for {
+ select {
+ case <-metricsUpdateChan:
+
+ readersMemStr := storage.db.GetProperty("rocksdb.estimate-table-readers-mem")
+ allMemTablesStr := storage.db.GetProperty("rocksdb.cur-size-all-mem-tables")
+ cacheSize := storage.cache.GetUsage()
+ pinnedSize := storage.cache.GetPinnedUsage()
+
+ readersMem, err := strconv.Atoi(readersMemStr)
+ if err != nil {
+ break
+ }
+ allMemTables, err := strconv.Atoi(allMemTablesStr)
+ if err != nil {
+ break
+ }
+
+ metricsBlocksdbAllMemTables.Update(int64(allMemTables))
+ metricsBlocksdbTableReaderMem.Update(int64(readersMem))
+ metricsBlocksdbCacheSize.Update(int64(cacheSize))
+ metricsBlocksdbCachePinnedSize.Update(int64(pinnedSize))
+ }
+ }
+}
diff --git a/storage/rocks_storage_test.go b/storage/rocks_storage_test.go
index ecbf89c21..20070222f 100644
--- a/storage/rocks_storage_test.go
+++ b/storage/rocks_storage_test.go
@@ -17,7 +17,7 @@ func TestNewRocksStorage(t *testing.T) {
want *RocksStorage
wantErr bool
}{
- // TODO: Add test cases.
+ // TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {