Skip to content

Commit e11e488

Browse files
Merge pull request #300 from OffchainLabs/merge-v1.13.4
Merge v1.13.4
2 parents 39c3ff6 + 0073476 commit e11e488

37 files changed

+610
-545
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v4
1717
with:
18-
submodules: true
18+
submodules: recursive
1919

2020
- name: Set up Go
2121
uses: actions/setup-go@v4

build/checksums.txt

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
# This file contains sha256 checksums of optional build dependencies.
22

3+
# version:spec-tests 1.0.6
34
# https://github.com/ethereum/execution-spec-tests/releases
4-
24bac679f3a2d8240d8e08e7f6a70b70c2dabf673317d924cf1d1887b9fe1f81 fixtures.tar.gz
5+
# https://github.com/ethereum/execution-spec-tests/releases/download/v1.0.6/
6+
485af7b66cf41eb3a8c1bd46632913b8eb95995df867cf665617bbc9b4beedd1 fixtures_develop.tar.gz
57

8+
# version:golang 1.21.3
69
# https://go.dev/dl/
7-
bfa36bf75e9a1e9cbbdb9abcf9d1707e479bd3a07880a8ae3564caee5711cb99 go1.21.1.src.tar.gz
8-
809f5b0ef4f7dcdd5f51e9630a5b2e5a1006f22a047126d61560cdc365678a19 go1.21.1.darwin-amd64.tar.gz
9-
ffd40391a1e995855488b008ad9326ff8c2e81803a6e80894401003bae47fcf1 go1.21.1.darwin-arm64.tar.gz
10-
9919a9a4dc82371aba3da5b7c830bcb6249fc1502cd26d959eb340a60e41ee01 go1.21.1.freebsd-386.tar.gz
11-
2571f10f6047e04d87c1f5986a05e5e8f7b511faf98803ef12b66d563845d2a1 go1.21.1.freebsd-amd64.tar.gz
12-
b93850666cdadbd696a986cf7b03111fe99db8c34a9aaa113d7c96d0081e1901 go1.21.1.linux-386.tar.gz
13-
b3075ae1ce5dab85f89bc7905d1632de23ca196bd8336afd93fa97434cfa55ae go1.21.1.linux-amd64.tar.gz
14-
7da1a3936a928fd0b2602ed4f3ef535b8cd1990f1503b8d3e1acc0fa0759c967 go1.21.1.linux-arm64.tar.gz
15-
f3716a43f59ae69999841d6007b42c9e286e8d8ce470656fb3e70d7be2d7ca85 go1.21.1.linux-armv6l.tar.gz
16-
eddf018206f8a5589bda75252b72716d26611efebabdca5d0083ec15e9e41ab7 go1.21.1.linux-ppc64le.tar.gz
17-
a83b3e8eb4dbf76294e773055eb51397510ff4d612a247bad9903560267bba6d go1.21.1.linux-s390x.tar.gz
18-
170256c820f466f29d64876f25f4dfa4029ed9902a0a9095d8bd603aecf4d83b go1.21.1.windows-386.zip
19-
10a4f5b63215d11d1770453733dbcbf024f3f74872f84e28d7ea59f0250316c6 go1.21.1.windows-amd64.zip
20-
41135ce6e0ced4bc1e459cb96bd4090c9dc2062e24179c3f337d855af9b560ef go1.21.1.windows-arm64.zip
10+
186f2b6f8c8b704e696821b09ab2041a5c1ee13dcbc3156a13adcf75931ee488 go1.21.3.src.tar.gz
11+
27014fc69e301d7588a169ca239b3cc609f0aa1abf38528bf0d20d3b259211eb go1.21.3.darwin-amd64.tar.gz
12+
65302a7a9f7a4834932b3a7a14cb8be51beddda757b567a2f9e0cbd0d7b5a6ab go1.21.3.darwin-arm64.tar.gz
13+
8e0cd2f66cf1bde9d07b4aee01e3d7c3cfdd14e20650488e1683da4b8492594a go1.21.3.freebsd-386.tar.gz
14+
6e74f65f586e93d1f3947894766f69e9b2ebda488592a09df61f36f06bfe58a8 go1.21.3.freebsd-amd64.tar.gz
15+
fb209fd070db500a84291c5a95251cceeb1723e8f6142de9baca5af70a927c0e go1.21.3.linux-386.tar.gz
16+
1241381b2843fae5a9707eec1f8fb2ef94d827990582c7c7c32f5bdfbfd420c8 go1.21.3.linux-amd64.tar.gz
17+
fc90fa48ae97ba6368eecb914343590bbb61b388089510d0c56c2dde52987ef3 go1.21.3.linux-arm64.tar.gz
18+
a1ddcaaf0821a12a800884c14cb4268ce1c1f5a0301e9060646f1e15e611c6c7 go1.21.3.linux-armv6l.tar.gz
19+
3b0e10a3704f164a6e85e0377728ec5fd21524fabe4c925610e34076586d5826 go1.21.3.linux-ppc64le.tar.gz
20+
4c78e2e6f4c684a3d5a9bdc97202729053f44eb7be188206f0627ef3e18716b6 go1.21.3.linux-s390x.tar.gz
21+
e36737f4f2fadb4d2f919ec4ce517133a56e06064cca6e82fc883bb000c4d56c go1.21.3.windows-386.zip
22+
27c8daf157493f288d42a6f38debc6a2cb391f6543139eba9152fceca0be2a10 go1.21.3.windows-amd64.zip
23+
bfb7a5c56f9ded07d8ae0e0b3702ac07b65e68fa8f33da24ed6df4ce01fe2c5c go1.21.3.windows-arm64.zip
2124

