Skip to content

Commit e737446

Browse files
committed
feat: Handler.PostProcess() method for result aggregation before end of block
1 parent ed05fb6 commit e737446

File tree

5 files changed

+98
-56
lines changed

5 files changed

+98
-56
lines changed

go.mod

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/ava-labs/libevm
22

3-
go 1.23
3+
go 1.24.8
44

55
require (
66
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
@@ -31,7 +31,7 @@ require (
3131
github.com/golang-jwt/jwt/v4 v4.5.0
3232
github.com/golang/protobuf v1.5.3
3333
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
34-
github.com/google/go-cmp v0.5.9
34+
github.com/google/go-cmp v0.6.0
3535
github.com/google/gofuzz v1.2.0
3636
github.com/google/uuid v1.3.0
3737
github.com/gorilla/websocket v1.4.2
@@ -59,20 +59,20 @@ require (
5959
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
6060
github.com/status-im/keycard-go v0.2.0
6161
github.com/stretchr/testify v1.8.4
62-
github.com/supranational/blst v0.3.11
62+
github.com/supranational/blst v0.3.14
6363
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
6464
github.com/tyler-smith/go-bip39 v1.1.0
6565
github.com/urfave/cli/v2 v2.25.7
6666
go.uber.org/automaxprocs v1.5.2
6767
go.uber.org/goleak v1.3.0
68-
golang.org/x/crypto v0.17.0
68+
golang.org/x/crypto v0.43.0
6969
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
70-
golang.org/x/mod v0.14.0
71-
golang.org/x/sync v0.5.0
72-
golang.org/x/sys v0.16.0
73-
golang.org/x/text v0.14.0
70+
golang.org/x/mod v0.29.0
71+
golang.org/x/sync v0.17.0
72+
golang.org/x/sys v0.37.0
73+
golang.org/x/text v0.30.0
7474
golang.org/x/time v0.3.0
75-
golang.org/x/tools v0.15.0
75+
golang.org/x/tools v0.38.0
7676
gopkg.in/natefinch/lumberjack.v2 v2.0.0
7777
gopkg.in/yaml.v3 v3.0.1
7878
)
@@ -139,7 +139,7 @@ require (
139139
github.com/tklauser/go-sysconf v0.3.12 // indirect
140140
github.com/tklauser/numcpus v0.6.1 // indirect
141141
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
142-
golang.org/x/net v0.18.0 // indirect
142+
golang.org/x/net v0.46.0 // indirect
143143
google.golang.org/protobuf v1.27.1 // indirect
144144
gopkg.in/yaml.v2 v2.4.0 // indirect
145145
rsc.io/tmplfunc v0.0.3 // indirect

go.sum

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
299299
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
300300
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
301301
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
302-
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
303-
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
302+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
303+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
304304
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
305305
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
306306
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
@@ -580,8 +580,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
580580
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
581581
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
582582
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
583-
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
584-
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
583+
github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo=
584+
github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
585585
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
586586
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
587587
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
@@ -635,8 +635,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
635635
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
636636
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
637637
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
638-
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
639-
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
638+
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
639+
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
640640
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
641641
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
642642
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -670,8 +670,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
670670
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
671671
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
672672
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
673-
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
674-
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
673+
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
674+
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
675675
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
676676
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
677677
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -711,8 +711,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
711711
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
712712
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
713713
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
714-
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
715-
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
714+
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
715+
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
716716
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
717717
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
718718
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -731,8 +731,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
731731
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
732732
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
733733
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
734-
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
735-
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
734+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
735+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
736736
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
737737
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
738738
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -796,8 +796,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
796796
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
797797
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
798798
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
799-
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
800-
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
799+
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
800+
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
801801
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
802802
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
803803
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -810,8 +810,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
810810
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
811811
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
812812
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
813-
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
814-
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
813+
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
814+
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
815815
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
816816
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
817817
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -866,8 +866,8 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
866866
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
867867
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
868868
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
869-
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
870-
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
869+
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
870+
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
871871
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
872872
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
873873
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

libevm/libevm.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ type StateReader interface {
5656

5757
AddressInAccessList(addr common.Address) bool
5858
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
59+
60+
TxHash() common.Hash
61+
TxIndex() int
5962
}
6063

6164
// AddressContext carries addresses available to contexts such as calls and

libevm/precompiles/parallel/parallel.go

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package parallel
2121
import (
2222
"errors"
2323
"fmt"
24+
"iter"
2425
"sync"
2526

2627
"github.com/ava-labs/libevm/common"
@@ -48,12 +49,13 @@ import (
4849
// All [libevm.StateReader] instances are opened to the state at the beginning
4950
// of the block. The [StateDB] is the same one used to execute the block,
5051
// before being committed, and MAY be written to.
51-
type Handler[Data, Result any] interface {
52+
type Handler[Data, Result, Aggregated any] interface {
5253
BeforeBlock(libevm.StateReader, *types.Block)
5354
Gas(*types.Transaction) (gas uint64, process bool)
5455
Prefetch(sdb libevm.StateReader, index int, tx *types.Transaction) Data
5556
Process(sdb libevm.StateReader, index int, tx *types.Transaction, data Data) Result
56-
AfterBlock(StateDB, *types.Block, types.Receipts)
57+
PostProcess(iter.Seq2[int, Result]) Aggregated
58+
AfterBlock(StateDB, Aggregated, *types.Block, types.Receipts)
5759
}
5860

5961
// StateDB is the subset of [state.StateDB] methods that MAY be called by
@@ -64,14 +66,17 @@ type StateDB interface {
6466
}
6567

6668
// A Processor orchestrates dispatch and collection of results from a [Handler].
67-
type Processor[D, R any] struct {
68-
handler Handler[D, R]
69-
workers sync.WaitGroup
69+
type Processor[D, R, A any] struct {
70+
handler Handler[D, R, A]
71+
workers sync.WaitGroup
72+
73+
stateShare stateDBSharer
74+
txGas map[common.Hash]uint64
75+
7076
prefetch, process chan *job
7177
data [](chan D)
7278
results [](chan result[R])
73-
txGas map[common.Hash]uint64
74-
stateShare stateDBSharer
79+
aggregated chan A
7580
}
7681

7782
type job struct {
@@ -87,20 +92,21 @@ type result[T any] struct {
8792
// New constructs a new [Processor] with the specified number of concurrent
8893
// workers. [Processor.Close] must be called after the final call to
8994
// [Processor.FinishBlock] to avoid leaking goroutines.
90-
func New[D, R any](h Handler[D, R], prefetchers, processors int) *Processor[D, R] {
95+
func New[D, R, A any](h Handler[D, R, A], prefetchers, processors int) *Processor[D, R, A] {
9196
prefetchers = max(prefetchers, 1)
9297
processors = max(processors, 1)
9398
workers := prefetchers + processors
9499

95-
p := &Processor[D, R]{
96-
handler: h,
97-
prefetch: make(chan *job),
98-
process: make(chan *job),
99-
txGas: make(map[common.Hash]uint64),
100+
p := &Processor[D, R, A]{
101+
handler: h,
100102
stateShare: stateDBSharer{
101103
workers: workers,
102104
nextAvailable: make(chan struct{}),
103105
},
106+
txGas: make(map[common.Hash]uint64),
107+
prefetch: make(chan *job),
108+
process: make(chan *job),
109+
aggregated: make(chan A),
104110
}
105111

106112
p.workers.Add(workers) // for shutdown via [Processor.Close]
@@ -139,7 +145,7 @@ func (s *stateDBSharer) distribute(sdb *state.StateDB) {
139145
s.wg.Wait()
140146
}
141147

142-
func (p *Processor[D, R]) worker(prefetch, process chan *job) {
148+
func (p *Processor[D, R, A]) worker(prefetch, process chan *job) {
143149
defer p.workers.Done()
144150

145151
var sdb *state.StateDB
@@ -181,7 +187,7 @@ func (p *Processor[D, R]) worker(prefetch, process chan *job) {
181187
}
182188

183189
// Close shuts down the [Processor], after which it can no longer be used.
184-
func (p *Processor[D, R]) Close() {
190+
func (p *Processor[D, R, A]) Close() {
185191
close(p.prefetch)
186192
close(p.process)
187193
p.workers.Wait()
@@ -190,7 +196,7 @@ func (p *Processor[D, R]) Close() {
190196
// StartBlock dispatches transactions to the [Handler] and returns immediately.
191197
// It MUST be paired with a call to [Processor.FinishBlock], without overlap of
192198
// blocks.
193-
func (p *Processor[D, R]) StartBlock(sdb *state.StateDB, rules params.Rules, b *types.Block) error {
199+
func (p *Processor[D, R, A]) StartBlock(sdb *state.StateDB, rules params.Rules, b *types.Block) error {
194200
// The distribution mechanism copies the StateDB so we don't need to do it
195201
// here, but the [Handler] is called directly so we do copy.
196202
p.stateShare.distribute(sdb)
@@ -232,9 +238,6 @@ func (p *Processor[D, R]) StartBlock(sdb *state.StateDB, rules params.Rules, b *
232238
}
233239
}
234240

235-
// The first goroutine pipelines into the second, which has its results
236-
// emptied by [Processor.FinishBlock]. The return of said function therefore
237-
// guarantees that we haven't leaked either of these.
238241
go func() {
239242
for _, j := range jobs {
240243
p.prefetch <- j
@@ -245,21 +248,40 @@ func (p *Processor[D, R]) StartBlock(sdb *state.StateDB, rules params.Rules, b *
245248
p.process <- j
246249
}
247250
}()
251+
go func() {
252+
n := len(b.Transactions())
253+
p.aggregated <- p.handler.PostProcess(p.resultIter(n))
254+
}()
248255
return nil
249256
}
250257

258+
func (p *Processor[D, R, A]) resultIter(n int) iter.Seq2[int, R] {
259+
return func(yield func(int, R) bool) {
260+
for i := range n {
261+
r, ok := p.Result(i)
262+
if !ok {
263+
continue
264+
}
265+
if !yield(i, r) {
266+
return
267+
}
268+
}
269+
}
270+
}
271+
251272
// FinishBlock returns the [Processor] to a state ready for the next block. A
252273
// return from FinishBlock guarantees that all dispatched work from the
253274
// respective call to [Processor.StartBlock] has been completed.
254-
func (p *Processor[D, R]) FinishBlock(sdb vm.StateDB, b *types.Block, rs types.Receipts) {
275+
func (p *Processor[D, R, A]) FinishBlock(sdb vm.StateDB, b *types.Block, rs types.Receipts) {
276+
p.handler.AfterBlock(sdb, <-p.aggregated, b, rs)
277+
255278
for i := range len(b.Transactions()) {
256279
// Every result channel is guaranteed to have some value in its buffer
257280
// because [Processor.BeforeBlock] either sends a nil *R or it
258281
// dispatches a job, which will send a non-nil *R.
259282
tx := (<-p.results[i]).tx
260283
delete(p.txGas, tx)
261284
}
262-
p.handler.AfterBlock(sdb, b, rs)
263285
}
264286

265287
// Result blocks until the i'th transaction passed to [Processor.StartBlock] has
@@ -271,9 +293,12 @@ func (p *Processor[D, R]) FinishBlock(sdb vm.StateDB, b *types.Block, rs types.R
271293
// Multiple calls to Result with the same argument are allowed. Callers MUST NOT
272294
// charge the gas price for preprocessing as this is handled by
273295
// [Processor.PreprocessingGasCharge] if registered as a [vm.Preprocessor].
296+
//
274297
// The same value will be returned by each call with the same argument, such
275-
// that if R is a pointer then modifications will persist between calls.
276-
func (p *Processor[D, R]) Result(i int) (R, bool) {
298+
// that if R is a pointer then modifications will persist between calls. The
299+
// caller does NOT have mutually exclusive access to R, which MUST carry a mutex
300+
// if thread safety is required.
301+
func (p *Processor[D, R, A]) Result(i int) (R, bool) {
277302
ch := p.results[i]
278303
r := <-ch
279304
defer func() {
@@ -289,7 +314,7 @@ func (p *Processor[D, R]) Result(i int) (R, bool) {
289314
return *r.val, true
290315
}
291316

292-
func (p *Processor[R, D]) shouldProcess(tx *types.Transaction, rules params.Rules) (process bool, retErr error) {
317+
func (p *Processor[R, D, S]) shouldProcess(tx *types.Transaction, rules params.Rules) (process bool, retErr error) {
293318
// An explicit 0 is necessary to avoid [Processor.PreprocessingGasCharge]
294319
// returning [ErrTxUnknown].
295320
p.txGas[tx.Hash()] = 0
@@ -339,12 +364,12 @@ var ErrTxUnknown = errors.New("transaction unknown by parallel preprocessor")
339364

340365
// PreprocessingGasCharge implements the [vm.Preprocessor] interface and MUST be
341366
// registered via [vm.RegisterHooks] to ensure proper gas accounting.
342-
func (p *Processor[R, D]) PreprocessingGasCharge(tx common.Hash) (uint64, error) {
367+
func (p *Processor[R, D, S]) PreprocessingGasCharge(tx common.Hash) (uint64, error) {
343368
g, ok := p.txGas[tx]
344369
if !ok {
345370
return 0, fmt.Errorf("%w: %v", ErrTxUnknown, tx)
346371
}
347372
return g, nil
348373
}
349374

350-
var _ vm.Preprocessor = (*Processor[struct{}, struct{}])(nil)
375+
var _ vm.Preprocessor = (*Processor[any, any, any])(nil)

0 commit comments

Comments
 (0)