diff --git a/go.mod b/go.mod index 5aff3a4c..0efcbf6d 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,14 @@ module github.com/eoscanada/eos-go go 1.22 require ( - github.com/jarcoal/httpmock v1.2.0 - github.com/pkg/errors v0.9.1 + github.com/jarcoal/httpmock v1.3.1 github.com/streamingfast/cli v0.0.3 github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 github.com/streamingfast/validator v0.0.0-20231124184318-71ec8080e4ae - github.com/stretchr/testify v1.7.0 - github.com/test-go/testify v1.1.4 + github.com/stretchr/testify v1.9.0 github.com/thedevsaddam/govalidator v1.9.10 - github.com/tidwall/gjson v1.9.3 - go.uber.org/zap v1.21.0 + github.com/tidwall/gjson v1.17.3 + go.uber.org/zap v1.27.0 golang.org/x/crypto v0.1.0 ) @@ -34,9 +32,8 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/multierr v1.10.0 // indirect golang.org/x/sys v0.1.0 // indirect golang.org/x/term v0.1.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2fba969a..512d4b73 100644 --- a/go.sum +++ b/go.sum @@ -19,7 +19,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -101,8 +100,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc= -github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk= +github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= +github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -117,8 +116,9 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= @@ -134,8 +134,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk= -github.com/maxatome/go-testdeep v1.11.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70= +github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= +github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -155,8 +155,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -200,16 +198,17 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/thedevsaddam/govalidator v1.9.6/go.mod h1:Ilx8u7cg5g3LXbSS943cx5kczyNuUn7LH/cK5MYuE90= github.com/thedevsaddam/govalidator v1.9.10 h1:m3dLRbSZ5Hts3VUWYe+vxLMG+FdyQuWOjzTeQRiMCvU= github.com/thedevsaddam/govalidator v1.9.10/go.mod h1:Ilx8u7cg5g3LXbSS943cx5kczyNuUn7LH/cK5MYuE90= -github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E= -github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -222,19 +221,21 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -378,11 +379,11 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/name.go b/name.go index b53a6a1c..cbd88d4e 100644 --- a/name.go +++ b/name.go @@ -80,8 +80,8 @@ var base32Alphabet = []byte(".12345abcdefghijklmnopqrstuvwxyz") var eosioNameUint64 = uint64(6138663577826885632) var eosioTokenNameUint64 = uint64(6138663591592764928) var cachedNames = map[uint64]string{ - 6138663577826885632: "eosio", - 6138663591592764928: "eosio.token", + eosioNameUint64: "eosio", + eosioTokenNameUint64: "eosio.token", } func NameToString(in uint64) string { diff --git a/p2p/peer.go b/p2p/peer.go index a69bc671..bb868e73 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -13,7 +13,6 @@ import ( "github.com/eoscanada/eos-go" "github.com/eoscanada/eos-go/ecc" - "github.com/pkg/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -213,7 +212,7 @@ func (p *Peer) SendSyncRequest(startBlockNum uint32, endBlockNumber uint32) (err EndBlock: endBlockNumber, } - return errors.WithStack(p.WriteP2PMessage(syncRequest)) + return p.WriteP2PMessage(syncRequest) } func (p *Peer) SendRequest(startBlockNum uint32, endBlockNumber uint32) (err error) { zlog.Debug("SendRequest", @@ -232,7 +231,7 @@ func (p *Peer) SendRequest(startBlockNum uint32, endBlockNumber uint32) (err err }, } - return errors.WithStack(p.WriteP2PMessage(request)) + return p.WriteP2PMessage(request) } func (p *Peer) SendNotice(headBlockNum uint32, libNum uint32, mode byte) error { @@ -253,14 +252,14 @@ func (p *Peer) SendNotice(headBlockNum uint32, libNum uint32, mode byte) error { }, } - return errors.WithStack(p.WriteP2PMessage(notice)) + return p.WriteP2PMessage(notice) } func (p *Peer) SendTime() error { zlog.Debug("SendTime", zap.String("peer", p.Address)) notice := &eos.TimeMessage{} - return errors.WithStack(p.WriteP2PMessage(notice)) + return p.WriteP2PMessage(notice) } func (p *Peer) SendHandshake(info *HandshakeInfo) error { diff --git a/validator.go b/validator.go new file mode 100644 index 00000000..77c2f518 --- /dev/null +++ b/validator.go @@ -0,0 +1,130 @@ +package eos + +import ( + "fmt" + "regexp" + "strconv" + "strings" + + "github.com/streamingfast/validator" + "github.com/thedevsaddam/govalidator" +) + +func init() { + govalidator.AddCustomRule("eos.blockNum", EOSBlockNumRule) + govalidator.AddCustomRule("eos.name", EOSNameRule) +} + +func EOSBlockNumRule(field string, rule string, message string, value interface{}) error { + val, ok := value.(string) + if !ok { + return fmt.Errorf("The %s field must be a string", field) + } + + _, err := strconv.ParseInt(val, 10, 64) + if err != nil { + return fmt.Errorf("The %s field must be a valid EOS block num", field) + } + + return nil +} + +func EOSNameRule(field string, rule string, message string, value interface{}) error { + checkName := func(field string, name string) error { + if !IsValidName(name) { + return fmt.Errorf("The %s field must be a valid EOS name", field) + } + + return nil + } + + switch v := value.(type) { + case string: + return checkName(field, v) + case Name, PermissionName, ActionName, AccountName, TableName: + return checkName(field, fmt.Sprintf("%s", v)) + default: + return fmt.Errorf("The %s field is not a known type for an EOS name", field) + } +} + +func EOSExtendedNameRule(field string, rule string, message string, value interface{}) error { + checkName := func(field string, name string) error { + if !IsValidExtendedName(name) { + return fmt.Errorf("The %s field must be a valid EOS name", field) + } + + return nil + } + + switch v := value.(type) { + case string: + return checkName(field, v) + case Symbol: + return checkName(field, v.String()) + case SymbolCode: + return checkName(field, v.String()) + case Name, PermissionName, ActionName, AccountName, TableName: + return checkName(field, fmt.Sprintf("%s", v)) + default: + return fmt.Errorf("The %s field is not a known type for an EOS name", field) + } +} + +func EOSNamesListRuleFactory(sep string, maxCount int) validator.Rule { + return validator.StringListRuleFactory(sep, maxCount, EOSNameRule) +} + +func EOSExtendedNamesListRuleFactory(sep string, maxCount int) validator.Rule { + return validator.StringListRuleFactory(sep, maxCount, EOSExtendedNameRule) +} + +func EOSTrxIDRule(field string, rule string, message string, value interface{}) error { + err := validator.HexRule(field, rule, message, value) + if err != nil { + return err + } + + val := value.(string) + if len(val) != 64 { + return fmt.Errorf("The %s field must have exactly 64 characters", field) + } + + return nil +} + +var symbolRegexp = regexp.MustCompile(`^[0-9],[A-Z]{1,7}$`) +var symbolCodeRegexp = regexp.MustCompile(`^[A-Z]{1,7}$`) +var nameRegexp = regexp.MustCompile(`^[\.a-z1-5]{0,13}$`) + +func ExplodeNames(input string, sep string) (names []string) { + rawNames := strings.Split(input, sep) + for _, rawName := range rawNames { + account := strings.TrimSpace(rawName) + if account == "" { + continue + } + + names = append(names, rawName) + } + + return +} + +func IsValidName(input string) bool { + // An empty string name means a uint64 transformed name with a 0 value + if input == "" { + return true + } + + return nameRegexp.MatchString(input) +} + +func IsValidExtendedName(input string) bool { + // An empty string name means a uint64 transformed name with a 0 value + if input == "" { + return true + } + + return nameRegexp.MatchString(input) || symbolCodeRegexp.MatchString(input) || symbolRegexp.MatchString(input) +} diff --git a/validator_test.go b/validator_test.go new file mode 100644 index 00000000..8c458a55 --- /dev/null +++ b/validator_test.go @@ -0,0 +1,164 @@ +package eos + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +type ruleTestCase struct { + name string + value interface{} + expectedError string +} + +func TestEOSBlockNumRule(t *testing.T) { + tag := "eos_block_num" + validator := func(field string, value interface{}) error { + return EOSBlockNumRule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field must be a string"}, + {"should not contains invalid characters", "!", "The test field must be a valid EOS block num"}, + + {"valid block num", "10", ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func TestEOSNameRule(t *testing.T) { + tag := "eos_name" + validator := func(field string, value interface{}) error { + return EOSNameRule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field is not a known type for an EOS name"}, + {"should not contains invalid characters", "6", "The test field must be a valid EOS name"}, + {"should not be longer than 13", "abcdefghigklma", "The test field must be a valid EOS name"}, + + {"valid empty", "", ""}, + {"valid single", "e", ""}, + {"valid limit", "5", ""}, + {"valid with dots and 13 chars", "eosio.tokenfl", ""}, + {"valid eos.Name", Name("eosio"), ""}, + {"valid eos.PermissionName", PermissionName("eosio"), ""}, + {"valid eos.ActionName", ActionName("eosio"), ""}, + {"valid eos.AccountName", AccountName("eosio"), ""}, + {"valid eos.TableName", TableName("eosio"), ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func TestEOSExtendedNameRule(t *testing.T) { + tag := "eos_extended_name" + validator := func(field string, value interface{}) error { + return EOSExtendedNameRule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field is not a known type for an EOS name"}, + {"should not contains invalid characters", "6", "The test field must be a valid EOS name"}, + {"should not be longer than 13", "abcdefghigklma", "The test field must be a valid EOS name"}, + + {"valid empty", "", ""}, + {"valid single", "e", ""}, + {"valid limit", "5", ""}, + {"valid with dots and 13 chars", "eosio.tokenfl", ""}, + {"valid with whem symbol", "4,EOS", ""}, + {"valid with whem symbol code", "EOS", ""}, + + {"valid eos.Name", Name("eosio"), ""}, + {"valid eos.PermissionName", PermissionName("eosio"), ""}, + {"valid eos.ActionName", ActionName("eosio"), ""}, + {"valid eos.AccountName", AccountName("eosio"), ""}, + {"valid eos.TableName", TableName("eosio"), ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func TestEOSNamesListRule(t *testing.T) { + tag := "eos_names_list" + rule := EOSNamesListRuleFactory("|", 2) + validator := func(field string, value interface{}) error { + return rule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field must be a string"}, + {"should have at least 1 element", "", "The test field must have at least 1 element"}, + {"should have at max macCount element", "eos|eos|eos", "The test field must have at most 2 elements"}, + {"should fail on single error", "6", "The test[0] field must be a valid EOS name"}, + {"should fail if any element error", "ab|6", "The test[1] field must be a valid EOS name"}, + + {"valid single", "ab", ""}, + {"valid multiple", "ded|eos", ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func TestEOSExtendedNamesListRule(t *testing.T) { + tag := "eos_extended_names_list" + rule := EOSExtendedNamesListRuleFactory("|", 3) + validator := func(field string, value interface{}) error { + return rule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field must be a string"}, + {"should have at least 1 element", "", "The test field must have at least 1 element"}, + {"should have at max macCount element", "eos|eos|eos|eos", "The test field must have at most 3 elements"}, + {"should fail on single error", "6", "The test[0] field must be a valid EOS name"}, + {"should fail if any element error", "ab|6", "The test[1] field must be a valid EOS name"}, + + {"valid single", "ab", ""}, + {"valid multiple", "ded|eos", ""}, + {"valid multiple symbol", "ded|eos|EOS", ""}, + {"valid multiple symbol code", "ded|4,EOS", ""}, + {"valid multiple mixed", "ded|EOS|4,EOS", ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func TestEOSTrxIDRule(t *testing.T) { + tag := "eos_trx_id" + validator := func(field string, value interface{}) error { + return EOSTrxIDRule(field, tag, "", value) + } + + tests := []ruleTestCase{ + {"should be a string", true, "The test field must be a string"}, + {"should contains something", "", "The test field must be a valid hexadecimal"}, + {"should contains a least two characters", "a", "The test field must be a valid hexadecimal"}, + {"should not contains invalid characters", "az", "The test field must be a valid hexadecimal"}, + {"should be a multple of 2", "ab01020", "The test field must be a valid hexadecimal"}, + {"should be long enough", "d8fe02221408fbcc221d1207c1b8cc67e0d9b3ca1c6005a36ea10428dd7fd1", "The test field must have exactly 64 characters"}, + + {"valid", "d8fe02221408fbcc221d1207c1b8cc67e0d9b3ca1c6005a36ea10428dd7fd148", ""}, + {"valid", "D8FE02221408FBCC221D1207C1B8CC67E0D9B3CA1C6005A36EA10428DD7FD148", ""}, + } + + runRuleTestCases(t, tag, tests, validator) +} + +func runRuleTestCases(t *testing.T, tag string, tests []ruleTestCase, validator func(field string, value interface{}) error) { + for _, test := range tests { + t.Run(fmt.Sprintf("%s_%s", tag, test.name), func(t *testing.T) { + err := validator("test", test.value) + + if test.expectedError == "" { + assert.NoError(t, err) + } else { + assert.Equal(t, errors.New(test.expectedError), err) + } + }) + } +}