22-
# https://github.com/golangci/golangci-lint/releases
25+
# version:golangci 1.51.1
26+
# https://github.com/golangci/golangci-lint/releases/
27+
# https://github.com/golangci/golangci-lint/releases/download/v1.51.1/
2328
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
2429
75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz
2530
e06b3459aaed356e1667580be00b05f41f3b2e29685d12cdee571c23e1edb414 golangci-lint-1.51.1-freebsd-386.tar.gz
@@ -48,4 +53,12 @@ bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint-
4853
cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip
4954

5055
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
56+
#
57+
# This version is fine to be old and full of security holes, we just use it
58+
# to build the latest Go. Don't change it. If it ever becomes insufficient,
59+
# we need to switch over to a recursive builder to jump across supported
60+
# versions.
61+
#
62+
# version:ppa-builder 1.19.6
63+
# https://go.dev/dl/
5164
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz

build/ci.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -136,23 +136,6 @@ var (
136136
"golang-go": "/usr/lib/go",
137137
}
138138

139-
// This is the version of Go that will be downloaded by
140-
//
141-
// go run ci.go install -dlgo
142-
dlgoVersion = "1.21.1"
143-
144-
// This is the version of Go that will be used to bootstrap the PPA builder.
145-
//
146-
// This version is fine to be old and full of security holes, we just use it
147-
// to build the latest Go. Don't change it. If it ever becomes insufficient,
148-
// we need to switch over to a recursive builder to jumpt across supported
149-
// versions.
150-
gobootVersion = "1.19.6"
151-
152-
// This is the version of execution-spec-tests that we are using.
153-
// When updating, you must also update build/checksums.txt.
154-
executionSpecTestsVersion = "1.0.2"
155-
156139
// This is where the tests should be unpacked.
157140
executionSpecTestsDir = "tests/spec-tests"
158141
)
@@ -192,6 +175,8 @@ func main() {
192175
doWindowsInstaller(os.Args[2:])
193176
case "purge":
194177
doPurge(os.Args[2:])
178+
case "sanitycheck":
179+
doSanityCheck()
195180
default:
196181
log.Fatal("unknown command ", os.Args[1])
197182
}
@@ -213,9 +198,8 @@ func doInstall(cmdline []string) {
213198
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
214199
if *dlgo {
215200
csdb := build.MustLoadChecksums("build/checksums.txt")
216-
tc.Root = build.DownloadGo(csdb, dlgoVersion)
201+
tc.Root = build.DownloadGo(csdb)
217202
}
218-
219203
// Disable CLI markdown doc generation in release builds.
220204
buildTags := []string{"urfave_cli_no_docs"}
221205

@@ -312,7 +296,7 @@ func doTest(cmdline []string) {
312296
// Configure the toolchain.
313297
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
314298
if *dlgo {
315-
tc.Root = build.DownloadGo(csdb, dlgoVersion)
299+
tc.Root = build.DownloadGo(csdb)
316300
}
317301
gotest := tc.Go("test")
318302

@@ -345,8 +329,12 @@ func doTest(cmdline []string) {
345329

346330
// downloadSpecTestFixtures downloads and extracts the execution-spec-tests fixtures.
347331
func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
332+
executionSpecTestsVersion, err := build.Version(csdb, "spec-tests")
333+
if err != nil {
334+
log.Fatal(err)
335+
}
348336
ext := ".tar.gz"
349-
base := "fixtures" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename
337+
base := "fixtures_develop" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename
350338
url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/v%s/%s%s", executionSpecTestsVersion, base, ext)
351339
archivePath := filepath.Join(cachedir, base+ext)
352340
if err := csdb.DownloadFile(url, archivePath); err != nil {
@@ -377,9 +365,11 @@ func doLint(cmdline []string) {
377365

378366
// downloadLinter downloads and unpacks golangci-lint.
379367
func downloadLinter(cachedir string) string {
380-
const version = "1.51.1"
381-
382368
csdb := build.MustLoadChecksums("build/checksums.txt")
369+
version, err := build.Version(csdb, "golangci")
370+
if err != nil {
371+
log.Fatal(err)
372+
}
383373
arch := runtime.GOARCH
384374
ext := ".tar.gz"
385375

@@ -761,6 +751,10 @@ func doDebianSource(cmdline []string) {
761751
// to bootstrap the builder Go.
762752
func downloadGoBootstrapSources(cachedir string) string {
763753
csdb := build.MustLoadChecksums("build/checksums.txt")
754+
gobootVersion, err := build.Version(csdb, "ppa-builder")
755+
if err != nil {
756+
log.Fatal(err)
757+
}
764758
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
765759
url := "https://dl.google.com/go/" + file
766760
dst := filepath.Join(cachedir, file)
@@ -773,6 +767,10 @@ func downloadGoBootstrapSources(cachedir string) string {
773767
// downloadGoSources downloads the Go source tarball.
774768
func downloadGoSources(cachedir string) string {
775769
csdb := build.MustLoadChecksums("build/checksums.txt")
770+
dlgoVersion, err := build.Version(csdb, "golang")
771+
if err != nil {
772+
log.Fatal(err)
773+
}
776774
file := fmt.Sprintf("go%s.src.tar.gz", dlgoVersion)
777775
url := "https://dl.google.com/go/" + file
778776
dst := filepath.Join(cachedir, file)
@@ -1099,3 +1097,7 @@ func doPurge(cmdline []string) {
10991097
log.Fatal(err)
11001098
}
11011099
}
1100+
1101+
func doSanityCheck() {
1102+
build.DownloadAndVerifyChecksums(build.MustLoadChecksums("build/checksums.txt"))
1103+
}

cmd/clef/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ func GenDoc(ctx *cli.Context) error {
12061206
URL: accounts.URL{Path: ".. ignored .."},
12071207
},
12081208
{
1209-
Address: common.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff"),
1209+
Address: common.MaxAddress,
12101210
},
12111211
}})
12121212
}

cmd/devp2p/dns_cloudflare.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
114114
records = lrecords
115115

116116
log.Info(fmt.Sprintf("Retrieving existing TXT records on %s", name))
117-
entries, err := c.DNSRecords(context.Background(), c.zoneID, cloudflare.DNSRecord{Type: "TXT"})
117+
entries, _, err := c.ListDNSRecords(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), cloudflare.ListDNSRecordsParams{Type: "TXT"})
118118
if err != nil {
119119
return err
120120
}
@@ -141,14 +141,25 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
141141
if path != name {
142142
ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare
143143
}
144-
record := cloudflare.DNSRecord{Type: "TXT", Name: path, Content: val, TTL: ttl}
145-
_, err = c.CreateDNSRecord(context.Background(), c.zoneID, record)
144+
record := cloudflare.CreateDNSRecordParams{Type: "TXT", Name: path, Content: val, TTL: ttl}
145+
_, err = c.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), record)
146146
} else if old.Content != val {
147147
// Entry already exists, only change its content.
148148
log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
149149
updated++
150-
old.Content = val
151-
err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old)
150+
151+
record := cloudflare.UpdateDNSRecordParams{
152+
Type: old.Type,
153+
Name: old.Name,
154+
Content: val,
155+
Data: old.Data,
156+
ID: old.ID,
157+
Priority: old.Priority,
158+
TTL: old.TTL,
159+
Proxied: old.Proxied,
160+
Tags: old.Tags,
161+
}
162+
_, err = c.UpdateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), record)
152163
} else {
153164
skipped++
154165
log.Debug(fmt.Sprintf("Skipping %s = %q", path, val))
@@ -168,7 +179,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
168179
// Stale entry, nuke it.
169180
log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content))
170181
deleted++
171-
if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil {
182+
if err := c.DeleteDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), entry.ID); err != nil {
172183
return fmt.Errorf("failed to delete %s: %v", path, err)
173184
}
174185
}

