Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
2a7d347d
Unverified
Commit
2a7d347d
authored
Oct 28, 2021
by
Mark Tyneway
Committed by
GitHub
Oct 28, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1645 from cfromknecht/bss-txmgr
feat: add batch-submitter/txmgr for tx publication and gas bumping
parents
fc0616e5
5097797e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
720 additions
and
24 deletions
+720
-24
go.mod
go/batch-submitter/go.mod
+1
-1
go.sum
go/batch-submitter/go.sum
+24
-14
sentry_log.go
go/batch-submitter/sentry_log.go
+13
-9
txmgr.go
go/batch-submitter/txmgr/txmgr.go
+251
-0
txmgr_test.go
go/batch-submitter/txmgr/txmgr_test.go
+431
-0
No files found.
go/batch-submitter/go.mod
View file @
2a7d347d
...
...
@@ -4,7 +4,7 @@ go 1.16
require (
github.com/decred/dcrd/hdkeychain/v3 v3.0.0
github.com/ethereum/go-ethereum v1.10.
8
github.com/ethereum/go-ethereum v1.10.
11
github.com/getsentry/sentry-go v0.11.0
github.com/prometheus/client_golang v1.0.0
github.com/stretchr/testify v1.7.0
...
...
go/batch-submitter/go.sum
View file @
2a7d347d
...
...
@@ -101,6 +101,7 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
...
...
@@ -138,9 +139,10 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.
2.0
/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.
4.1-0.20201116162257-a2a8dda75c91
/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
...
...
@@ -149,8 +151,8 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/go-ethereum v1.10.
8 h1:0UP5WUR8hh46ffbjJV7PK499+uGEyasRIfffS0vy06o
=
github.com/ethereum/go-ethereum v1.10.
8/go.mod h1:pJNuIUYfX5+JKzSD/BTdNsvJSZ1TJqmz0dVyXMAbf6M
=
github.com/ethereum/go-ethereum v1.10.
11 h1:KKIcwpmur9iTaVbR2dxlHu+peHVhU+/KX//NWvT1n9U
=
github.com/ethereum/go-ethereum v1.10.
11/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw
=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
...
...
@@ -185,7 +187,7 @@ github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sourcemap/sourcemap v2.1.
2
+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sourcemap/sourcemap v2.1.
3
+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
...
...
@@ -215,9 +217,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
...
...
@@ -249,6 +251,8 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
...
...
@@ -299,8 +303,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
...
...
@@ -318,11 +321,13 @@ github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPR
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
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/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
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/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
...
...
@@ -358,6 +363,10 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
...
...
@@ -458,8 +467,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.1-0.20210
305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs
=
github.com/syndtr/goleveldb v1.0.1-0.20210
305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM
=
github.com/syndtr/goleveldb v1.0.1-0.20210
819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY
=
github.com/syndtr/goleveldb v1.0.1-0.20210
819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc
=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
...
...
@@ -716,8 +725,9 @@ google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyz
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
...
...
go/batch-submitter/sentry_log.go
View file @
2a7d347d
...
...
@@ -11,18 +11,22 @@ import (
var
jsonFmt
=
log
.
JSONFormat
()
// SentryStreamHandler creates a log.Handler that behaves similarly to
// log.StreamHandler, however it writes any log
levels greater than or equal to
//
LvlError to Sentry. In that case, the passed log.Record is encoded using JSON
//
rather than the default terminal output, so that it can be captured for
// debugging in the Sentry dashboard.
// log.StreamHandler, however it writes any log
with severity greater than or
//
equal to log.LvlError to Sentry. In that case, the passed log.Record is
//
encoded using JSON rather than the default terminal output, so that it can be
//
captured for
debugging in the Sentry dashboard.
func
SentryStreamHandler
(
wr
io
.
Writer
,
fmtr
log
.
Format
)
log
.
Handler
{
h
:=
log
.
FuncHandler
(
func
(
r
*
log
.
Record
)
error
{
_
,
err
:=
wr
.
Write
(
fmtr
.
Format
(
r
))
// If this record is LvlError or higher, serialize the record
// using JSON and write it to Sentry. We also capture the error
// message separately so that it's easy to parse what the error
// is in the dashboard.
if
r
.
Lvl
>=
log
.
LvlError
{
// If this record's severity is log.LvlError or higher,
// serialize the record using JSON and write it to Sentry. We
// also capture the error message separately so that it's easy
// to parse what the error is in the dashboard.
//
// NOTE: The log.Lvl* constants are defined in reverse order of
// their severity, i.e. zero (log.LvlCrit) is the highest
// severity.
if
r
.
Lvl
<=
log
.
LvlError
{
sentry
.
WithScope
(
func
(
scope
*
sentry
.
Scope
)
{
scope
.
SetExtra
(
"context"
,
jsonFmt
.
Format
(
r
))
sentry
.
CaptureException
(
errors
.
New
(
r
.
Msg
))
...
...
go/batch-submitter/txmgr/txmgr.go
0 → 100644
View file @
2a7d347d
package
txmgr
import
(
"context"
"errors"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
// ErrPublishTimeout signals that the tx manager did not receive a confirmation
// for a given tx after publishing with the maximum gas price and waiting out a
// resubmission timeout.
var
ErrPublishTimeout
=
errors
.
New
(
"failed to publish tx with max gas price"
)
// SendTxFunc defines a function signature for publishing a desired tx with a
// specific gas price. Implementations of this signature should also return
// promptly when the context is canceled.
type
SendTxFunc
=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
)
(
*
types
.
Transaction
,
error
)
// Config houses parameters for altering the behavior of a SimpleTxManager.
type
Config
struct
{
// MinGasPrice is the minimum gas price (in gwei). This is used as the
// initial publication attempt.
MinGasPrice
*
big
.
Int
// MaxGasPrice is the maximum gas price (in gwei). This is used to clamp
// the upper end of the range that the TxManager will ever publish when
// attempting to confirm a transaction.
MaxGasPrice
*
big
.
Int
// GasRetryIncrement is the additive gas price (in gwei) that will be
// used to bump each successive tx after a ResubmissionTimeout has
// elapsed.
GasRetryIncrement
*
big
.
Int
// ResubmissionTimeout is the interval at which, if no previously
// published transaction has been mined, the new tx with a bumped gas
// price will be published. Only one publication at MaxGasPrice will be
// attempted.
ResubmissionTimeout
time
.
Duration
// RequireQueryInterval is the interval at which the tx manager will
// query the backend to check for confirmations after a tx at a
// specific gas price has been published.
ReceiptQueryInterval
time
.
Duration
}
// TxManager is an interface that allows callers to reliably publish txs,
// bumping the gas price if needed, and obtain the receipt of the resulting tx.
type
TxManager
interface
{
// Send is used to publish a transaction with incrementally higher gas
// prices until the transaction eventually confirms. This method blocks
// until an invocation of sendTx returns (called with differing gas
// prices). The method may be canceled using the passed context.
//
// NOTE: Send should be called by AT MOST one caller at a time.
Send
(
ctx
context
.
Context
,
sendTx
SendTxFunc
)
(
*
types
.
Receipt
,
error
)
}
// ReceiptSource is a minimal function signature used to detect the confirmation
// of published txs.
//
// NOTE: This is a subset of bind.DeployBackend.
type
ReceiptSource
interface
{
// TransactionReceipt queries the backend for a receipt associated with
// txHash. If lookup does not fail, but the transaction is not found,
// nil should be returned for both values.
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
}
// SimpleTxManager is a implementation of TxManager that performs linear fee
// bumping of a tx until it confirms.
type
SimpleTxManager
struct
{
cfg
Config
backend
ReceiptSource
}
// NewSimpleTxManager initializes a new SimpleTxManager with the passed Config.
func
NewSimpleTxManager
(
cfg
Config
,
backend
ReceiptSource
)
*
SimpleTxManager
{
return
&
SimpleTxManager
{
cfg
:
cfg
,
backend
:
backend
,
}
}
// Send is used to publish a transaction with incrementally higher gas prices
// until the transaction eventually confirms. This method blocks until an
// invocation of sendTx returns (called with differing gas prices). The method
// may be canceled using the passed context.
//
// NOTE: Send should be called by AT MOST one caller at a time.
func
(
m
*
SimpleTxManager
)
Send
(
ctx
context
.
Context
,
sendTx
SendTxFunc
)
(
*
types
.
Receipt
,
error
)
{
// Initialize a wait group to track any spawned goroutines, and ensure
// we properly clean up any dangling resources this method generates.
// We assert that this is the case thoroughly in our unit tests.
var
wg
sync
.
WaitGroup
defer
wg
.
Wait
()
// Initialize a subcontext for the goroutines spawned in this process.
// The defer to cancel is done here (in reverse order of Wait) so that
// the goroutines can exit before blocking on the wait group.
ctxc
,
cancel
:=
context
.
WithCancel
(
ctx
)
defer
cancel
()
// Create a closure that will block on passed sendTx function in the
// background, returning the first successfully mined receipt back to
// the main event loop via receiptChan.
receiptChan
:=
make
(
chan
*
types
.
Receipt
,
1
)
sendTxAsync
:=
func
(
gasPrice
*
big
.
Int
)
{
defer
wg
.
Done
()
// Sign and publish transaction with current gas price.
tx
,
err
:=
sendTx
(
ctxc
,
gasPrice
)
if
err
!=
nil
{
log
.
Error
(
"Unable to publish transaction"
,
"gas_price"
,
gasPrice
,
"err"
,
err
)
// TODO(conner): add retry?
return
}
txHash
:=
tx
.
Hash
()
log
.
Info
(
"Transaction published successfully"
,
"hash"
,
txHash
,
"gas_price"
,
gasPrice
)
// Wait for the transaction to be mined, reporting the receipt
// back to the main event loop if found.
receipt
,
err
:=
WaitMined
(
ctxc
,
m
.
backend
,
tx
,
m
.
cfg
.
ReceiptQueryInterval
,
)
if
err
!=
nil
{
log
.
Trace
(
"Send tx failed"
,
"hash"
,
txHash
,
"gas_price"
,
gasPrice
,
"err"
,
err
)
}
if
receipt
!=
nil
{
// Use non-blocking select to ensure function can exit
// if more than one receipt is discovered.
select
{
case
receiptChan
<-
receipt
:
log
.
Trace
(
"Send tx succeeded"
,
"hash"
,
txHash
,
"gas_price"
,
gasPrice
)
default
:
}
}
}
// Initialize our initial gas price to the configured minimum.
curGasPrice
:=
new
(
big
.
Int
)
.
Set
(
m
.
cfg
.
MinGasPrice
)
// Submit and wait for the receipt at our first gas price in the
// background, before entering the event loop and waiting out the
// resubmission timeout.
wg
.
Add
(
1
)
go
sendTxAsync
(
curGasPrice
)
for
{
select
{
// Whenever a resubmission timeout has elapsed, bump the gas
// price and publish a new transaction.
case
<-
time
.
After
(
m
.
cfg
.
ResubmissionTimeout
)
:
// If our last attempt published at the max gas price,
// return an error as we are unlikely to succeed in
// publishing. This also indicates that the max gas
// price should likely be adjusted higher for the
// daemon.
if
curGasPrice
.
Cmp
(
m
.
cfg
.
MaxGasPrice
)
>=
0
{
return
nil
,
ErrPublishTimeout
}
// Bump the gas price using linear gas price increments.
curGasPrice
=
NextGasPrice
(
curGasPrice
,
m
.
cfg
.
GasRetryIncrement
,
m
.
cfg
.
MaxGasPrice
,
)
// Submit and wait for the bumped traction to confirm.
wg
.
Add
(
1
)
go
sendTxAsync
(
curGasPrice
)
// The passed context has been canceled, i.e. in the event of a
// shutdown.
case
<-
ctxc
.
Done
()
:
return
nil
,
ctxc
.
Err
()
// The transaction has confirmed.
case
receipt
:=
<-
receiptChan
:
return
receipt
,
nil
}
}
}
// WaitMined blocks until the backend indicates confirmation of tx and returns
// the tx receipt. Queries are made every queryInterval, regardless of whether
// the backend returns an error. This method can be canceled using the passed
// context.
func
WaitMined
(
ctx
context
.
Context
,
backend
ReceiptSource
,
tx
*
types
.
Transaction
,
queryInterval
time
.
Duration
,
)
(
*
types
.
Receipt
,
error
)
{
queryTicker
:=
time
.
NewTicker
(
queryInterval
)
defer
queryTicker
.
Stop
()
txHash
:=
tx
.
Hash
()
for
{
receipt
,
err
:=
backend
.
TransactionReceipt
(
ctx
,
txHash
)
if
receipt
!=
nil
{
return
receipt
,
nil
}
if
err
!=
nil
{
log
.
Trace
(
"Receipt retrievel failed"
,
"hash"
,
txHash
,
"err"
,
err
)
}
else
{
log
.
Trace
(
"Transaction not yet mined"
,
"hash"
,
txHash
)
}
select
{
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
case
<-
queryTicker
.
C
:
}
}
}
// NextGasPrice bumps the current gas price using an additive gasRetryIncrement,
// clamping the resulting value to maxGasPrice.
//
// NOTE: This method does not mutate curGasPrice, but instead returns a copy.
// This removes the possiblity of races occuring from goroutines sharing access
// to the same underlying big.Int.
func
NextGasPrice
(
curGasPrice
,
gasRetryIncrement
,
maxGasPrice
*
big
.
Int
)
*
big
.
Int
{
nextGasPrice
:=
new
(
big
.
Int
)
.
Set
(
curGasPrice
)
nextGasPrice
.
Add
(
nextGasPrice
,
gasRetryIncrement
)
if
nextGasPrice
.
Cmp
(
maxGasPrice
)
==
1
{
nextGasPrice
.
Set
(
maxGasPrice
)
}
return
nextGasPrice
}
go/batch-submitter/txmgr/txmgr_test.go
0 → 100644
View file @
2a7d347d
package
txmgr_test
import
(
"context"
"errors"
"math/big"
"sync"
"testing"
"time"
"github.com/ethereum-optimism/go/batch-submitter/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
// TestNextGasPrice asserts that NextGasPrice properly bumps the passed current
// gas price, and clamps it to the max gas price. It also tests that
// NextGasPrice doesn't mutate the passed curGasPrice argument.
func
TestNextGasPrice
(
t
*
testing
.
T
)
{
t
.
Parallel
()
tests
:=
[]
struct
{
name
string
curGasPrice
*
big
.
Int
gasRetryIncrement
*
big
.
Int
maxGasPrice
*
big
.
Int
expGasPrice
*
big
.
Int
}{
{
name
:
"increment below max"
,
curGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
5
),
gasRetryIncrement
:
new
(
big
.
Int
)
.
SetUint64
(
10
),
maxGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
20
),
expGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
15
),
},
{
name
:
"increment equal max"
,
curGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
5
),
gasRetryIncrement
:
new
(
big
.
Int
)
.
SetUint64
(
10
),
maxGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
15
),
expGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
15
),
},
{
name
:
"increment above max"
,
curGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
5
),
gasRetryIncrement
:
new
(
big
.
Int
)
.
SetUint64
(
10
),
maxGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
12
),
expGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
12
),
},
}
for
_
,
test
:=
range
tests
{
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
// Copy curGasPrice, as we will later test for mutation.
curGasPrice
:=
new
(
big
.
Int
)
.
Set
(
test
.
curGasPrice
)
nextGasPrice
:=
txmgr
.
NextGasPrice
(
curGasPrice
,
test
.
gasRetryIncrement
,
test
.
maxGasPrice
,
)
require
.
Equal
(
t
,
nextGasPrice
,
test
.
expGasPrice
)
// Ensure curGasPrice hasn't been mutated. This check
// enforces that NextGasPrice creates a copy internally.
// Failure to do so could result in gas price bumps
// being read concurrently from other goroutines, and
// introduce race conditions.
require
.
Equal
(
t
,
curGasPrice
,
test
.
curGasPrice
)
})
}
}
// testHarness houses the necessary resources to test the SimpleTxManager.
type
testHarness
struct
{
cfg
txmgr
.
Config
mgr
txmgr
.
TxManager
backend
*
mockBackend
}
// newTestHarnessWithConfig initializes a testHarness with a specific
// configuration.
func
newTestHarnessWithConfig
(
cfg
txmgr
.
Config
)
*
testHarness
{
backend
:=
newMockBackend
()
mgr
:=
txmgr
.
NewSimpleTxManager
(
cfg
,
backend
)
return
&
testHarness
{
cfg
:
cfg
,
mgr
:
mgr
,
backend
:
backend
,
}
}
// newTestHarness initializes a testHarness with a defualt configuration that is
// suitable for most tests.
func
newTestHarness
()
*
testHarness
{
return
newTestHarnessWithConfig
(
txmgr
.
Config
{
MinGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
5
),
MaxGasPrice
:
new
(
big
.
Int
)
.
SetUint64
(
50
),
GasRetryIncrement
:
new
(
big
.
Int
)
.
SetUint64
(
5
),
ResubmissionTimeout
:
time
.
Second
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
})
}
// mockBackend implements txmgr.ReceiptSource that tracks mined transactions
// along with the gas price used.
type
mockBackend
struct
{
mu
sync
.
RWMutex
// txHashMinedWithGasPrice tracks the has of a mined transaction to its
// gas price.
txHashMinedWithGasPrice
map
[
common
.
Hash
]
*
big
.
Int
}
// newMockBackend initializes a new mockBackend.
func
newMockBackend
()
*
mockBackend
{
return
&
mockBackend
{
txHashMinedWithGasPrice
:
make
(
map
[
common
.
Hash
]
*
big
.
Int
),
}
}
// mine records a (txHash, gasPrice) as confirmed. Subsequent calls to
// TransactionReceipt with a matching txHash will result in a non-nil receipt.
func
(
b
*
mockBackend
)
mine
(
txHash
common
.
Hash
,
gasPrice
*
big
.
Int
)
{
b
.
mu
.
Lock
()
defer
b
.
mu
.
Unlock
()
b
.
txHashMinedWithGasPrice
[
txHash
]
=
gasPrice
}
// TransactionReceipt queries the mockBackend for a mined txHash. If none is
// found, nil is returned for both return values. Otherwise, it retruns a
// receipt containing the txHash and the gasPrice used in the GasUsed to make
// the value accessible from our test framework.
func
(
b
*
mockBackend
)
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
,
)
(
*
types
.
Receipt
,
error
)
{
b
.
mu
.
RLock
()
defer
b
.
mu
.
RUnlock
()
gasPrice
,
ok
:=
b
.
txHashMinedWithGasPrice
[
txHash
]
if
!
ok
{
return
nil
,
nil
}
// Return the gas price for the transaction in the GasUsed field so that
// we can assert the proper tx confirmed in our tests.
return
&
types
.
Receipt
{
TxHash
:
txHash
,
GasUsed
:
gasPrice
.
Uint64
(),
},
nil
}
// TestTxMgrConfirmAtMinGasPrice asserts that Send returns the min gas price tx
// if the tx is mined instantly.
func
TestTxMgrConfirmAtMinGasPrice
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
})
h
.
backend
.
mine
(
tx
.
Hash
(),
gasPrice
)
return
tx
,
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
GasUsed
,
h
.
cfg
.
MinGasPrice
.
Uint64
())
}
// TestTxMgrNeverConfirmCancel asserts that a Send can be canceled even if no
// transaction is mined. This is done to ensure the the tx mgr can properly
// abort on shutdown, even if a txn is in the process of being published.
func
TestTxMgrNeverConfirmCancel
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
// Don't publish tx to backend, simulating never being mined.
return
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
}),
nil
}
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
defer
cancel
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Equal
(
t
,
err
,
context
.
DeadlineExceeded
)
require
.
Nil
(
t
,
receipt
)
}
// TestTxMgrConfirmsAtMaxGasPrice asserts that Send properly returns the max gas
// price receipt if none of the lower gas price txs were mined.
func
TestTxMgrConfirmsAtMaxGasPrice
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
})
if
gasPrice
.
Cmp
(
h
.
cfg
.
MaxGasPrice
)
==
0
{
h
.
backend
.
mine
(
tx
.
Hash
(),
gasPrice
)
}
return
tx
,
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
GasUsed
,
h
.
cfg
.
MaxGasPrice
.
Uint64
())
}
// TestTxMgrConfirmsAtMaxGasPriceDelayed asserts that after the maximum gas
// price tx has been published, and a resubmission timeout has elapsed, that an
// error is returned signaling that even our max gas price is taking too long.
func
TestTxMgrConfirmsAtMaxGasPriceDelayed
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
})
// Delay mining of the max gas price tx by more than the
// resubmission timeout. Default config uses 1 second. Send
// should still return an error beforehand.
if
gasPrice
.
Cmp
(
h
.
cfg
.
MaxGasPrice
)
==
0
{
time
.
AfterFunc
(
2
*
time
.
Second
,
func
()
{
h
.
backend
.
mine
(
tx
.
Hash
(),
gasPrice
)
})
}
return
tx
,
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Equal
(
t
,
err
,
txmgr
.
ErrPublishTimeout
)
require
.
Nil
(
t
,
receipt
)
}
// errRpcFailure is a sentinel error used in testing to fail publications.
var
errRpcFailure
=
errors
.
New
(
"rpc failure"
)
// TestTxMgrBlocksOnFailingRpcCalls asserts that if all of the publication
// attempts fail due to rpc failures, that the tx manager will return
// txmgr.ErrPublishTimeout.
func
TestTxMgrBlocksOnFailingRpcCalls
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
return
nil
,
errRpcFailure
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Equal
(
t
,
err
,
txmgr
.
ErrPublishTimeout
)
require
.
Nil
(
t
,
receipt
)
}
// TestTxMgrOnlyOnePublicationSucceeds asserts that the tx manager will return a
// receipt so long as at least one of the publications is able to succeed with a
// simulated rpc failure.
func
TestTxMgrOnlyOnePublicationSucceeds
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
// Fail all but the final attempt.
if
gasPrice
.
Cmp
(
h
.
cfg
.
MaxGasPrice
)
!=
0
{
return
nil
,
errRpcFailure
}
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
})
h
.
backend
.
mine
(
tx
.
Hash
(),
gasPrice
)
return
tx
,
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
GasUsed
,
h
.
cfg
.
MaxGasPrice
.
Uint64
())
}
// TestTxMgrConfirmsMinGasPriceAfterBumping delays the mining of the initial tx
// with the minimum gas price, and asserts that it's receipt is returned even
// though if the gas price has been bumped in other goroutines.
func
TestTxMgrConfirmsMinGasPriceAfterBumping
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
sendTxFunc
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{
GasPrice
:
gasPrice
,
})
// Delay mining the tx with the min gas price.
if
gasPrice
.
Cmp
(
h
.
cfg
.
MinGasPrice
)
==
0
{
time
.
AfterFunc
(
5
*
time
.
Second
,
func
()
{
h
.
backend
.
mine
(
tx
.
Hash
(),
gasPrice
)
})
}
return
tx
,
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
sendTxFunc
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
GasUsed
,
h
.
cfg
.
MinGasPrice
.
Uint64
())
}
// TestWaitMinedReturnsReceiptOnFirstSuccess insta-mines a transaction and
// asserts that WaitMined returns the appropriate receipt.
func
TestWaitMinedReturnsReceiptOnFirstSuccess
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
// Create a tx and mine it immediately using the default backend.
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{})
txHash
:=
tx
.
Hash
()
h
.
backend
.
mine
(
txHash
,
new
(
big
.
Int
))
ctx
:=
context
.
Background
()
receipt
,
err
:=
txmgr
.
WaitMined
(
ctx
,
h
.
backend
,
tx
,
50
*
time
.
Millisecond
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
TxHash
,
txHash
)
}
// TestWaitMinedCanBeCanceled ensures that WaitMined exits of the passed context
// is canceled before a receipt is found.
func
TestWaitMinedCanBeCanceled
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
defer
cancel
()
// Create an unimined tx.
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{})
receipt
,
err
:=
txmgr
.
WaitMined
(
ctx
,
h
.
backend
,
tx
,
50
*
time
.
Millisecond
)
require
.
Equal
(
t
,
err
,
context
.
DeadlineExceeded
)
require
.
Nil
(
t
,
receipt
)
}
// failingBackend implements txmgr.ReceiptSource, returning a failure on the
// first call but a success on the second call. This allows us to test that the
// inner loop of WaitMined properly handles this case.
type
failingBackend
struct
{
returnSuccess
bool
}
// TransactionReceipt for the failingBackend returns errRpcFailure on the first
// invocation, and a receipt containing the passed TxHash on the second.
func
(
b
*
failingBackend
)
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
if
!
b
.
returnSuccess
{
b
.
returnSuccess
=
true
return
nil
,
errRpcFailure
}
return
&
types
.
Receipt
{
TxHash
:
txHash
,
},
nil
}
// TestWaitMinedReturnsReceiptAfterFailure asserts that WaitMined is able to
// recover from failed calls to the backend. It uses the failedBackend to
// simulate an rpc call failure, followed by the successful return of a receipt.
func
TestWaitMinedReturnsReceiptAfterFailure
(
t
*
testing
.
T
)
{
t
.
Parallel
()
var
borkedBackend
failingBackend
// Don't mine the tx with the default backend. The failingBackend will
// return the txHash on the second call.
tx
:=
types
.
NewTx
(
&
types
.
LegacyTx
{})
txHash
:=
tx
.
Hash
()
ctx
:=
context
.
Background
()
receipt
,
err
:=
txmgr
.
WaitMined
(
ctx
,
&
borkedBackend
,
tx
,
50
*
time
.
Millisecond
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
receipt
.
TxHash
,
txHash
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment