From ffa9f10fbb8da5d60f3eed29107ff7c5432db9cc Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 11 Jan 2022 00:39:23 +0100 Subject: [PATCH 1/5] ref impl: implement rollup node main process, connect to sources/engines, starts drivers, handle shutdown --- go.sum | 19 ++++ opnode/node/node.go | 220 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 238 insertions(+), 1 deletion(-) diff --git a/go.sum b/go.sum index 044d42ce4f0d..05182a2c2353 100644 --- a/go.sum +++ b/go.sum @@ -103,17 +103,20 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r 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/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 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/ethereum-optimism/reference-optimistic-geth v0.0.0-20220107224313-7f6d88bc156a h1:ifL2rtsPv8plDlAucTQdLecBgLWph9HeXA0CHDKpxIE= github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220107224313-7f6d88bc156a/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= @@ -177,6 +180,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -185,15 +189,18 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 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/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= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -209,6 +216,7 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -252,12 +260,14 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= @@ -265,7 +275,9 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +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-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -317,8 +329,10 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/protolambda/ask v0.1.2 h1:BSQP7VDmh+L0lLFjEYUMrTnb2SwdT64UY3vXqDuIIok= github.com/protolambda/ask v0.1.2/go.mod h1:7WB3T4BXZhKUaDcEjF7Ksgi7HCrBDxM37gyM1EhwkmM= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= @@ -334,6 +348,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= @@ -352,6 +367,7 @@ github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -443,6 +459,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -496,6 +513,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -584,6 +602,7 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= 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= diff --git a/opnode/node/node.go b/opnode/node/node.go index 6d8d7858152e..9e338d576dd7 100644 --- a/opnode/node/node.go +++ b/opnode/node/node.go @@ -1,8 +1,69 @@ package node -import "context" +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimistic-specs/opnode/eth" + + "github.com/ethereum-optimism/optimistic-specs/opnode/l1" + "github.com/ethereum-optimism/optimistic-specs/opnode/l2" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum/go-ethereum/ethclient" + + "github.com/ethereum/go-ethereum/rpc" +) + +type GenesisConf struct { + L2Hash common.Hash `ask:"--l2-hash" help:"Genesis block hash of L2"` + L1Hash common.Hash `ask:"--l1-hash" help:"Block hash of L1 after (not incl.) which L1 starts deriving blocks"` + L1Num uint64 `ask:"--l1-num" help:"Block number of L1 matching the l1-hash"` +} + +func (conf *GenesisConf) GetGenesis() l2.Genesis { + return l2.Genesis{ + L1: eth.BlockID{Hash: conf.L1Hash, Number: conf.L1Num}, + // TODO: if we start from a squashed snapshot we might have a non-zero L2 genesis number + L2: eth.BlockID{Hash: conf.L2Hash, Number: 0}, + } +} type OpNodeCmd struct { + L1NodeAddrs []string `ask:"--l1" help:"Addresses of L1 User JSON-RPC endpoints to use (eth namespace required)"` + L2EngineAddrs []string `ask:"--l2" help:"Addresses of L2 Engine JSON-RPC endpoints to use (engine and eth namespace required)"` + + LogCmd `ask:".log" help:"Log configuration"` + + Genesis GenesisConf `ask:".genesis" help:"Genesis anchor point"` + + // during later sequencer rollup implementation: + // TODO: multi-addrs option (static peers) + // TODO: bootnodes option (bootstrap discovery of more peers) + + log log.Logger + + // (combined) source to fetch data from + l1Source eth.L1Source + + // engines to keep synced + l2Engines []*l2.EngineDriver + + l1Downloader l1.Downloader + + ctx context.Context + close chan chan error +} + +func (c *OpNodeCmd) Default() { + c.L1NodeAddrs = []string{"http://127.0.0.1:8545"} + c.L2EngineAddrs = []string{"http://127.0.0.1:8551"} } func (c *OpNodeCmd) Help() string { @@ -10,9 +71,166 @@ func (c *OpNodeCmd) Help() string { } func (c *OpNodeCmd) Run(ctx context.Context, args ...string) error { + logger := c.LogCmd.Create() + c.log = logger + c.ctx = ctx + + if c.Genesis == (GenesisConf{}) { + return errors.New("genesis configuration required") + } + + l1Sources := make([]eth.L1Source, 0, len(c.L1NodeAddrs)) + for i, addr := range c.L1NodeAddrs { + // L1 exec engine: read-only, to update L2 consensus with + l1Node, err := rpc.DialContext(ctx, addr) + if err != nil { + // HTTP or WS RPC may create a disconnected client, RPC over IPC may fail directly + if l1Node == nil { + return fmt.Errorf("failed to dial L1 address %d (%s): %v", i, addr, err) + } + c.log.Warn("failed to dial L1 address, but may connect later", "i", i, "addr", addr, "err", err) + } + // TODO: we may need to authenticate the connection with L1 + // l1Node.SetHeader() + cl := ethclient.NewClient(l1Node) + l1Sources = append(l1Sources, cl) + } + if len(l1Sources) == 0 { + return fmt.Errorf("need at least one L1 source endpoint, see --l1") + } + + // Combine L1 sources, so work can be balanced between them + c.l1Source = eth.NewCombinedL1Source(l1Sources) + l1CanonicalChain := eth.CanonicalChain(c.l1Source) + + c.l1Downloader = l1.NewDownloader(c.l1Source) + + for i, addr := range c.L2EngineAddrs { + // L2 exec engine: updated by this OpNode (L2 consensus layer node) + backend, err := rpc.DialContext(ctx, addr) + if err != nil { + if backend == nil { + return fmt.Errorf("failed to dial L2 address %d (%s): %v", i, addr, err) + } + c.log.Warn("failed to dial L2 address, but may connect later", "i", i, "addr", addr, "err", err) + } + // TODO: we may need to authenticate the connection with L2 + // backend.SetHeader() + client := &l2.EngineClient{ + RPCBackend: backend, + EthBackend: ethclient.NewClient(backend), + Log: c.log.New("engine_client", i), + } + engine := &l2.EngineDriver{ + Ctx: c.ctx, + Log: c.log.New("engine", i), + RPC: client, + SyncRef: l2.SyncSource{ + L1: l1CanonicalChain, + L2: client, + }, + } + c.l2Engines = append(c.l2Engines, engine) + } + + // TODO: maybe spin up an API server + // (to get debug data, change runtime settings like logging, serve pprof, get peering info, node health, etc.) + + c.close = make(chan chan error) + + go c.RunNode() + return nil } +func (c *OpNodeCmd) RunNode() { + c.log.Info("Starting OpNode") + + var unsub []func() + mergeSub := func(sub ethereum.Subscription, errMsg string) { + unsub = append(unsub, sub.Unsubscribe) + go func() { + err, ok := <-sub.Err() + if !ok { + return + } + c.log.Error(errMsg, "err", err) + }() + } + + c.log.Info("Fetching rollup starting point") + + // We download receipts in parallel + c.l1Downloader.AddReceiptWorkers(4) + + // Feed of eth.HeadSignal + var l1HeadsFeed event.Feed + + c.log.Info("Attaching execution engine(s)") + for _, eng := range c.l2Engines { + // Update genesis info, to anchor sync at + eng.Genesis = c.Genesis.GetGenesis() + // Request initial head update, default to genesis otherwise + if err := eng.RequestHeadUpdate(); err != nil { + eng.Log.Error("failed to fetch engine head, defaulting to genesis", "err", err) + eng.UpdateHead(eng.Genesis.L1, eng.Genesis.L2) + } + + // driver subscribes to L1 head changes + l1SubCh := make(chan eth.HeadSignal, 10) + l1HeadsFeed.Subscribe(l1SubCh) + // start driving engine: sync blocks by deriving them from L1 and driving them into the engine + engDriveSub := eng.Drive(c.l1Downloader, l1SubCh) + mergeSub(engDriveSub, "engine driver unexpectedly failed") + } + + // Keep subscribed to the L1 heads, which keeps the L1 maintainer pointing to the best headers to sync + l1HeadsSub := event.ResubscribeErr(time.Second*10, func(ctx context.Context, err error) (event.Subscription, error) { + if err != nil { + c.log.Warn("resubscribing after failed L1 subscription", "err", err) + } + return eth.WatchHeadChanges(c.ctx, c.l1Source, eth.HeadSignalFn(func(sig eth.HeadSignal) { + l1HeadsFeed.Send(sig) + })) + }) + mergeSub(l1HeadsSub, "l1 heads subscription failed") + + // subscribe to L1 heads for info + l1Heads := make(chan eth.HeadSignal, 10) + l1HeadsFeed.Subscribe(l1Heads) + + c.log.Info("Start-up complete!") + + for { + select { + case l1Head := <-l1Heads: + c.log.Info("New L1 head", "head", l1Head.Self, "parent", l1Head.Parent) + // TODO: maybe log other info on interval or other chain events (individual engines also log things) + case done := <-c.close: + c.log.Info("Closing OpNode") + // close all tasks + for _, f := range unsub { + f() + } + // close L1 data source + c.l1Source.Close() + // close L2 engines + for _, eng := range c.l2Engines { + eng.Close() + } + // signal back everything closed without error + done <- nil + return + } + } +} + func (c *OpNodeCmd) Close() error { + if c.close != nil { + done := make(chan error) + c.close <- done + err := <-done + return err + } return nil } From 475cbce1fccdafa39804d72bf17e54dc101bf1cb Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 12 Jan 2022 19:47:17 +0100 Subject: [PATCH 2/5] ref impl: readme --- opnode/README.md | 38 ++++++++++++++++++++++++++++++++++++++ package.json | 6 +++--- 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 opnode/README.md diff --git a/opnode/README.md b/opnode/README.md new file mode 100644 index 000000000000..d93e12510d03 --- /dev/null +++ b/opnode/README.md @@ -0,0 +1,38 @@ +# opnode + +This is the reference implementation of the [rollup-node spec](../specs/rollup-node.md). + +## Compiling + +```shell +go build -o op ./opnode/cmd +``` + +## Running + +Options can be reviewed with: + +```shell +./op run --help +``` + +To start syncing the rollup: + +Connect to at least one L1 RPC and L2 execution engine: + +- L1: use any L1 node / RPC (websocket connection path may differ) +- L2: run the Optimism fork of geth: + +Initialize the L2 chain with a `genesis.json` chain spec like L1, with the Merge fork activated from genesis. + +Specify genesis details: + +- L1 number / hash: starting-point of L2 chain inputs +- L2 genesis hash: to confirm we are building on the correct L2 genesis + +```shell +# websockets or IPC preferred for event notifications to improve sync, http RPC works with adaptive polling. +op node run \ + --l1=ws://localhost:8546 --l2=ws//localhost:9001 \ + --genesis.l1-num=.... --genesis.l1-hash=..... --genesis.l2-hash=.... +``` diff --git a/package.json b/package.json index f1302f9a1dfb..1e5e8808b0d5 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "scripts": { "setup": "yarn install && cargo install lychee", "lint": "yarn lint:fix && yarn lint:check", - "lint:fix": "markdownlint-cli2-fix \"./specs/**/*.md\" \"#node_modules\"", - "lint:check": "markdownlint-cli2 \"./specs/**/*.md\" \"#node_modules\"", - "lint:links": "lychee --exclude twitter.com --exclude-mail README.md \"./specs/**/*.md\" \"./meta/**/*.md\" \"./opnode/**/*.md\"" + "lint:fix": "markdownlint-cli2-fix \"./opnode/README.md\" \"./specs/**/*.md\" \"#node_modules\"", + "lint:check": "markdownlint-cli2 \"./opnode/README.md\" \"./specs/**/*.md\" \"#node_modules\"", + "lint:links": "lychee --exclude twitter.com --exclude-mail README.md \"./opnode/README.md\" \"./specs/**/*.md\" \"./meta/**/*.md\" \"./opnode/**/*.md\"" } } From 1efef020d39892b69926f63aab2b9f0c7973fc15 Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 19 Jan 2022 19:40:22 +0100 Subject: [PATCH 3/5] ref impl: pass context to Drive instead of into engine-driver struct. And remove unnecessary type conversion --- opnode/node/node.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/opnode/node/node.go b/opnode/node/node.go index 9e338d576dd7..db169dc0ef00 100644 --- a/opnode/node/node.go +++ b/opnode/node/node.go @@ -122,7 +122,6 @@ func (c *OpNodeCmd) Run(ctx context.Context, args ...string) error { Log: c.log.New("engine_client", i), } engine := &l2.EngineDriver{ - Ctx: c.ctx, Log: c.log.New("engine", i), RPC: client, SyncRef: l2.SyncSource{ @@ -171,16 +170,18 @@ func (c *OpNodeCmd) RunNode() { // Update genesis info, to anchor sync at eng.Genesis = c.Genesis.GetGenesis() // Request initial head update, default to genesis otherwise - if err := eng.RequestHeadUpdate(); err != nil { + reqCtx, reqCancel := context.WithTimeout(c.ctx, time.Second*10) + if err := eng.RequestHeadUpdate(reqCtx); err != nil { eng.Log.Error("failed to fetch engine head, defaulting to genesis", "err", err) eng.UpdateHead(eng.Genesis.L1, eng.Genesis.L2) } + reqCancel() // driver subscribes to L1 head changes l1SubCh := make(chan eth.HeadSignal, 10) l1HeadsFeed.Subscribe(l1SubCh) // start driving engine: sync blocks by deriving them from L1 and driving them into the engine - engDriveSub := eng.Drive(c.l1Downloader, l1SubCh) + engDriveSub := eng.Drive(c.ctx, c.l1Downloader, l1SubCh) mergeSub(engDriveSub, "engine driver unexpectedly failed") } @@ -189,9 +190,9 @@ func (c *OpNodeCmd) RunNode() { if err != nil { c.log.Warn("resubscribing after failed L1 subscription", "err", err) } - return eth.WatchHeadChanges(c.ctx, c.l1Source, eth.HeadSignalFn(func(sig eth.HeadSignal) { + return eth.WatchHeadChanges(c.ctx, c.l1Source, func(sig eth.HeadSignal) { l1HeadsFeed.Send(sig) - })) + }) }) mergeSub(l1HeadsSub, "l1 heads subscription failed") From 8ab6af818ba1e5ef2d23d1db10e8f678a8d980fe Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 19 Jan 2022 19:42:43 +0100 Subject: [PATCH 4/5] ref impl: rename mergeSub to handleUnsubscribe --- opnode/node/node.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/opnode/node/node.go b/opnode/node/node.go index db169dc0ef00..fbffd9fb4dba 100644 --- a/opnode/node/node.go +++ b/opnode/node/node.go @@ -146,7 +146,7 @@ func (c *OpNodeCmd) RunNode() { c.log.Info("Starting OpNode") var unsub []func() - mergeSub := func(sub ethereum.Subscription, errMsg string) { + handleUnsubscribe := func(sub ethereum.Subscription, errMsg string) { unsub = append(unsub, sub.Unsubscribe) go func() { err, ok := <-sub.Err() @@ -182,7 +182,7 @@ func (c *OpNodeCmd) RunNode() { l1HeadsFeed.Subscribe(l1SubCh) // start driving engine: sync blocks by deriving them from L1 and driving them into the engine engDriveSub := eng.Drive(c.ctx, c.l1Downloader, l1SubCh) - mergeSub(engDriveSub, "engine driver unexpectedly failed") + handleUnsubscribe(engDriveSub, "engine driver unexpectedly failed") } // Keep subscribed to the L1 heads, which keeps the L1 maintainer pointing to the best headers to sync @@ -194,7 +194,7 @@ func (c *OpNodeCmd) RunNode() { l1HeadsFeed.Send(sig) }) }) - mergeSub(l1HeadsSub, "l1 heads subscription failed") + handleUnsubscribe(l1HeadsSub, "l1 heads subscription failed") // subscribe to L1 heads for info l1Heads := make(chan eth.HeadSignal, 10) From 59acf60f4d4fa081a3df4d0befa2b5368441006d Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 21 Jan 2022 17:03:57 +0100 Subject: [PATCH 5/5] ref impl: adapt node to driver actions/state separation refactor --- opnode/node/node.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/opnode/node/node.go b/opnode/node/node.go index fbffd9fb4dba..43d108b5f664 100644 --- a/opnode/node/node.go +++ b/opnode/node/node.go @@ -104,6 +104,7 @@ func (c *OpNodeCmd) Run(ctx context.Context, args ...string) error { l1CanonicalChain := eth.CanonicalChain(c.l1Source) c.l1Downloader = l1.NewDownloader(c.l1Source) + genesis := c.Genesis.GetGenesis() for i, addr := range c.L2EngineAddrs { // L2 exec engine: updated by this OpNode (L2 consensus layer node) @@ -124,10 +125,12 @@ func (c *OpNodeCmd) Run(ctx context.Context, args ...string) error { engine := &l2.EngineDriver{ Log: c.log.New("engine", i), RPC: client, + DL: c.l1Downloader, SyncRef: l2.SyncSource{ L1: l1CanonicalChain, L2: client, }, + EngineDriverState: l2.EngineDriverState{Genesis: genesis}, } c.l2Engines = append(c.l2Engines, engine) } @@ -167,12 +170,10 @@ func (c *OpNodeCmd) RunNode() { c.log.Info("Attaching execution engine(s)") for _, eng := range c.l2Engines { - // Update genesis info, to anchor sync at - eng.Genesis = c.Genesis.GetGenesis() // Request initial head update, default to genesis otherwise reqCtx, reqCancel := context.WithTimeout(c.ctx, time.Second*10) - if err := eng.RequestHeadUpdate(reqCtx); err != nil { - eng.Log.Error("failed to fetch engine head, defaulting to genesis", "err", err) + if !eng.RequestUpdate(reqCtx, eng.Log, eng) { + eng.Log.Error("failed to fetch engine head, defaulting to genesis") eng.UpdateHead(eng.Genesis.L1, eng.Genesis.L2) } reqCancel() @@ -181,7 +182,7 @@ func (c *OpNodeCmd) RunNode() { l1SubCh := make(chan eth.HeadSignal, 10) l1HeadsFeed.Subscribe(l1SubCh) // start driving engine: sync blocks by deriving them from L1 and driving them into the engine - engDriveSub := eng.Drive(c.ctx, c.l1Downloader, l1SubCh) + engDriveSub := eng.Drive(c.ctx, l1SubCh) handleUnsubscribe(engDriveSub, "engine driver unexpectedly failed") }