Skip to content

Commit

Permalink
[alpha] Sweep latest changes from devel to alpha (#3990)
Browse files Browse the repository at this point in the history
* Change version to alpha (#3926)

Co-authored-by: Alexey Sharp <[email protected]>
Co-authored-by: Alex Sharp <[email protected]>

* docs: update libmdbx links (#3929)

* Makefile: refactor build flags and fix 1.17 (#3930)

* Fix some cli flag descriptions (#3933)

* Fix some cli flag descriptions

* add node about verbosity

* min requirement to go 1.18 (#3934)

* save

* save

* save

* Added Ethstats service (#3931)

* somewhat there but not yet

* lol

* more efficient ethstats

* lint

* not die on no wifi

* Update bor mumbai config (#3937)

* Update ci.yml (#3936)

* Use heimdall url in integration bor consensus (#3940)

* Downloader: re-use flags defaults (#3941)

* torrent: print peers amount in logs (#3942)

* Observer - P2P network crawler (#3928)

Observer crawls the Ethereum network and collects information about the nodes.

* Torrent conns print (#3943)

* save

* save

* [erigon2] Fuzz tests for commitment (#3939)

* [erigon2] Fuzz tests for commitment

* Cleanup

* Update to erigon-lib main

Co-authored-by: Alexey Sharp <[email protected]>

* Introduce unlimited download rate (#3945)

* Introduce unlimited download rate

* More generous burst

Co-authored-by: Alexey Sharp <[email protected]>

* Replace ioutil with io and os (#3946)

* Sentry GRPC: rename Peers to PeerEvents (#3944)

* Sentry GRPC: rename Peers to PeerEvents

see erigontech/interfaces#101

* Update to erigon-lib main

Co-authored-by: Alexey Sharp <[email protected]>

* cleaned up forkchoices db insertions #3949

* fixed ethstats (#3951)

* bsc: disable snap sync (#3955)

* bsc: disable snap sync (#3956)

* Snapshots: support empty buf case (#3957)

* Snapshots: rare nil pointer at fresh start (#3958)

* got rid of the automatic usage of net api (#3952)

* got rid of the automatic usage of net api

* less confusing comment

* ops

* ops2

* important

* ops

* RPC: admin.peers() (#3960)

* RPC: admin.peers()

This RPC method returns information about the connected remote nodes.
https://geth.ethereum.org/docs/rpc/ns-admin#admin_peers

The peers are collected from all configured sentries.
See: erigontech/interfaces#102

Test with:
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc": "2.0", "method": "admin_peers", "params": [], "id":1}' localhost:8545

* save

* liner fix

Co-authored-by: alex.sharov <[email protected]>

* sentry: refactor flags, add maxpeers. (#3961)

* Experiment files 1 by 1 (#3959)

* Experiment files 1 by 1

* Remove check

* sort preverified snapshots

* docs: docker permissions

* sort preverified snapshots

* sort preverified snapshots

* sort preverified snapshots

* sort preverified snapshots

* sort preverified snapshots

* sort preverified snapshots

* save

* Fix speed log, remove file name

* Move timer out of the loop

* Calculate total size of downloaded files

* Fixes

* Fix

* Fix

* Fix

* Move downloadData

* Fix

* Revert "Fix"

This reverts commit 038e02b.

* Revert "Move downloadData"

This reverts commit 8130a4d.

* Revert "Fix"

This reverts commit 1dca25b.

* Revert "Fix"

This reverts commit ee5a1e8.

* Revert "Fix"

This reverts commit 8af7be7.

* Revert "Fixes"

This reverts commit 50509af.

* Revert "Calculate total size of downloaded files"

This reverts commit 64a26df.

* Remove progress

* Remove progress

Co-authored-by: Alexey Sharp <[email protected]>
Co-authored-by: alex.sharov <[email protected]>

* Update stage_headers.go (#3966)

* Snapshots: open bittorrent udp port in docker (#3969)

* Snapshots: open torrent udp in docker-compose.yml

* Snapshots: open torrent udp in docker-compose.yml

* Delete blocks in [from, to) range (#3970)

* Snapshots: allow stage_headers --unwind behind available snapshots (#3971)

* save

* save

* save

* Integration: allow headers --reset (#3972)

* Bsc: enable syncmode=snap by default #3973

* rlp: add support for optional struct fields (#22832) (#3977)

This adds support for a new struct tag "optional". Using this tag, structs used
for RLP encoding/decoding can be extended in a backwards-compatible way,
by adding new fields at the end.

see geth commit ethereum/go-ethereum@700df14

Co-authored-by: Felix Lange <[email protected]>

* Forgot to check err status (#3978)

* Forgot to check err status

* Invalid header shouldn't fail the entire stage

* Potential fix for verification (#3962)

* Potential fix for verification

* multi verify

Co-authored-by: Alexey Sharp <[email protected]>
Co-authored-by: Alex Sharp <[email protected]>

* p2p/discover/v4wire: use optional RLP field for EIP-868 seq (#3963)

This changes the definitions of Ping and Pong, adding an optional field
for the sequence number. This field was previously encoded/decoded using
the "tail" struct tag, but using "optional" is much nicer.

see ethereum/go-ethereum#22842

Co-authored-by: Felix Lange <[email protected]>

* FullSync instead of FastSync (#3980)

* Update README.md (#3984)

* Update README.md (#3985)

* Update README.md (#3987)

* Update README.md (#3988)

* Update README.md (#3989)

* save (#3983)

Co-authored-by: Alexey Sharp <[email protected]>
Co-authored-by: Alex Sharp <[email protected]>
Co-authored-by: battlmonstr <[email protected]>
Co-authored-by: Chase Wright <[email protected]>
Co-authored-by: Alex Sharov <[email protected]>
Co-authored-by: Giulio rebuffo <[email protected]>
Co-authored-by: Krishna Upadhyaya <[email protected]>
Co-authored-by: Håvard Anda Estensen <[email protected]>
Co-authored-by: Enrique Jose  Avila Asapche <[email protected]>
Co-authored-by: Felix Lange <[email protected]>
Co-authored-by: Andrew Ashikhmin <[email protected]>
  • Loading branch information
12 people authored Apr 27, 2022
1 parent a279241 commit 9d3c4c6
Show file tree
Hide file tree
Showing 17 changed files with 463 additions and 217 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ changes but we don't guarantee anything. Things can and will break.**
System Requirements
===================

For a full archive node we recommend >=3TB storage space on a single partition: 1.8TB state (as of March 2022),
200GB temp files (can symlink or mount folder `<datadir>/etl-tmp` to another disk).
For an Archive node of Mainnet we recommend >=3TB storage space: 1.8TB state (as of March 2022),
200GB temp files (can symlink or mount folder `<datadir>/etl-tmp` to another disk). Mainnet Full node (see `--prune*` flags): 400Gb (April 2022), BSC Archive: 7Tb. BSC Full: 1Tb
SSD or NVMe. Do not recommend HDD - on HDD Erigon will always stay N blocks behind chain tip, but not fall behind.
Bear in mind that SSD performance deteriorates when close to capacity.

RAM: >=16GB, 64-bit architecture, [Golang version >= 1.16](https://golang.org/doc/install), GCC 10+
RAM: >=16GB, 64-bit architecture, [Golang version >= 1.18](https://golang.org/doc/install), GCC 10+

<code>🔬 more info on disk storage is [here](https://ledgerwatch.github.io/turbo_geth_release.html#Disk-space).</code>

Expand All @@ -63,7 +63,7 @@ make erigon
./build/bin/erigon
```

Default `--syncmode=snap` for `mainnet`, `goerli`, `bsc`. Other networks now have default `--syncmode=fast`. Increase download speed by flag `--torrent.download.rate=20mb`. <code>🔬 See [Downloader docs](./cmd/downloader/readme.md)</code>
Default `--syncmode=snap` for `mainnet`, `goerli`, `bsc`. Other networks now have default `--syncmode=full`. Increase download speed by flag `--torrent.download.rate=20mb`. <code>🔬 See [Downloader docs](./cmd/downloader/readme.md)</code>

Use `--datadir` to choose where to store data.

Expand Down Expand Up @@ -96,8 +96,8 @@ Support only remote-miners.
* To enable, add `--mine --miner.etherbase=...` or `--mine --miner.miner.sigkey=...` flags.
* Other supported options: `--miner.extradata`, `--miner.notify`, `--miner.gaslimit`, `--miner.gasprice`
, `--miner.gastarget`
* RPCDaemon supports methods: eth_coinbase , eth_hashrate, eth_mining, eth_getWork, eth_submitWork, eth_submitHashrate
* RPCDaemon supports websocket methods: newPendingTransaction
* JSON-RPC supports methods: eth_coinbase , eth_hashrate, eth_mining, eth_getWork, eth_submitWork, eth_submitHashrate
* JSON-RPC supports websocket methods: newPendingTransaction
* TODO:
+ we don't broadcast mined blocks to p2p-network
yet, [but it's easy to accomplish](https://github.com/ledgerwatch/erigon/blob/9b8cdc0f2289a7cef78218a15043de5bdff4465e/eth/downloader/downloader.go#L673)
Expand All @@ -118,7 +118,7 @@ Windows users may run erigon in 3 possible ways:
build on windows :
* [Git](https://git-scm.com/downloads) for Windows must be installed. If you're cloning this repository is very
likely you already have it
* [GO Programming Language](https://golang.org/dl/) must be installed. Minimum required version is 1.16
* [GO Programming Language](https://golang.org/dl/) must be installed. Minimum required version is 1.18
* GNU CC Compiler at least version 10 (is highly suggested that you install `chocolatey` package manager - see
following point)
* If you need to build MDBX tools (i.e. `.\wmake.ps1 db-tools`)
Expand Down Expand Up @@ -153,13 +153,13 @@ Erigon can be used as an execution-layer for beacon chain consensus clients (Eth
relies on availability of receipts - don't prune them: don't add character `r` to `--prune` flag. However, old receipts
are not needed for Eth2 and you can safely prune them with `--prune.r.before=11184524` in combination with `--prune htc`.

You must run the [JSON-RPC daemon](#json-rpc-daemon) in addition to the Erigon.
You must enable JSON-RPC by `--http` and add `engine` to `--http.api` list. (Or run the [JSON-RPC daemon](#json-rpc-daemon) in addition to the Erigon)

If beacon chain client on a different device: add `--http.addr 0.0.0.0` (JSON-RPC daemon listen on localhost by default)
If beacon chain client on a different device: add `--http.addr 0.0.0.0` (JSON-RPC listen on localhost by default)
.

Once the JSON-RPC daemon is running, all you need to do is point your beacon chain client to `<ip address>:8545`,
where `<ip address>` is either localhost or the IP address of the device running the JSON-RPC daemon.
Once the JSON-RPC is running, all you need to do is point your beacon chain client to `<ip address>:8545`,
where `<ip address>` is either localhost or the IP address of the device running the JSON-RPC.

Erigon has been tested with Lighthouse however all other clients that support JSON-RPC should also work.

Expand Down Expand Up @@ -241,7 +241,7 @@ Examples of stages are:

### JSON-RPC daemon

Most of Erigon's components can work inside Erigon and as independent process.
Most of Erigon's components (sentry, txpool, snapshots downloader, can work inside Erigon and as independent process.

To enable built-in RPC server: `--http` and `--ws` (sharing same port with http)

Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ var (
}
SyncModeFlag = cli.StringFlag{
Name: "syncmode",
Usage: `Default: "snap" for BSC, Mainnet and Goerli. "fast" in all other cases`,
Usage: `Default: "snap" for BSC, Mainnet and Goerli. "full" in all other cases`,
}
// Transaction pool settings
TxPoolDisableFlag = cli.BoolFlag{
Expand Down
10 changes: 5 additions & 5 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var LightClientGPO = gasprice.Config{

// Defaults contains default settings for use on the Ethereum main net.
var Defaults = Config{
SyncMode: FastSync,
SyncMode: FullSync,
Ethash: ethash.Config{
CachesInMem: 2,
CachesLockMmap: false,
Expand Down Expand Up @@ -290,20 +290,20 @@ func CreateConsensusEngine(chainConfig *params.ChainConfig, logger log.Logger, c
type SyncMode string

const (
FastSync SyncMode = "fast"
FullSync SyncMode = "full"
SnapSync SyncMode = "snap"
)

func SyncModeByChainName(chain, syncCliFlag string) SyncMode {
if syncCliFlag == "fast" {
return FastSync
if syncCliFlag == "full" {
return FullSync
} else if syncCliFlag == "snap" {
return SnapSync
}
switch chain {
case networkname.MainnetChainName, networkname.BSCChainName, networkname.GoerliChainName:
return SnapSync
default:
return FastSync
return FullSync
}
}
8 changes: 4 additions & 4 deletions eth/stagedsync/stage_headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ func HeadersPOS(
cfg.hd.ClearPendingPayloadStatus()

if forkChoiceInsteadOfNewPayload {
startHandlingForkChoice(forkChoiceMessage, status, requestId, s, u, ctx, tx, cfg, headerInserter)
if err := startHandlingForkChoice(forkChoiceMessage, status, requestId, s, u, ctx, tx, cfg, headerInserter); err != nil {
return err
}
} else {
if err := handleNewPayload(payloadMessage, status, requestId, s, ctx, tx, cfg, headerInserter); err != nil {
return err
Expand Down Expand Up @@ -579,7 +581,7 @@ func schedulePoSDownload(
cfg.hd.SetPosStatus(headerdownload.Syncing)
}

func verifyAndSaveDownloadedPoSHeaders(tx kv.RwTx, cfg HeadersCfg, headerInserter *headerdownload.HeaderInserter) error {
func verifyAndSaveDownloadedPoSHeaders(tx kv.RwTx, cfg HeadersCfg, headerInserter *headerdownload.HeaderInserter) {
var lastValidHash common.Hash

headerLoadFunc := func(key, value []byte, _ etl.CurrentTableReader, _ etl.LoadNextFunc) error {
Expand Down Expand Up @@ -612,8 +614,6 @@ func verifyAndSaveDownloadedPoSHeaders(tx kv.RwTx, cfg HeadersCfg, headerInserte
cfg.hd.HeadersCollector().Close()
cfg.hd.SetHeadersCollector(nil)
cfg.hd.SetPosStatus(headerdownload.Idle)

return err
}

// HeadersPOW progresses Headers stage for Proof-of-Work headers
Expand Down
2 changes: 1 addition & 1 deletion eth/stagedsync/stage_txlookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func SpawnTxLookup(s *StageState, tx kv.RwTx, toBlock uint64, cfg TxLookupCfg, c
} else if cfg.snapshots != nil && cfg.snapshots.Cfg().Enabled {
if cfg.snapshots.BlocksAvailable() > startBlock {
// Snapshot .idx files already have TxLookup index - then no reason iterate over them here
startBlock = cfg.snapshots.BlocksAvailable()
startBlock = cfg.snapshots.BlocksAvailable() + 1
if err = s.UpdatePrune(tx, startBlock); err != nil { // prune func of this stage will use this value to prevent all ancient blocks traversal
return err
}
Expand Down
10 changes: 3 additions & 7 deletions p2p/discover/v4_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"github.com/ledgerwatch/erigon/p2p/discover/v4wire"
"github.com/ledgerwatch/erigon/p2p/enode"
"github.com/ledgerwatch/erigon/p2p/netutil"
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/log/v3"
)

Expand Down Expand Up @@ -217,7 +216,7 @@ func (t *UDPv4) Ping(n *enode.Node) error {
func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) {
rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil)
if err = <-rm.errc; err == nil {
seq = rm.reply.(*v4wire.Pong).ENRSeq()
seq = rm.reply.(*v4wire.Pong).ENRSeq
}
return seq, err
}
Expand Down Expand Up @@ -248,13 +247,12 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r
}

func (t *UDPv4) makePing(toaddr *net.UDPAddr) *v4wire.Ping {
seq, _ := rlp.EncodeToBytes(t.localNode.Node().Seq())
return &v4wire.Ping{
Version: 4,
From: t.ourEndpoint(),
To: v4wire.NewEndpoint(toaddr, 0),
Expiration: uint64(time.Now().Add(expiration).Unix()),
Rest: []rlp.RawValue{seq},
ENRSeq: t.localNode.Node().Seq(),
}
}

Expand Down Expand Up @@ -684,14 +682,12 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I
req := h.Packet.(*v4wire.Ping)

// Reply.
seq, _ := rlp.EncodeToBytes(t.localNode.Node().Seq())

//nolint:errcheck
t.send(from, fromID, &v4wire.Pong{
To: v4wire.NewEndpoint(from, req.From.TCP),
ReplyTok: mac,
Expiration: uint64(time.Now().Add(expiration).Unix()),
Rest: []rlp.RawValue{seq},
ENRSeq: t.localNode.Node().Seq(),
})

// Ping back if our last pong on file is too far in the past.
Expand Down
8 changes: 4 additions & 4 deletions p2p/discover/v4_udp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,13 @@ func TestUDPv4_EIP868(t *testing.T) {
// Perform endpoint proof and check for sequence number in packet tail.
test.packetIn(nil, &v4wire.Ping{Expiration: futureExp})
test.waitPacketOut(func(p *v4wire.Pong, addr *net.UDPAddr, hash []byte) {
if p.ENRSeq() != wantNode.Seq() {
t.Errorf("wrong sequence number in pong: %d, want %d", p.ENRSeq(), wantNode.Seq())
if p.ENRSeq != wantNode.Seq() {
t.Errorf("wrong sequence number in pong: %d, want %d", p.ENRSeq, wantNode.Seq())
}
})
test.waitPacketOut(func(p *v4wire.Ping, addr *net.UDPAddr, hash []byte) {
if p.ENRSeq() != wantNode.Seq() {
t.Errorf("wrong sequence number in ping: %d, want %d", p.ENRSeq(), wantNode.Seq())
if p.ENRSeq != wantNode.Seq() {
t.Errorf("wrong sequence number in ping: %d, want %d", p.ENRSeq, wantNode.Seq())
}
test.packetIn(nil, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash})
})
Expand Down
24 changes: 8 additions & 16 deletions p2p/discover/v4wire/v4wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type (
Version uint
From, To Endpoint
Expiration uint64
ENRSeq uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.

// Ignore additional fields (for forward compatibility).
Rest []rlp.RawValue `rlp:"tail"`
}
Expand All @@ -61,6 +63,8 @@ type (
To Endpoint
ReplyTok []byte // This contains the hash of the ping packet.
Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
ENRSeq uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.

// Ignore additional fields (for forward compatibility).
Rest []rlp.RawValue `rlp:"tail"`
}
Expand Down Expand Up @@ -156,13 +160,11 @@ type Packet interface {
Kind() byte
}

func (req *Ping) Name() string { return "PING/v4" }
func (req *Ping) Kind() byte { return PingPacket }
func (req *Ping) ENRSeq() uint64 { return seqFromTail(req.Rest) }
func (req *Ping) Name() string { return "PING/v4" }
func (req *Ping) Kind() byte { return PingPacket }

func (req *Pong) Name() string { return "PONG/v4" }
func (req *Pong) Kind() byte { return PongPacket }
func (req *Pong) ENRSeq() uint64 { return seqFromTail(req.Rest) }
func (req *Pong) Name() string { return "PONG/v4" }
func (req *Pong) Kind() byte { return PongPacket }

func (req *Findnode) Name() string { return "FINDNODE/v4" }
func (req *Findnode) Kind() byte { return FindnodePacket }
Expand All @@ -181,16 +183,6 @@ func Expired(ts uint64) bool {
return time.Unix(int64(ts), 0).Before(time.Now())
}

func seqFromTail(tail []rlp.RawValue) uint64 {
if len(tail) == 0 {
return 0
}
var seq uint64
//goland:noinspection GoUnhandledErrorResult
rlp.DecodeBytes(tail[0], &seq) //nolint:errcheck
return seq
}

// Encoder/decoder.

const (
Expand Down
24 changes: 2 additions & 22 deletions p2p/discover/v4wire/v4wire_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"testing"

"github.com/davecgh/go-spew/spew"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/crypto"
"github.com/ledgerwatch/erigon/rlp"
)
Expand All @@ -40,7 +39,6 @@ var testPackets = []struct {
From: Endpoint{net.ParseIP("127.0.0.1").To4(), 3322, 5544},
To: Endpoint{net.ParseIP("::1"), 2222, 3333},
Expiration: 1136239445,
Rest: []rlp.RawValue{},
},
},
{
Expand All @@ -50,26 +48,8 @@ var testPackets = []struct {
From: Endpoint{net.ParseIP("127.0.0.1").To4(), 3322, 5544},
To: Endpoint{net.ParseIP("::1"), 2222, 3333},
Expiration: 1136239445,
Rest: []rlp.RawValue{{0x01}, {0x02}},
},
},
{
input: "577be4349c4dd26768081f58de4c6f375a7a22f3f7adda654d1428637412c3d7fe917cadc56d4e5e7ffae1dbe3efffb9849feb71b262de37977e7c7a44e677295680e9e38ab26bee2fcbae207fba3ff3d74069a50b902a82c9903ed37cc993c50001f83e82022bd79020010db83c4d001500000000abcdef12820cfa8215a8d79020010db885a308d313198a2e037073488208ae82823a8443b9a355c5010203040531b9019afde696e582a78fa8d95ea13ce3297d4afb8ba6433e4154caa5ac6431af1b80ba76023fa4090c408f6b4bc3701562c031041d4702971d102c9ab7fa5eed4cd6bab8f7af956f7d565ee1917084a95398b6a21eac920fe3dd1345ec0a7ef39367ee69ddf092cbfe5b93e5e568ebc491983c09c76d922dc3",
wantPacket: &Ping{
Version: 555,
From: Endpoint{net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 3322, 5544},
To: Endpoint{net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"), 2222, 33338},
Expiration: 1136239445,
Rest: []rlp.RawValue{{0xC5, 0x01, 0x02, 0x03, 0x04, 0x05}},
},
},
{
input: "09b2428d83348d27cdf7064ad9024f526cebc19e4958f0fdad87c15eb598dd61d08423e0bf66b2069869e1724125f820d851c136684082774f870e614d95a2855d000f05d1648b2d5945470bc187c2d2216fbe870f43ed0909009882e176a46b0102f846d79020010db885a308d313198a2e037073488208ae82823aa0fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c9548443b9a355c6010203c2040506a0c969a58f6f9095004c0177a6b47f451530cab38966a25cca5cb58f055542124e",
wantPacket: &Pong{
To: Endpoint{net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"), 2222, 33338},
ReplyTok: common.Hex2Bytes("fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c954"),
Expiration: 1136239445,
Rest: []rlp.RawValue{{0xC6, 0x01, 0x02, 0x03, 0xC2, 0x04, 0x05}, {0x06}},
ENRSeq: 1,
Rest: []rlp.RawValue{{0x02}},
},
},
{
Expand Down
16 changes: 15 additions & 1 deletion rlp/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,16 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
if _, err := s.List(); err != nil {
return wrapStreamError(err, typ)
}
for _, f := range fields {
for i, f := range fields {
err := f.info.decoder(s, val.Field(f.index))
if err == EOL {
if f.optional {
// The field is optional, so reaching the end of the list before
// reaching the last field is acceptable. All remaining undecoded
// fields are zeroed.
zeroFields(val, fields[i:])
break
}
return &decodeError{msg: "too few elements", typ: typ}
} else if err != nil {
return addErrorContext(err, "."+typ.Field(f.index).Name)
Expand All @@ -457,6 +464,13 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
return dec, nil
}

func zeroFields(structval reflect.Value, fields []field) {
for _, f := range fields {
fv := structval.Field(f.index)
fv.Set(reflect.Zero(fv.Type()))
}
}

// makePtrDecoder creates a decoder that decodes into the pointer's element type.
func makePtrDecoder(typ reflect.Type, tag tags) (decoder, error) {
etype := typ.Elem()
Expand Down
Loading

0 comments on commit 9d3c4c6

Please sign in to comment.