cmd/devp2p/internal/ethtest/snap.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ type accRangeTest struct {
5858
func (s *Suite) TestSnapGetAccountRange(t *utesting.T) {
5959
var (
6060
root = s.chain.RootAt(999)
61-
ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
61+
ffHash = common.MaxHash
6262
zero = common.Hash{}
6363
firstKeyMinus1 = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf29")
6464
firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a")
@@ -125,7 +125,7 @@ type stRangesTest struct {
125125
// TestSnapGetStorageRanges various forms of GetStorageRanges requests.
126126
func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) {
127127
var (
128-
ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
128+
ffHash = common.MaxHash
129129
zero = common.Hash{}
130130
firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a")
131131
secondKey = common.HexToHash("0x09e47cd5056a689e708f22fe1f932709a320518e444f5f7d8d46a3da523d6606")
@@ -536,11 +536,7 @@ func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error {
536536
}
537537
proofdb := nodes.Set()
538538

539-
var end []byte
540-
if len(keys) > 0 {
541-
end = keys[len(keys)-1]
542-
}
543-
_, err = trie.VerifyRangeProof(tc.root, tc.origin[:], end, keys, accounts, proofdb)
539+
_, err = trie.VerifyRangeProof(tc.root, tc.origin[:], keys, accounts, proofdb)
544540
return err
545541
}
546542

cmd/evm/blockrunner.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323
"os"
24+
"sort"
2425

2526
"github.com/ethereum/go-ethereum/core/rawdb"
2627
"github.com/ethereum/go-ethereum/core/vm"
@@ -60,9 +61,16 @@ func blockTestCmd(ctx *cli.Context) error {
6061
if err = json.Unmarshal(src, &tests); err != nil {
6162
return err
6263
}
63-
for i, test := range tests {
64+
// run them in order
65+
var keys []string
66+
for key := range tests {
67+
keys = append(keys, key)
68+
}
69+
sort.Strings(keys)
70+
for _, name := range keys {
71+
test := tests[name]
6472
if err := test.Run(false, rawdb.HashScheme, tracer); err != nil {
65-
return fmt.Errorf("test %v: %w", i, err)
73+
return fmt.Errorf("test %v: %w", name, err)
6674
}
6775
}
6876
return nil

cmd/evm/testdata/8/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json
3232
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
3333
```
3434

35-
Simlarly, we can provide the input transactions via `stdin` instead of as file:
35+
Similarly, we can provide the input transactions via `stdin` instead of as file:
3636

3737
```
3838
$ dir=./testdata/8 \

cmd/utils/flags.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -961,17 +961,12 @@ var (
961961
DataDirFlag,
962962
AncientFlag,
963963
RemoteDBFlag,
964+
DBEngineFlag,
964965
StateSchemeFlag,
965966
HttpHeaderFlag,
966967
}
967968
)
968969

969-
func init() {
970-
if rawdb.PebbleEnabled {
971-
DatabaseFlags = append(DatabaseFlags, DBEngineFlag)
972-
}
973-
}
974-
975970
// MakeDataDir retrieves the currently requested data directory, terminating
976971
// if none (or the empty string) is specified. If the node is starting a testnet,
977972
// then a subdirectory of the specified datadir will be used.

common/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ const (
4444
var (
4545
hashT = reflect.TypeOf(Hash{})
4646
addressT = reflect.TypeOf(Address{})
47+
48+
// MaxAddress represents the maximum possible address value.
49+
MaxAddress = HexToAddress("0xffffffffffffffffffffffffffffffffffffffff")
50+
51+
// MaxHash represents the maximum possible hash value.
52+
MaxHash = HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
4753
)
4854

4955
// Hash represents the 32 byte Keccak256 hash of arbitrary data.

core/rawdb/database.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/ethereum/go-ethereum/ethdb"
3131
"github.com/ethereum/go-ethereum/ethdb/leveldb"
3232
"github.com/ethereum/go-ethereum/ethdb/memorydb"
33+
"github.com/ethereum/go-ethereum/ethdb/pebble"
3334
"github.com/ethereum/go-ethereum/log"
3435
"github.com/olekukonko/tablewriter"
3536
)
@@ -321,6 +322,16 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r
321322
return NewDatabase(db), nil
322323
}
323324

325+
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
326+
// moving immutable chain segments into cold storage.
327+
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool) (ethdb.Database, error) {
328+
db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral)
329+
if err != nil {
330+
return nil, err
331+
}
332+
return NewDatabase(db), nil
333+
}
334+
324335
const (
325336
dbPebble = "pebble"
326337
dbLeveldb = "leveldb"
@@ -375,26 +386,16 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
375386
return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb)
376387
}
377388
if o.Type == dbPebble || existingDb == dbPebble {
378-
if PebbleEnabled {
379-
log.Info("Using pebble as the backing database")
380-
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
381-
} else {
382-
return nil, errors.New("db.engine 'pebble' not supported on this platform")
383-
}
389+
log.Info("Using pebble as the backing database")
390+
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
384391
}
385392
if o.Type == dbLeveldb || existingDb == dbLeveldb {
386393
log.Info("Using leveldb as the backing database")
387394
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
388395
}
389-
// No pre-existing database, no user-requested one either. Default to Pebble
390-
// on supported platforms and LevelDB on anything else.
391-
if PebbleEnabled {
392-
log.Info("Defaulting to pebble as the backing database")
393-
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
394-
} else {
395-
log.Info("Defaulting to leveldb as the backing database")
396-
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
397-
}
396+
// No pre-existing database, no user-requested one either. Default to Pebble.
397+
log.Info("Defaulting to pebble as the backing database")
398+
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
398399
}
399400

400401
// Open opens both a disk-based key-value database such as leveldb or pebble, but also

0 commit comments

Comments
 (0)