Unverified Commit 3c507063 authored by Will's avatar Will Committed by GitHub

fuzzing harness (#153)

Adds a go-fuzz entrypoint for fuzzing datastore transactions for crashes.
parent 799f546c
provider_*.go
*.zip
corpus
crashers
suppressions
IPFS Datastore Fuzzer
====
The fuzzer provides a [go fuzzer](https://github.com/dvyukov/go-fuzz) interface
to Datastore implementations. This can be used for fuzz testing of these
implementations.
Usage
----
First, configure the datastores to fuzz (from this directory):
```golang
// either run via `go run`
go run ./cmd/generate github.com/ipfs/go-ds-badger
// or `go generate`
DS_PROVIDERS="github.com/ipfs/go-ds-badger" go generate
```
Then, build the fuzzing artifact and fuzz:
```golang
go-fuzz-build
go-fuzz
```
If you don't have `go-fuzz` installed, it can be acquired as:
```
go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
```
package main
import (
"fmt"
"io/ioutil"
"os"
ds "github.com/ipfs/go-datastore"
fuzzer "github.com/ipfs/go-datastore/fuzz"
dsq "github.com/ipfs/go-datastore/query"
"github.com/spf13/pflag"
)
var input *string = pflag.StringP("input", "i", "", "file to read input from (stdin used if not specified)")
var db1 *string = pflag.StringP("db1", "d", "badger", "database to fuzz")
var db2 *string = pflag.StringP("db2", "e", "level", "database to fuzz")
var dbFile *string = pflag.StringP("file", "f", "tmp", "where the db instances should live on disk")
var threads *int = pflag.IntP("threads", "t", 1, "concurrent threads")
func main() {
pflag.Parse()
// do one, then the other, then compare state.
fuzzer.Threads = *threads
var dat []byte
var err error
if *input == "" {
dat, err = ioutil.ReadAll(os.Stdin)
} else {
dat, err = ioutil.ReadFile(*input)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Could not read %s: %v\n", *input, err)
return
}
db1loc := *dbFile + "1"
inst1, err := fuzzer.Open(*db1, db1loc, false)
if err != nil {
fmt.Fprintf(os.Stderr, "Could not open db: %v\n", err)
return
}
defer inst1.Cancel()
db2loc := *dbFile + "2"
inst2, err := fuzzer.Open(*db2, db2loc, false)
if err != nil {
inst1.Cancel()
fmt.Fprintf(os.Stderr, "Could not open db: %v\n", err)
return
}
defer inst2.Cancel()
fmt.Printf("Running db1.........")
inst1.Fuzz(dat)
fmt.Printf("done\n")
fmt.Printf("Running db2.........")
inst2.Fuzz(dat)
fmt.Printf("done\n")
fmt.Printf("Checking equality...")
db1 := inst1.DB()
db2 := inst2.DB()
r1, err := db1.Query(dsq.Query{})
if err != nil {
panic(err)
}
for r := range r1.Next() {
if r.Error != nil {
break
}
if r.Entry.Key == "/" {
continue
}
if exist, _ := db2.Has(ds.NewKey(r.Entry.Key)); !exist {
fmt.Fprintf(os.Stderr, "db2 failed to get key %s held by db1\n", r.Entry.Key)
}
}
r2, err := db2.Query(dsq.Query{})
if err != nil {
panic(err)
}
for r := range r2.Next() {
if r.Error != nil {
break
}
if r.Entry.Key == "/" {
continue
}
if exist, _ := db1.Has(ds.NewKey(r.Entry.Key)); !exist {
fmt.Fprintf(os.Stderr, "db1 failed to get key %s held by db2\n", r.Entry.Key)
}
}
fmt.Printf("Done\n")
}
// This file is invoked by `go generate`
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"text/template"
)
// This program generates bindings to fuzz a concrete datastore implementation.
// It can be invoked by running `go generate <implemenation>`
func main() {
providers := os.Args[1:]
if len(providers) == 0 {
providers = strings.Split(os.Getenv("DS_PROVIDERS"), ",")
}
if len(providers) == 0 {
fmt.Fprintf(os.Stderr, "No providers specified to generate. Nothing to do.")
return
}
for _, provider := range providers {
provider = strings.TrimSpace(provider)
if len(provider) == 0 {
continue
}
cmd := exec.Command("go", "get", provider)
err := cmd.Run()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to add dependency for %s: %v\n", provider, err)
os.Exit(1)
}
nameComponents := strings.Split(provider, "/")
name := nameComponents[len(nameComponents)-1]
f, err := os.Create(fmt.Sprintf("provider_%s.go", name))
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create provider file: %v\n", err)
os.Exit(1)
}
defer f.Close()
err = provideTemplate.Execute(f, struct {
Package string
PackageName string
}{
Package: provider,
PackageName: name,
})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to write provider: %v\n", err)
os.Exit(1)
}
}
}
var provideTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
package fuzzer
import prov "{{ .Package }}"
import ds "github.com/ipfs/go-datastore"
func init() {
AddOpener("{{ .PackageName }}", func(loc string) ds.TxnDatastore {
d, err := prov.NewDatastore(loc, nil)
if err != nil {
panic("could not create db instance")
}
return d
})
}
`))
package main
// Checks if a db instance is equivalent to some prefix of an input script.
import (
"fmt"
"io/ioutil"
"os"
ds "github.com/ipfs/go-datastore"
fuzzer "github.com/ipfs/go-datastore/fuzz"
dsq "github.com/ipfs/go-datastore/query"
"github.com/spf13/pflag"
)
var input *string = pflag.StringP("input", "i", "", "file to read input from (stdin used if not specified)")
var db *string = pflag.StringP("db", "d", "go-ds-badger", "database driver")
var dbPrev *string = pflag.StringP("exist", "e", "tmp1", "database instance already made")
var dbFile *string = pflag.StringP("file", "f", "tmp2", "where the replay should live")
var threads *int = pflag.IntP("threads", "t", 1, "concurrent threads")
type validatingReader struct {
b []byte
i int
validator func(bool) bool
validI int
}
func (v *validatingReader) Read(buf []byte) (n int, err error) {
if v.i == len(v.b) {
return 0, nil
}
if v.validator(false) {
v.validI = v.i
}
buf[0] = v.b[v.i]
v.i++
return 1, nil
}
func main() {
pflag.Parse()
fuzzer.Threads = *threads
var dat []byte
var err error
if *input == "" {
dat, err = ioutil.ReadAll(os.Stdin)
} else {
dat, err = ioutil.ReadFile(*input)
}
if err != nil {
fmt.Fprintf(os.Stderr, "could not read %s: %v\n", *input, err)
return
}
previousDB, err := fuzzer.Open(*db, *dbPrev, false)
if err != nil {
fmt.Fprintf(os.Stderr, "could not open: %v\n", err)
return
}
defer previousDB.Cancel()
replayDB, err := fuzzer.Open(*db, *dbFile, true)
if err != nil {
fmt.Fprintf(os.Stderr, "could not open: %v\n", err)
return
}
defer replayDB.Cancel()
reader := validatingReader{dat, 0, func(verbose bool) bool {
res, _ := replayDB.DB().Query(dsq.Query{})
for e := range res.Next() {
if e.Entry.Key == "/" {
continue
}
if h, _ := previousDB.DB().Has(ds.NewKey(e.Entry.Key)); !h {
if verbose {
fmt.Printf("failed - script run db has %s not in existing.\n", e.Entry.Key)
}
return false // not yet complete
}
}
// next; make sure the other way is equal.
res, _ = previousDB.DB().Query(dsq.Query{})
for e := range res.Next() {
if e.Entry.Key == "/" {
continue
}
if h, _ := replayDB.DB().Has(ds.NewKey(e.Entry.Key)); !h {
if verbose {
fmt.Printf("failed - existing db has %s not in replay.\n", e.Entry.Key)
}
return false
}
}
// db images are the same.
return true
}, -1}
replayDB.FuzzStream(&reader)
if reader.validator(true) {
reader.validI = reader.i
}
if reader.validI > -1 {
fmt.Printf("Matched at stream position %d.\n", reader.validI)
os.Exit(0)
} else {
fmt.Printf("Failed to match\n")
os.Exit(1)
}
}
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
fuzzer "github.com/ipfs/go-datastore/fuzz"
"github.com/spf13/pflag"
)
var input *string = pflag.StringP("input", "i", "", "file to read input from (stdin used if not specified)")
var db *string = pflag.StringP("database", "d", "go-ds-badger", "database to fuzz")
var dbFile *string = pflag.StringP("file", "f", "tmp", "where the db instace should live on disk")
var threads *int = pflag.IntP("threads", "t", 1, "concurrent threads")
func main() {
pflag.Parse()
fuzzer.Threads = *threads
if *input != "" {
dat, err := ioutil.ReadFile(*input)
if err != nil {
fmt.Fprintf(os.Stderr, "could not read %s: %v\n", *input, err)
os.Exit(1)
}
ret := fuzzer.FuzzDB(*db, *dbFile, false, dat)
os.Exit(ret)
} else {
reader := bufio.NewReader(os.Stdin)
err := fuzzer.FuzzStream(*db, *dbFile, false, reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Error fuzzing: %v\n", err)
os.Exit(1)
}
return
}
}
package fuzzer
import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"sync"
"sync/atomic"
ds "github.com/ipfs/go-datastore"
dsq "github.com/ipfs/go-datastore/query"
)
//go:generate go run ./cmd/generate
// openers contains the known datastore implementations.
var openers map[string]func(string) ds.TxnDatastore
// AddOpener allows registration of a new driver for fuzzing.
func AddOpener(name string, opener func(loc string) ds.TxnDatastore) {
if openers == nil {
openers = make(map[string]func(string) ds.TxnDatastore)
}
openers[name] = opener
}
// Threads is a measure of concurrency.
// Note: if Threads > 1, determinism is not guaranteed.
var Threads int
func init() {
if openers == nil {
openers = make(map[string]func(string) ds.TxnDatastore)
}
Threads = 1
}
// RunState encapulates the state of a given fuzzing run
type RunState struct {
inst ds.TxnDatastore
inputChannels []chan<- byte
wg sync.WaitGroup
Cancel context.CancelFunc
keyCache [128]ds.Key
cachedKeys int32
ctr int32 //nolint:structcheck,unused
}
// DB returns the datastore being driven by this instance
func (r *RunState) DB() ds.TxnDatastore {
return r.inst
}
type threadState struct {
op
keyReady bool
key ds.Key
valReady bool
val []byte
reader ds.Read
writer ds.Write
txn ds.Txn
*RunState
}
// Open instantiates an instance of the database implementation for testing.
func Open(driver string, location string, cleanup bool) (*RunState, error) {
ctx, cncl := context.WithCancel(context.Background())
opener, ok := openers[driver]
if !ok {
cncl()
return nil, fmt.Errorf("no such driver: %s", driver)
}
state := RunState{}
state.inst = opener(location)
state.keyCache[0] = ds.NewKey("/")
state.cachedKeys = 1
state.wg.Add(Threads)
// wrap the context cancel to block until everythign is fully closed.
doneCh := make(chan struct{})
state.Cancel = func() {
for i := 0; i < Threads; i++ {
close(state.inputChannels[i])
}
cncl()
<-doneCh
}
go func() {
state.wg.Wait()
state.inst.Close()
if cleanup {
os.RemoveAll(location)
}
close(doneCh)
}()
state.inputChannels = make([]chan<- byte, Threads)
for i := 0; i < Threads; i++ {
dr := make(chan byte, 15)
go threadDriver(ctx, &state, dr)
state.inputChannels[i] = dr
}
return &state, nil
}
// Fuzz is a go-fuzzer compatible input point for replaying
// data (interpreted as a script of commands)
// to known ipfs datastore implementations
func Fuzz(data []byte) int {
var impls []string
for impl := range openers {
impls = append(impls, impl)
}
defaultLoc, _ := ioutil.TempDir("", "fuzz-*")
if len(impls) == 0 {
fmt.Fprintf(os.Stderr, "No datastores to fuzz.\n")
return -1
} else if len(impls) == 1 {
return FuzzDB(impls[0], defaultLoc, true, data)
} else {
impl := impls[int(data[0])%len(impls)]
return FuzzDB(impl, defaultLoc, true, data[1:])
}
}
// FuzzDB fuzzes a given database entry, providing sufficient hooks to be
// used by CLI commands.
func FuzzDB(driver string, location string, cleanup bool, data []byte) int {
inst, err := Open(driver, location, cleanup)
if err != nil {
return -1
}
inst.Fuzz(data)
inst.Cancel()
return 0
}
// FuzzStream does the same as fuzz but with streaming input
func FuzzStream(driver string, location string, cleanup bool, data io.Reader) error {
inst, err := Open("badger", "tmp", true)
if err != nil {
return err
}
inst.FuzzStream(data)
inst.Cancel()
return nil
}
// Fuzz sends a set of bytes to drive the current open datastore instance.
func (r *RunState) Fuzz(data []byte) {
for i, b := range data {
r.inputChannels[i%Threads] <- b
}
}
// FuzzStream sends a set of bytes to drive the current instance from a reader.
func (r *RunState) FuzzStream(data io.Reader) {
b := make([]byte, 4096)
for {
n, _ := data.Read(b)
if n == 0 {
break
}
r.Fuzz(b[:n])
}
}
type op byte
const (
opNone op = iota
opGet
opHas
opGetSize
opQuery
opPut
opDelete
opNewTX
opCommitTX
opDiscardTX
opSync
opMax
)
func threadDriver(ctx context.Context, runState *RunState, cmnds chan byte) {
defer runState.wg.Done()
s := threadState{}
s.RunState = runState
s.reader = runState.inst
s.writer = runState.inst
for {
select {
case c, ok := <-cmnds:
if !ok {
return
}
_ = nextState(&s, c)
case <-ctx.Done():
return
}
}
}
func nextState(s *threadState, c byte) error {
if s.op == opNone {
s.op = op(c) % opMax
return nil
} else if s.op == opGet {
if !s.keyReady {
return makeKey(s, c)
}
_, _ = s.reader.Get(s.key)
reset(s)
return nil
} else if s.op == opHas {
if !s.keyReady {
return makeKey(s, c)
}
_, _ = s.reader.Has(s.key)
reset(s)
return nil
} else if s.op == opGetSize {
if !s.keyReady {
return makeKey(s, c)
}
_, _ = s.reader.GetSize(s.key)
reset(s)
return nil
} else if s.op == opQuery {
r, _ := s.reader.Query(dsq.Query{})
defer r.Close()
reset(s)
for e := range r.Next() {
if e.Error != nil {
return nil
}
}
return nil
} else if s.op == opPut {
if !s.keyReady {
return makeKey(s, c)
}
if !s.valReady {
return makeValue(s, c)
}
_ = s.writer.Put(s.key, s.val)
reset(s)
return nil
} else if s.op == opDelete {
if !s.keyReady {
return makeKey(s, c)
}
_ = s.writer.Delete(s.key)
reset(s)
return nil
} else if s.op == opNewTX {
if s.txn == nil {
s.txn, _ = s.RunState.inst.NewTransaction(((c & 1) == 1))
if (c & 1) != 1 { // read+write
s.writer = s.txn
}
s.reader = s.txn
}
reset(s)
return nil
} else if s.op == opCommitTX {
if s.txn != nil {
s.txn.Discard()
s.txn = nil
s.reader = s.RunState.inst
s.writer = s.RunState.inst
}
reset(s)
return nil
} else if s.op == opDiscardTX {
if s.txn != nil {
s.txn.Discard()
s.txn = nil
s.reader = s.RunState.inst
s.writer = s.RunState.inst
}
reset(s)
return nil
} else if s.op == opSync {
if !s.keyReady {
return makeKey(s, c)
}
_ = s.RunState.inst.Sync(s.key)
reset(s)
return nil
}
return nil
}
func reset(s *threadState) {
s.op = opNone
s.keyReady = false
s.key = ds.RawKey("")
s.valReady = false
}
func makeKey(s *threadState, c byte) error {
keys := atomic.LoadInt32(&s.RunState.cachedKeys)
if keys > 128 {
keys = 128
}
if c&1 == 1 {
// 50% chance we want to-reuse an existing key
s.key = s.RunState.keyCache[(c>>1)%byte(keys)]
s.keyReady = true
} else {
s.key = ds.NewKey(fmt.Sprintf("key-%d", atomic.AddInt32(&s.ctr, 1)))
// half the time we'll make it a child of an existing key
if c&2 == 2 {
s.key = s.RunState.keyCache[(c>>1)%byte(keys)].Child(s.key)
}
// new key
if keys < 128 {
keys = atomic.AddInt32(&s.RunState.cachedKeys, 1)
if keys >= 128 {
atomic.StoreInt32(&s.RunState.cachedKeys, 128)
} else {
s.RunState.keyCache[keys-1] = s.key
}
}
s.keyReady = true
}
return nil
}
func makeValue(s *threadState, c byte) error {
s.val = make([]byte, c)
if c != 0 {
s.val[0] = 1
}
s.valReady = true
return nil
}
module github.com/ipfs/go-datastore/fuzz
go 1.14
replace github.com/ipfs/go-datastore => ../
require (
github.com/ipfs/go-datastore v0.4.4
github.com/ipfs/go-ds-badger v0.2.4
github.com/spf13/pflag v1.0.3
)
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg=
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8=
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-ds-badger v0.2.4 h1:UPGB0y7luFHk+mY/tUZrif/272M8o+hFsW+avLUeWrM=
github.com/ipfs/go-ds-badger v0.2.4/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc=
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
......@@ -3,7 +3,8 @@ module github.com/ipfs/go-datastore
require (
github.com/google/uuid v1.1.1
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8
github.com/jbenet/goprocess v0.1.4
github.com/kr/pretty v0.2.0 // indirect
go.uber.org/multierr v1.5.0
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
......
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8 h1:NAviDvJ0WXgD+yiL2Rj35AmnfgI11+pHXbdciD917U0=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw=
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
......@@ -48,7 +39,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......@@ -56,5 +46,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment