diff --git a/.circleci/config.yml b/.circleci/config.yml index e1ec7e57fb7..bb8fe945c74 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,22 +3,136 @@ orbs: go: gotest/tools@0.0.9 +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + - go/install: {package: bzr} + prepare: + steps: + - checkout + - run: git submodule sync + - run: git submodule update --init + + jobs: mod-tidy-check: executor: go/circleci-golang steps: - - go/install-ssh - - checkout + - install-deps + - prepare - go/mod-download - go/mod-tidy-check + test: + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: go/circleci-golang + go-test-flags: + type: string + default: "" + description: Flags passed to go test. + packages: + type: string + default: "./..." + description: Import paths of packages to be tested. + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + gotestsum-format: + type: string + default: short + description: gotestsum format. https://github.com/gotestyourself/gotestsum#format + coverage: + type: string + default: -coverprofile=coverage.txt + description: Coverage flag. Set to the empty string to disable. + codecov-upload: + type: boolean + default: false + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - run: make deps + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: go test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + GOTESTSUM_FORMAT: << parameters.gotestsum-format >> + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + gotestsum -- \ + << parameters.coverage >> \ + << parameters.go-test-flags >> \ + << parameters.packages >> + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + + lint: + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: go/circleci-golang + golangci-lint-version: + type: string + default: 1.17.1 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - run: make deps + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + + workflows: version: 2 ci: jobs: - - go/lint: - golangci-lint-version: 1.17.1 - - go/test: - executor: go/circleci-golang + - lint + - lint: + args: "--no-config --exclude-use-default=false --disable-all --enable golint" + - test: codecov-upload: true - mod-tidy-check diff --git a/.gitignore b/.gitignore index a8ed1beda71..188904e8fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ lotus +**/*.h +**/*.a +**/*.pc diff --git a/.golangci.yml b/.golangci.yml index dcc21617942..f873557aa38 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -20,12 +20,16 @@ issues: exclude: - "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this" - "Potential file inclusion via variable" + - "should have( a package)? comment" exclude-use-default: false exclude-rules: - path: node/modules/lp2p linters: - golint + - path: ".*_test.go" + linters: + - gosec linters-settings: goconst: diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..9011ca7a6d5 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +all: build + +blssigs: lib/bls-signatures/include/libbls_signatures.h + +lib/bls-signatures/include/libbls_signatures.h: lib/bls-signatures/bls-signatures ; + ./scripts/install-bls-signatures.sh + +deps: blssigs + +build: deps + go build -o lotus ./cmd/lotus + +.PHONY: all build deps blssigs diff --git a/api/client/client.go b/api/client/client.go index 2aaa0557977..2dbc98f21aa 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -2,12 +2,12 @@ package client import ( "github.com/filecoin-project/go-lotus/api" - "github.com/filecoin-project/go-lotus/rpclib" + "github.com/filecoin-project/go-lotus/lib/jsonrpc" ) // NewRPC creates a new http jsonrpc client. func NewRPC(addr string) api.API { var res api.Struct - rpclib.NewClient(addr, "Filecoin", &res.Internal) + jsonrpc.NewClient(addr, "Filecoin", &res.Internal) return &res } diff --git a/chain/actors.go b/chain/actors.go new file mode 100644 index 00000000000..87e9094ca38 --- /dev/null +++ b/chain/actors.go @@ -0,0 +1,111 @@ +package chain + +import ( + "context" + "fmt" + + "github.com/filecoin-project/go-lotus/chain/address" + + "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" + cbor "github.com/ipfs/go-ipld-cbor" + mh "github.com/multiformats/go-multihash" +) + +func init() { + cbor.RegisterCborType(InitActorState{}) + cbor.RegisterCborType(AccountActorState{}) +} + +var AccountActorCodeCid cid.Cid +var StorageMarketActorCodeCid cid.Cid +var StorageMinerCodeCid cid.Cid +var MultisigActorCodeCid cid.Cid +var InitActorCodeCid cid.Cid + +var InitActorAddress = mustIDAddress(0) +var NetworkAddress = mustIDAddress(1) +var StorageMarketAddress = mustIDAddress(2) + +func mustIDAddress(i uint64) address.Address { + a, err := address.NewIDAddress(i) + if err != nil { + panic(err) + } + return a +} + +func init() { + pref := cid.NewPrefixV1(cid.Raw, mh.ID) + mustSum := func(s string) cid.Cid { + c, err := pref.Sum([]byte(s)) + if err != nil { + panic(err) + } + return c + } + + AccountActorCodeCid = mustSum("account") + StorageMarketActorCodeCid = mustSum("smarket") + StorageMinerCodeCid = mustSum("sminer") + MultisigActorCodeCid = mustSum("multisig") + InitActorCodeCid = mustSum("init") +} + +type VMActor struct { +} + +type InitActorState struct { + AddressMap cid.Cid + + NextID uint64 +} + +func (ias *InitActorState) AddActor(vmctx *VMContext, addr address.Address) (address.Address, error) { + nid := ias.NextID + ias.NextID++ + + amap, err := hamt.LoadNode(context.TODO(), vmctx.Ipld(), ias.AddressMap) + if err != nil { + return address.Undef, err + } + + if err := amap.Set(context.TODO(), string(addr.Bytes()), nid); err != nil { + return address.Undef, err + } + + if err := amap.Flush(context.TODO()); err != nil { + return address.Undef, err + } + + ncid, err := vmctx.Ipld().Put(context.TODO(), amap) + if err != nil { + return address.Undef, err + } + ias.AddressMap = ncid + + return address.NewIDAddress(nid) +} + +func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) { + amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap) + if err != nil { + return address.Undef, err + } + + val, err := amap.Find(context.TODO(), string(addr.Bytes())) + if err != nil { + return address.Undef, err + } + + ival, ok := val.(uint64) + if !ok { + return address.Undef, fmt.Errorf("invalid value in init actor state, expected uint64, got %T", val) + } + + return address.NewIDAddress(ival) +} + +type AccountActorState struct { + Address address.Address +} diff --git a/chain/address/address.go b/chain/address/address.go new file mode 100644 index 00000000000..f085779a5e1 --- /dev/null +++ b/chain/address/address.go @@ -0,0 +1,315 @@ +package address + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/filecoin-project/go-lotus/lib/bls-signatures" + + "github.com/filecoin-project/go-leb128" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/minio/blake2b-simd" + "github.com/polydawn/refmt/obj/atlas" +) + +func init() { + cbor.RegisterCborType(addressAtlasEntry) +} + +var addressAtlasEntry = atlas.BuildEntry(Address{}).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(a Address) ([]byte, error) { + return a.Bytes(), nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x []byte) (Address, error) { + return NewFromBytes(x) + })). + Complete() + +// Address is the go type that represents an address in the filecoin network. +type Address struct{ str string } + +// Undef is the type that represents an undefined address. +var Undef = Address{} + +// Network represents which network an address belongs to. +type Network = byte + +const ( + // Mainnet is the main network. + Mainnet Network = iota + // Testnet is the test network. + Testnet +) + +// MainnetPrefix is the main network prefix. +const MainnetPrefix = "f" + +// TestnetPrefix is the main network prefix. +const TestnetPrefix = "t" + +// Protocol represents which protocol an address uses. +type Protocol = byte + +const ( + // ID represents the address ID protocol. + ID Protocol = iota + // SECP256K1 represents the address SECP256K1 protocol. + SECP256K1 + // Actor represents the address Actor protocol. + Actor + // BLS represents the address BLS protocol. + BLS +) + +// Protocol returns the protocol used by the address. +func (a Address) Protocol() Protocol { + return a.str[0] +} + +// Payload returns the payload of the address. +func (a Address) Payload() []byte { + return []byte(a.str[1:]) +} + +// Bytes returns the address as bytes. +func (a Address) Bytes() []byte { + return []byte(a.str) +} + +// String returns an address encoded as a string. +func (a Address) String() string { + str, err := encode(Testnet, a) + if err != nil { + panic(err) + } + return str +} + +// Empty returns true if the address is empty, false otherwise. +func (a Address) Empty() bool { + return a == Undef +} + +// Unmarshal unmarshals the cbor bytes into the address. +func (a Address) Unmarshal(b []byte) error { + return cbor.DecodeInto(b, &a) +} + +// Marshal marshals the address to cbor. +func (a Address) Marshal() ([]byte, error) { + return cbor.DumpObject(a) +} + +// UnmarshalJSON implements the json unmarshal interface. +func (a *Address) UnmarshalJSON(b []byte) error { + in := strings.TrimSuffix(strings.TrimPrefix(string(b), `"`), `"`) + addr, err := decode(in) + if err != nil { + return err + } + *a = addr + return nil +} + +// MarshalJSON implements the json marshal interface. +func (a Address) MarshalJSON() ([]byte, error) { + return json.Marshal(a.String()) +} + +// Format implements the Formatter interface. +func (a Address) Format(f fmt.State, c rune) { + switch c { + case 'v': + if a.Empty() { + fmt.Fprint(f, UndefAddressString) //nolint: errcheck + } else { + fmt.Fprintf(f, "[%x - %x]", a.Protocol(), a.Payload()) // nolint: errcheck + } + case 's': + fmt.Fprintf(f, "%s", a.String()) // nolint: errcheck + default: + fmt.Fprintf(f, "%"+string(c), a.Bytes()) // nolint: errcheck + } +} + +// NewIDAddress returns an address using the ID protocol. +func NewIDAddress(id uint64) (Address, error) { + return newAddress(ID, leb128.FromUInt64(id)) +} + +// NewSecp256k1Address returns an address using the SECP256K1 protocol. +func NewSecp256k1Address(pubkey []byte) (Address, error) { + return newAddress(SECP256K1, addressHash(pubkey)) +} + +// NewActorAddress returns an address using the Actor protocol. +func NewActorAddress(data []byte) (Address, error) { + return newAddress(Actor, addressHash(data)) +} + +// NewBLSAddress returns an address using the BLS protocol. +func NewBLSAddress(pubkey []byte) (Address, error) { + return newAddress(BLS, pubkey) +} + +// NewFromString returns the address represented by the string `addr`. +func NewFromString(addr string) (Address, error) { + return decode(addr) +} + +// NewFromBytes return the address represented by the bytes `addr`. +func NewFromBytes(addr []byte) (Address, error) { + if len(addr) == 0 { + return Undef, nil + } + if len(addr) == 1 { + return Undef, ErrInvalidLength + } + return newAddress(addr[0], addr[1:]) +} + +// Checksum returns the checksum of `ingest`. +func Checksum(ingest []byte) []byte { + return hash(ingest, checksumHashConfig) +} + +// ValidateChecksum returns true if the checksum of `ingest` is equal to `expected`> +func ValidateChecksum(ingest, expect []byte) bool { + digest := Checksum(ingest) + return bytes.Equal(digest, expect) +} + +func addressHash(ingest []byte) []byte { + return hash(ingest, payloadHashConfig) +} + +func newAddress(protocol Protocol, payload []byte) (Address, error) { + switch protocol { + case ID: + case SECP256K1, Actor: + if len(payload) != PayloadHashLength { + return Undef, ErrInvalidPayload + } + case BLS: + if len(payload) != bls.PublicKeyBytes { + return Undef, ErrInvalidPayload + } + default: + return Undef, ErrUnknownProtocol + } + explen := 1 + len(payload) + buf := make([]byte, explen) + + buf[0] = protocol + copy(buf[1:], payload) + + return Address{string(buf)}, nil +} + +func encode(network Network, addr Address) (string, error) { + if addr == Undef { + return UndefAddressString, nil + } + var ntwk string + switch network { + case Mainnet: + ntwk = MainnetPrefix + case Testnet: + ntwk = TestnetPrefix + default: + return UndefAddressString, ErrUnknownNetwork + } + + var strAddr string + switch addr.Protocol() { + case SECP256K1, Actor, BLS: + cksm := Checksum(append([]byte{addr.Protocol()}, addr.Payload()...)) + strAddr = ntwk + fmt.Sprintf("%d", addr.Protocol()) + AddressEncoding.WithPadding(-1).EncodeToString(append(addr.Payload(), cksm[:]...)) + case ID: + strAddr = ntwk + fmt.Sprintf("%d", addr.Protocol()) + fmt.Sprintf("%d", leb128.ToUInt64(addr.Payload())) + default: + return UndefAddressString, ErrUnknownProtocol + } + return strAddr, nil +} + +func decode(a string) (Address, error) { + if len(a) == 0 { + return Undef, nil + } + if a == UndefAddressString { + return Undef, nil + } + if len(a) > MaxAddressStringLength || len(a) < 3 { + return Undef, ErrInvalidLength + } + + if string(a[0]) != MainnetPrefix && string(a[0]) != TestnetPrefix { + return Undef, ErrUnknownNetwork + } + + var protocol Protocol + switch a[1] { + case '0': + protocol = ID + case '1': + protocol = SECP256K1 + case '2': + protocol = Actor + case '3': + protocol = BLS + default: + return Undef, ErrUnknownProtocol + } + + raw := a[2:] + if protocol == ID { + // 20 is length of math.MaxUint64 as a string + if len(raw) > 20 { + return Undef, ErrInvalidLength + } + id, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return Undef, ErrInvalidPayload + } + return newAddress(protocol, leb128.FromUInt64(id)) + } + + payloadcksm, err := AddressEncoding.WithPadding(-1).DecodeString(raw) + if err != nil { + return Undef, err + } + payload := payloadcksm[:len(payloadcksm)-ChecksumHashLength] + cksm := payloadcksm[len(payloadcksm)-ChecksumHashLength:] + + if protocol == SECP256K1 || protocol == Actor { + if len(payload) != 20 { + return Undef, ErrInvalidPayload + } + } + + if !ValidateChecksum(append([]byte{protocol}, payload...), cksm) { + return Undef, ErrInvalidChecksum + } + + return newAddress(protocol, payload) +} + +func hash(ingest []byte, cfg *blake2b.Config) []byte { + hasher, err := blake2b.New(cfg) + if err != nil { + // If this happens sth is very wrong. + panic(fmt.Sprintf("invalid address hash configuration: %v", err)) + } + if _, err := hasher.Write(ingest); err != nil { + // blake2bs Write implementation never returns an error in its current + // setup. So if this happens sth went very wrong. + panic(fmt.Sprintf("blake2b is unable to process hashes: %v", err)) + } + return hasher.Sum(nil) +} diff --git a/chain/address/address_test.go b/chain/address/address_test.go new file mode 100644 index 00000000000..c551165446b --- /dev/null +++ b/chain/address/address_test.go @@ -0,0 +1,429 @@ +package address + +import ( + "encoding/base32" + "fmt" + "math" + "math/rand" + "strconv" + "testing" + "time" + + "github.com/filecoin-project/go-leb128" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-lotus/lib/bls-signatures" + "github.com/filecoin-project/go-lotus/lib/crypto" +) + +func init() { + rand.Seed(time.Now().Unix()) +} + +func TestRandomIDAddress(t *testing.T) { + assert := assert.New(t) + + addr, err := NewIDAddress(uint64(rand.Int())) + assert.NoError(err) + assert.Equal(ID, addr.Protocol()) + + str, err := encode(Testnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorsIDAddress(t *testing.T) { + testCases := []struct { + input uint64 + expected string + }{ + {uint64(0), "t00"}, + {uint64(1), "t01"}, + {uint64(10), "t010"}, + {uint64(150), "t0150"}, + {uint64(499), "t0499"}, + {uint64(1024), "t01024"}, + {uint64(1729), "t01729"}, + {uint64(999999), "t0999999"}, + {math.MaxUint64, fmt.Sprintf("t0%s", strconv.FormatUint(math.MaxUint64, 10))}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing actorID address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewIDAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(ID, maybeAddr.Protocol()) + assert.Equal(tc.input, leb128.ToUInt64(maybeAddr.Payload())) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } + +} + +func TestSecp256k1Address(t *testing.T) { + assert := assert.New(t) + + sk, err := crypto.GenerateKey() + assert.NoError(err) + + addr, err := NewSecp256k1Address(crypto.PublicKey(sk)) + assert.NoError(err) + assert.Equal(SECP256K1, addr.Protocol()) + + str, err := encode(Mainnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorSecp256k1Address(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{4, 148, 2, 250, 195, 126, 100, 50, 164, 22, 163, 160, 202, 84, + 38, 181, 24, 90, 179, 178, 79, 97, 52, 239, 162, 92, 228, 135, 200, + 45, 46, 78, 19, 191, 69, 37, 17, 224, 210, 36, 84, 33, 248, 97, 59, + 193, 13, 114, 250, 33, 102, 102, 169, 108, 59, 193, 57, 32, 211, + 255, 35, 63, 208, 188, 5}, + "t15ihq5ibzwki2b4ep2f46avlkrqzhpqgtga7pdrq"}, + + {[]byte{4, 118, 135, 185, 16, 55, 155, 242, 140, 190, 58, 234, 103, 75, + 18, 0, 12, 107, 125, 186, 70, 255, 192, 95, 108, 148, 254, 42, 34, + 187, 204, 38, 2, 255, 127, 92, 118, 242, 28, 165, 93, 54, 149, 145, + 82, 176, 225, 232, 135, 145, 124, 57, 53, 118, 238, 240, 147, 246, + 30, 189, 58, 208, 111, 127, 218}, + "t12fiakbhe2gwd5cnmrenekasyn6v5tnaxaqizq6a"}, + {[]byte{4, 222, 253, 208, 16, 1, 239, 184, 110, 1, 222, 213, 206, 52, + 248, 71, 167, 58, 20, 129, 158, 230, 65, 188, 182, 11, 185, 41, 147, + 89, 111, 5, 220, 45, 96, 95, 41, 133, 248, 209, 37, 129, 45, 172, + 65, 99, 163, 150, 52, 155, 35, 193, 28, 194, 255, 53, 157, 229, 75, + 226, 135, 234, 98, 49, 155}, + "t1wbxhu3ypkuo6eyp6hjx6davuelxaxrvwb2kuwva"}, + {[]byte{4, 3, 237, 18, 200, 20, 182, 177, 13, 46, 224, 157, 149, 180, + 104, 141, 178, 209, 128, 208, 169, 163, 122, 107, 106, 125, 182, 61, + 41, 129, 30, 233, 115, 4, 121, 216, 239, 145, 57, 233, 18, 73, 202, + 189, 57, 50, 145, 207, 229, 210, 119, 186, 118, 222, 69, 227, 224, + 133, 163, 118, 129, 191, 54, 69, 210}, + "t1xtwapqc6nh4si2hcwpr3656iotzmlwumogqbuaa"}, + {[]byte{4, 247, 150, 129, 154, 142, 39, 22, 49, 175, 124, 24, 151, 151, + 181, 69, 214, 2, 37, 147, 97, 71, 230, 1, 14, 101, 98, 179, 206, 158, + 254, 139, 16, 20, 65, 97, 169, 30, 208, 180, 236, 137, 8, 0, 37, 63, + 166, 252, 32, 172, 144, 251, 241, 251, 242, 113, 48, 164, 236, 195, + 228, 3, 183, 5, 118}, + "t1xcbgdhkgkwht3hrrnui3jdopeejsoatkzmoltqy"}, + {[]byte{4, 66, 131, 43, 248, 124, 206, 158, 163, 69, 185, 3, 80, 222, + 125, 52, 149, 133, 156, 164, 73, 5, 156, 94, 136, 221, 231, 66, 133, + 223, 251, 158, 192, 30, 186, 188, 95, 200, 98, 104, 207, 234, 235, + 167, 174, 5, 191, 184, 214, 142, 183, 90, 82, 104, 120, 44, 248, 111, + 200, 112, 43, 239, 138, 31, 224}, + "t17uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing secp256k1 address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewSecp256k1Address(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(SECP256K1, maybeAddr.Protocol()) + assert.Equal(addressHash(tc.input), maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestRandomActorAddress(t *testing.T) { + assert := assert.New(t) + + actorMsg := make([]byte, 20) + rand.Read(actorMsg) + + addr, err := NewActorAddress(actorMsg) + assert.NoError(err) + assert.Equal(Actor, addr.Protocol()) + + str, err := encode(Mainnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorActorAddress(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{118, 18, 129, 144, 205, 240, 104, 209, 65, 128, 68, 172, 192, + 62, 11, 103, 129, 151, 13, 96}, + "t24vg6ut43yw2h2jqydgbg2xq7x6f4kub3bg6as6i"}, + {[]byte{44, 175, 184, 226, 224, 107, 186, 152, 234, 101, 124, 92, 245, + 244, 32, 35, 170, 35, 232, 142}, + "t25nml2cfbljvn4goqtclhifepvfnicv6g7mfmmvq"}, + {[]byte{2, 44, 158, 14, 162, 157, 143, 64, 197, 106, 190, 195, 92, 141, + 88, 125, 160, 166, 76, 24}, + "t2nuqrg7vuysaue2pistjjnt3fadsdzvyuatqtfei"}, + {[]byte{223, 236, 3, 14, 32, 79, 15, 89, 216, 15, 29, 94, 233, 29, 253, + 6, 109, 127, 99, 189}, + "t24dd4ox4c2vpf5vk5wkadgyyn6qtuvgcpxxon64a"}, + {[]byte{61, 58, 137, 232, 221, 171, 84, 120, 50, 113, 108, 109, 70, 140, + 53, 96, 201, 244, 127, 216}, + "t2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing Actor address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewActorAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(Actor, maybeAddr.Protocol()) + assert.Equal(addressHash(tc.input), maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestRandomBLSAddress(t *testing.T) { + assert := assert.New(t) + + pk := bls.PrivateKeyPublicKey(bls.PrivateKeyGenerate()) + + addr, err := NewBLSAddress(pk[:]) + assert.NoError(err) + assert.Equal(BLS, addr.Protocol()) + + str, err := encode(Mainnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorBLSAddress(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{173, 88, 223, 105, 110, 45, 78, 145, 234, 134, 200, 129, 233, 56, + 186, 78, 168, 27, 57, 94, 18, 121, 123, 132, 185, 207, 49, 75, 149, 70, + 112, 94, 131, 156, 122, 153, 214, 6, 178, 71, 221, 180, 249, 172, 122, + 52, 20, 221}, + "t3vvmn62lofvhjd2ugzca6sof2j2ubwok6cj4xxbfzz4yuxfkgobpihhd2thlanmsh3w2ptld2gqkn2jvlss4a"}, + {[]byte{179, 41, 79, 10, 46, 41, 224, 198, 110, 188, 35, 93, 47, 237, + 202, 86, 151, 191, 120, 74, 246, 5, 199, 90, 246, 8, 230, 166, 61, 92, + 211, 142, 168, 92, 168, 152, 158, 14, 253, 233, 24, 139, 56, 47, + 147, 114, 70, 13}, + "t3wmuu6crofhqmm3v4enos73okk2l366ck6yc4owxwbdtkmpk42ohkqxfitcpa57pjdcftql4tojda2poeruwa"}, + {[]byte{150, 161, 163, 228, 234, 122, 20, 212, 153, 133, 230, 97, 178, + 36, 1, 212, 79, 237, 64, 45, 29, 9, 37, 178, 67, 201, 35, 88, 156, + 15, 188, 126, 50, 205, 4, 226, 158, 215, 141, 21, 211, 125, 58, 170, + 63, 230, 218, 51}, + "t3s2q2hzhkpiknjgmf4zq3ejab2rh62qbndueslmsdzervrhapxr7dftie4kpnpdiv2n6tvkr743ndhrsw6d3a"}, + {[]byte{134, 180, 84, 37, 140, 88, 148, 117, 247, 209, 111, 90, 172, 1, + 138, 121, 246, 193, 22, 157, 32, 252, 51, 146, 29, 216, 181, 206, 28, + 172, 108, 52, 143, 144, 163, 96, 54, 36, 246, 174, 185, 27, 100, 81, + 140, 46, 128, 149}, + "t3q22fijmmlckhl56rn5nkyamkph3mcfu5ed6dheq53c244hfmnq2i7efdma3cj5voxenwiummf2ajlsbxc65a"}, + {[]byte{167, 114, 107, 3, 128, 34, 247, 90, 56, 70, 23, 88, 83, 96, 206, + 230, 41, 7, 10, 45, 157, 40, 113, 41, 101, 229, 242, 110, 204, 64, + 133, 131, 130, 128, 55, 36, 237, 52, 242, 114, 3, 54, 240, 157, 182, + 49, 240, 116}, + "t3u5zgwa4ael3vuocgc5mfgygo4yuqocrntuuhcklf4xzg5tcaqwbyfabxetwtj4tsam3pbhnwghyhijr5mixa"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing bls address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewBLSAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(BLS, maybeAddr.Protocol()) + assert.Equal(tc.input, maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestInvalidStringAddresses(t *testing.T) { + testCases := []struct { + input string + expetErr error + }{ + {"Q2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y", ErrUnknownNetwork}, + {"t4gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y", ErrUnknownProtocol}, + {"t2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr24y", ErrInvalidChecksum}, + {"t0banananananannnnnnnnn", ErrInvalidLength}, + {"t0banananananannnnnnnn", ErrInvalidPayload}, + {"t2gfvuyh7v2sx3patm1k23wdzmhyhtmqctasbr24y", base32.CorruptInputError(16)}, // '1' is not in base32 alphabet + {"t2gfvuyh7v2sx3paTm1k23wdzmhyhtmqctasbr24y", base32.CorruptInputError(14)}, // 'T' is not in base32 alphabet + {"t2", ErrInvalidLength}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing string address: %s", tc.expetErr), func(t *testing.T) { + assert := assert.New(t) + + _, err := NewFromString(tc.input) + assert.Equal(tc.expetErr, err) + }) + } + +} + +func TestInvalidByteAddresses(t *testing.T) { + testCases := []struct { + input []byte + expetErr error + }{ + // Unknown Protocol + {[]byte{4, 4, 4}, ErrUnknownProtocol}, + + // ID protocol + {[]byte{0}, ErrInvalidLength}, + + // SECP256K1 Protocol + {append([]byte{1}, make([]byte, PayloadHashLength-1)...), ErrInvalidPayload}, + {append([]byte{1}, make([]byte, PayloadHashLength+1)...), ErrInvalidPayload}, + // Actor Protocol + {append([]byte{2}, make([]byte, PayloadHashLength-1)...), ErrInvalidPayload}, + {append([]byte{2}, make([]byte, PayloadHashLength+1)...), ErrInvalidPayload}, + + // BLS Protocol + {append([]byte{3}, make([]byte, bls.PublicKeyBytes-1)...), ErrInvalidPayload}, + {append([]byte{3}, make([]byte, bls.PrivateKeyBytes+1)...), ErrInvalidPayload}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing byte address: %s", tc.expetErr), func(t *testing.T) { + assert := assert.New(t) + + _, err := NewFromBytes(tc.input) + assert.Equal(tc.expetErr, err) + }) + } + +} + +func TestChecksum(t *testing.T) { + assert := assert.New(t) + + data := []byte("helloworld") + bata := []byte("kittinmittins") + + cksm := Checksum(data) + assert.Len(cksm, ChecksumHashLength) + + assert.True(ValidateChecksum(data, cksm)) + assert.False(ValidateChecksum(bata, cksm)) + +} + +func TestAddressFormat(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + a, err := NewActorAddress([]byte("hello")) + require.NoError(err) + + assert.Equal("t2wvjry4bx6bwj6kkhcmvgu5zafqyi5cjzbtet3va", a.String()) + assert.Equal("02B5531C7037F06C9F2947132A6A77202C308E8939", fmt.Sprintf("%X", a)) + assert.Equal("[2 - b5531c7037f06c9f2947132a6a77202c308e8939]", fmt.Sprintf("%v", a)) + + assert.Equal("", fmt.Sprintf("%X", Undef)) + assert.Equal(UndefAddressString, Undef.String()) + assert.Equal(UndefAddressString, fmt.Sprintf("%v", Undef)) +} diff --git a/chain/address/constants.go b/chain/address/constants.go new file mode 100644 index 00000000000..64138688675 --- /dev/null +++ b/chain/address/constants.go @@ -0,0 +1,87 @@ +package address + +import ( + "encoding/base32" + + "github.com/minio/blake2b-simd" + errors "github.com/pkg/errors" +) + +func init() { + + var err error + + TestAddress, err = NewActorAddress([]byte("satoshi")) + if err != nil { + panic(err) + } + + TestAddress2, err = NewActorAddress([]byte("nakamoto")) + if err != nil { + panic(err) + } + + NetworkAddress, err = NewActorAddress([]byte("filecoin")) + if err != nil { + panic(err) + } + + StorageMarketAddress, err = NewActorAddress([]byte("storage")) + if err != nil { + panic(err) + } + + PaymentBrokerAddress, err = NewActorAddress([]byte("payments")) + if err != nil { + panic(err) + } +} + +var ( + // TestAddress is an account with some initial funds in it. + TestAddress Address + // TestAddress2 is an account with some initial funds in it. + TestAddress2 Address + + // NetworkAddress is the filecoin network. + NetworkAddress Address + // StorageMarketAddress is the hard-coded address of the filecoin storage market. + StorageMarketAddress Address + // PaymentBrokerAddress is the hard-coded address of the filecoin storage market. + PaymentBrokerAddress Address +) + +var ( + // ErrUnknownNetwork is returned when encountering an unknown network in an address. + ErrUnknownNetwork = errors.New("unknown address network") + + // ErrUnknownProtocol is returned when encountering an unknown protocol in an address. + ErrUnknownProtocol = errors.New("unknown address protocol") + // ErrInvalidPayload is returned when encountering an invalid address payload. + ErrInvalidPayload = errors.New("invalid address payload") + // ErrInvalidLength is returned when encountering an address of invalid length. + ErrInvalidLength = errors.New("invalid address length") + // ErrInvalidChecksum is returned when encountering an invalid address checksum. + ErrInvalidChecksum = errors.New("invalid address checksum") +) + +// UndefAddressString is the string used to represent an empty address when encoded to a string. +var UndefAddressString = "empty" + +// PayloadHashLength defines the hash length taken over addresses using the Actor and SECP256K1 protocols. +const PayloadHashLength = 20 + +// ChecksumHashLength defines the hash length used for calculating address checksums. +const ChecksumHashLength = 4 + +// MaxAddressStringLength is the max length of an address encoded as a string +// it include the network prefx, protocol, and bls publickey +const MaxAddressStringLength = 2 + 84 + +var payloadHashConfig = &blake2b.Config{Size: PayloadHashLength} +var checksumHashConfig = &blake2b.Config{Size: ChecksumHashLength} + +const encodeStd = "abcdefghijklmnopqrstuvwxyz234567" + +// AddressEncoding defines the base32 config used for address encoding and decoding. +var AddressEncoding = base32.NewEncoding(encodeStd) diff --git a/chain/address/testing.go b/chain/address/testing.go new file mode 100644 index 00000000000..9bc41376dce --- /dev/null +++ b/chain/address/testing.go @@ -0,0 +1,20 @@ +package address + +import ( + "fmt" +) + +// NewForTestGetter returns a closure that returns an address unique to that invocation. +// The address is unique wrt the closure returned, not globally. +func NewForTestGetter() func() Address { + i := 0 + return func() Address { + s := fmt.Sprintf("address%d", i) + i++ + newAddr, err := NewActorAddress([]byte(s)) + if err != nil { + panic(err) + } + return newAddr + } +} diff --git a/chain/blocksync.go b/chain/blocksync.go new file mode 100644 index 00000000000..14641fa9eb2 --- /dev/null +++ b/chain/blocksync.go @@ -0,0 +1,436 @@ +package chain + +import ( + "bufio" + "context" + "fmt" + "math/rand" + "sync" + + exchange "github.com/ipfs/go-ipfs-exchange-interface" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/protocol" + + "github.com/filecoin-project/go-lotus/lib/cborrpc" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" +) + +type NewStreamFunc func(context.Context, peer.ID, ...protocol.ID) (inet.Stream, error) + +const BlockSyncProtocolID = "/fil/sync/blk/0.0.1" + +func init() { + cbor.RegisterCborType(BlockSyncRequest{}) + cbor.RegisterCborType(BlockSyncResponse{}) + cbor.RegisterCborType(BSTipSet{}) +} + +type BlockSyncService struct { + cs *ChainStore +} + +type BlockSyncRequest struct { + Start []cid.Cid + RequestLength uint64 + + Options uint64 +} + +type BSOptions struct { + IncludeBlocks bool + IncludeMessages bool +} + +func ParseBSOptions(optfield uint64) *BSOptions { + return &BSOptions{ + IncludeBlocks: optfield&(BSOptBlocks) != 0, + IncludeMessages: optfield&(BSOptMessages) != 0, + } +} + +const ( + BSOptBlocks = 1 << 0 + BSOptMessages = 1 << 1 +) + +type BlockSyncResponse struct { + Chain []*BSTipSet + + Status uint + Message string +} + +type BSTipSet struct { + Blocks []*BlockHeader + + Messages []*SignedMessage + MsgIncludes [][]int +} + +func NewBlockSyncService(cs *ChainStore) *BlockSyncService { + return &BlockSyncService{ + cs: cs, + } +} + +func (bss *BlockSyncService) HandleStream(s inet.Stream) { + defer s.Close() + log.Error("handling block sync request") + + var req BlockSyncRequest + if err := cborrpc.ReadCborRPC(bufio.NewReader(s), &req); err != nil { + log.Errorf("failed to read block sync request: %s", err) + return + } + log.Errorf("block sync request for: %s %d", req.Start, req.RequestLength) + + resp, err := bss.processRequest(&req) + if err != nil { + log.Error("failed to process block sync request: ", err) + return + } + + if err := cborrpc.WriteCborRPC(s, resp); err != nil { + log.Error("failed to write back response for handle stream: ", err) + return + } +} + +func (bss *BlockSyncService) processRequest(req *BlockSyncRequest) (*BlockSyncResponse, error) { + opts := ParseBSOptions(req.Options) + chain, err := bss.collectChainSegment(req.Start, req.RequestLength, opts) + if err != nil { + log.Error("encountered error while responding to block sync request: ", err) + return &BlockSyncResponse{ + Status: 203, + }, nil + } + + return &BlockSyncResponse{ + Chain: chain, + Status: 0, + }, nil +} + +func (bss *BlockSyncService) collectChainSegment(start []cid.Cid, length uint64, opts *BSOptions) ([]*BSTipSet, error) { + var bstips []*BSTipSet + cur := start + for { + var bst BSTipSet + ts, err := bss.cs.LoadTipSet(cur) + if err != nil { + return nil, err + } + + if opts.IncludeMessages { + log.Error("INCLUDING MESSAGES IN SYNC RESPONSE") + msgs, mincl, err := bss.gatherMessages(ts) + if err != nil { + return nil, err + } + log.Errorf("messages: ", msgs) + + bst.Messages = msgs + bst.MsgIncludes = mincl + } + + if opts.IncludeBlocks { + log.Error("INCLUDING BLOCKS IN SYNC RESPONSE") + bst.Blocks = ts.Blocks() + } + + bstips = append(bstips, &bst) + + if uint64(len(bstips)) >= length || ts.Height() == 0 { + return bstips, nil + } + + cur = ts.Parents() + } +} + +func (bss *BlockSyncService) gatherMessages(ts *TipSet) ([]*SignedMessage, [][]int, error) { + msgmap := make(map[cid.Cid]int) + var allmsgs []*SignedMessage + var msgincl [][]int + + for _, b := range ts.Blocks() { + msgs, err := bss.cs.MessagesForBlock(b) + if err != nil { + return nil, nil, err + } + log.Errorf("MESSAGES FOR BLOCK: %d", len(msgs)) + + msgindexes := make([]int, 0, len(msgs)) + for _, m := range msgs { + i, ok := msgmap[m.Cid()] + if !ok { + i = len(allmsgs) + allmsgs = append(allmsgs, m) + msgmap[m.Cid()] = i + } + + msgindexes = append(msgindexes, i) + } + msgincl = append(msgincl, msgindexes) + } + + return allmsgs, msgincl, nil +} + +type BlockSync struct { + bswap exchange.Interface + newStream NewStreamFunc + + syncPeersLk sync.Mutex + syncPeers map[peer.ID]struct{} +} + +func NewBlockSyncClient(bswap exchange.Interface, h host.Host) *BlockSync { + return &BlockSync{ + bswap: bswap, + newStream: h.NewStream, + syncPeers: make(map[peer.ID]struct{}), + } +} + +func (bs *BlockSync) getPeers() []peer.ID { + bs.syncPeersLk.Lock() + defer bs.syncPeersLk.Unlock() + var out []peer.ID + for p := range bs.syncPeers { + out = append(out, p) + } + return out +} + +func (bs *BlockSync) GetBlocks(ctx context.Context, tipset []cid.Cid, count int) ([]*TipSet, error) { + peers := bs.getPeers() + perm := rand.Perm(len(peers)) + // TODO: round robin through these peers on error + + req := &BlockSyncRequest{ + Start: tipset, + RequestLength: uint64(count), + Options: BSOptBlocks, + } + + res, err := bs.sendRequestToPeer(ctx, peers[perm[0]], req) + if err != nil { + return nil, err + } + + switch res.Status { + case 0: // Success + return bs.processBlocksResponse(req, res) + case 101: // Partial Response + panic("not handled") + case 201: // req.Start not found + return nil, fmt.Errorf("not found") + case 202: // Go Away + panic("not handled") + case 203: // Internal Error + return nil, fmt.Errorf("block sync peer errored: %s", res.Message) + default: + return nil, fmt.Errorf("unrecognized response code") + } +} + +func (bs *BlockSync) GetFullTipSet(ctx context.Context, p peer.ID, h []cid.Cid) (*FullTipSet, error) { + // TODO: round robin through these peers on error + + req := &BlockSyncRequest{ + Start: h, + RequestLength: 1, + Options: BSOptBlocks | BSOptMessages, + } + + res, err := bs.sendRequestToPeer(ctx, p, req) + if err != nil { + return nil, err + } + + switch res.Status { + case 0: // Success + if len(res.Chain) == 0 { + return nil, fmt.Errorf("got zero length chain response") + } + bts := res.Chain[0] + + return bstsToFullTipSet(bts) + case 101: // Partial Response + panic("not handled") + case 201: // req.Start not found + return nil, fmt.Errorf("not found") + case 202: // Go Away + panic("not handled") + case 203: // Internal Error + return nil, fmt.Errorf("block sync peer errored: %s", res.Message) + default: + return nil, fmt.Errorf("unrecognized response code") + } +} + +func (bs *BlockSync) GetChainMessages(ctx context.Context, h *TipSet, count uint64) ([]*BSTipSet, error) { + peers := bs.getPeers() + perm := rand.Perm(len(peers)) + // TODO: round robin through these peers on error + + req := &BlockSyncRequest{ + Start: h.Cids(), + RequestLength: count, + Options: BSOptMessages, + } + + res, err := bs.sendRequestToPeer(ctx, peers[perm[0]], req) + if err != nil { + return nil, err + } + + switch res.Status { + case 0: // Success + return res.Chain, nil + case 101: // Partial Response + panic("not handled") + case 201: // req.Start not found + return nil, fmt.Errorf("not found") + case 202: // Go Away + panic("not handled") + case 203: // Internal Error + return nil, fmt.Errorf("block sync peer errored: %s", res.Message) + default: + return nil, fmt.Errorf("unrecognized response code") + } +} + +func bstsToFullTipSet(bts *BSTipSet) (*FullTipSet, error) { + fts := &FullTipSet{} + for i, b := range bts.Blocks { + fb := &FullBlock{ + Header: b, + } + for _, mi := range bts.MsgIncludes[i] { + fb.Messages = append(fb.Messages, bts.Messages[mi]) + } + fts.Blocks = append(fts.Blocks, fb) + } + + return fts, nil +} + +func (bs *BlockSync) sendRequestToPeer(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) { + s, err := bs.newStream(inet.WithNoDial(ctx, "should already have connection"), p, BlockSyncProtocolID) + if err != nil { + return nil, err + } + + if err := cborrpc.WriteCborRPC(s, req); err != nil { + return nil, err + } + + var res BlockSyncResponse + if err := cborrpc.ReadCborRPC(bufio.NewReader(s), &res); err != nil { + return nil, err + } + + return &res, nil +} + +func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSyncResponse) ([]*TipSet, error) { + cur, err := NewTipSet(res.Chain[0].Blocks) + if err != nil { + return nil, err + } + + out := []*TipSet{cur} + for bi := 1; bi < len(res.Chain); bi++ { + next := res.Chain[bi].Blocks + nts, err := NewTipSet(next) + if err != nil { + return nil, err + } + + if !cidArrsEqual(cur.Parents(), nts.Cids()) { + return nil, fmt.Errorf("parents of tipset[%d] were not tipset[%d]", bi-1, bi) + } + + out = append(out, nts) + cur = nts + } + return out, nil +} + +func cidArrsEqual(a, b []cid.Cid) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if b[i] != v { + return false + } + } + return true +} + +func (bs *BlockSync) GetBlock(ctx context.Context, c cid.Cid) (*BlockHeader, error) { + sb, err := bs.bswap.GetBlock(ctx, c) + if err != nil { + return nil, err + } + + return DecodeBlock(sb.RawData()) +} + +func (bs *BlockSync) AddPeer(p peer.ID) { + bs.syncPeersLk.Lock() + defer bs.syncPeersLk.Unlock() + bs.syncPeers[p] = struct{}{} +} + +func (bs *BlockSync) FetchMessagesByCids(cids []cid.Cid) ([]*SignedMessage, error) { + out := make([]*SignedMessage, len(cids)) + + resp, err := bs.bswap.GetBlocks(context.TODO(), cids) + if err != nil { + return nil, err + } + + m := make(map[cid.Cid]int) + for i, c := range cids { + m[c] = i + } + + for i := 0; i < len(cids); i++ { + select { + case v, ok := <-resp: + if !ok { + if i == len(cids)-1 { + break + } + + return nil, fmt.Errorf("failed to fetch all messages") + } + + sm, err := DecodeSignedMessage(v.RawData()) + if err != nil { + return nil, err + } + ix, ok := m[sm.Cid()] + if !ok { + return nil, fmt.Errorf("received message we didnt ask for") + } + + if out[ix] != nil { + return nil, fmt.Errorf("received duplicate message") + } + + out[ix] = sm + } + } + + return out, nil +} diff --git a/chain/buf_bstore.go b/chain/buf_bstore.go new file mode 100644 index 00000000000..3df152901c1 --- /dev/null +++ b/chain/buf_bstore.go @@ -0,0 +1,117 @@ +package chain + +import ( + "context" + + block "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + bstore "github.com/ipfs/go-ipfs-blockstore" +) + +type BufferedBS struct { + read bstore.Blockstore + write bstore.Blockstore +} + +func NewBufferedBstore(base bstore.Blockstore) *BufferedBS { + buf := bstore.NewBlockstore(ds.NewMapDatastore()) + return &BufferedBS{ + read: base, + write: buf, + } +} + +var _ (bstore.Blockstore) = &BufferedBS{} + +func (bs *BufferedBS) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + a, err := bs.read.AllKeysChan(ctx) + if err != nil { + return nil, err + } + + b, err := bs.write.AllKeysChan(ctx) + if err != nil { + return nil, err + } + + out := make(chan cid.Cid) + go func() { + defer close(out) + for a != nil || b != nil { + select { + case val, ok := <-a: + if !ok { + a = nil + } else { + select { + case out <- val: + case <-ctx.Done(): + return + } + } + case val, ok := <-b: + if !ok { + b = nil + } else { + select { + case out <- val: + case <-ctx.Done(): + return + } + } + } + } + }() + + return out, nil +} + +func (bs *BufferedBS) DeleteBlock(c cid.Cid) error { + if err := bs.read.DeleteBlock(c); err != nil { + return err + } + + return bs.write.DeleteBlock(c) +} + +func (bs *BufferedBS) Get(c cid.Cid) (block.Block, error) { + if out, err := bs.read.Get(c); err != nil { + if err != bstore.ErrNotFound { + return nil, err + } + } else { + return out, nil + } + + return bs.write.Get(c) +} + +func (bs *BufferedBS) GetSize(c cid.Cid) (int, error) { + panic("nyi") +} + +func (bs *BufferedBS) Put(blk block.Block) error { + return bs.write.Put(blk) +} + +func (bs *BufferedBS) Has(c cid.Cid) (bool, error) { + has, err := bs.read.Has(c) + if err != nil { + return false, err + } + if has { + return true, nil + } + + return bs.write.Has(c) +} + +func (bs *BufferedBS) HashOnRead(hor bool) { + bs.read.HashOnRead(hor) + bs.write.HashOnRead(hor) +} + +func (bs *BufferedBS) PutMany(blks []block.Block) error { + return bs.write.PutMany(blks) +} diff --git a/chain/chain.go b/chain/chain.go new file mode 100644 index 00000000000..86956ddc69c --- /dev/null +++ b/chain/chain.go @@ -0,0 +1,459 @@ +package chain + +import ( + "context" + "fmt" + "sync" + + "github.com/filecoin-project/go-lotus/chain/address" + + "github.com/ipfs/go-cid" + datastore "github.com/ipfs/go-datastore" + dstore "github.com/ipfs/go-datastore" + hamt "github.com/ipfs/go-hamt-ipld" + bstore "github.com/ipfs/go-ipfs-blockstore" + logging "github.com/ipfs/go-log" + "github.com/pkg/errors" + pubsub "github.com/whyrusleeping/pubsub" + sharray "github.com/whyrusleeping/sharray" +) + +const ForkLengthThreshold = 20 + +var log = logging.Logger("f2") + +type GenesisBootstrap struct { + Genesis *BlockHeader + MinerKey address.Address +} + +func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*Actor, error) { + var ias InitActorState + ias.NextID = 100 + + cst := hamt.CSTFromBstore(bs) + amap := hamt.NewNode(cst) + + for i, a := range addrs { + if err := amap.Set(context.TODO(), string(a.Bytes()), 100+uint64(i)); err != nil { + return nil, err + } + } + + ias.NextID += uint64(len(addrs)) + if err := amap.Flush(context.TODO()); err != nil { + return nil, err + } + amapcid, err := cst.Put(context.TODO(), amap) + if err != nil { + return nil, err + } + + ias.AddressMap = amapcid + + statecid, err := cst.Put(context.TODO(), &ias) + if err != nil { + return nil, err + } + + act := &Actor{ + Code: InitActorCodeCid, + Head: statecid, + } + + return act, nil +} + +func init() { + bs := bstore.NewBlockstore(dstore.NewMapDatastore()) + cst := hamt.CSTFromBstore(bs) + emptyobject, err := cst.Put(context.TODO(), map[string]string{}) + if err != nil { + panic(err) + } + + EmptyObjectCid = emptyobject +} + +var EmptyObjectCid cid.Cid + +func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) { + cst := hamt.CSTFromBstore(bs) + state, err := NewStateTree(cst) + if err != nil { + return nil, err + } + + emptyobject, err := cst.Put(context.TODO(), map[string]string{}) + if err != nil { + return nil, err + } + + minerAddr, err := w.GenerateKey(KTSecp256k1) + if err != nil { + return nil, err + } + + initact, err := SetupInitActor(bs, []address.Address{minerAddr}) + if err != nil { + return nil, err + } + + if err := state.SetActor(InitActorAddress, initact); err != nil { + return nil, err + } + + err = state.SetActor(NetworkAddress, &Actor{ + Code: AccountActorCodeCid, + Balance: NewInt(100000000000), + Head: emptyobject, + }) + if err != nil { + return nil, err + } + + err = state.SetActor(minerAddr, &Actor{ + Code: AccountActorCodeCid, + Balance: NewInt(5000000), + Head: emptyobject, + }) + if err != nil { + return nil, err + } + fmt.Println("about to flush state...") + + stateroot, err := state.Flush() + if err != nil { + return nil, err + } + fmt.Println("at end of make Genesis block") + + emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst) + if err != nil { + return nil, err + } + fmt.Println("Empty Genesis root: ", emptyroot) + + b := &BlockHeader{ + Miner: InitActorAddress, + Tickets: []Ticket{}, + ElectionProof: []byte("the Genesis block"), + Parents: []cid.Cid{}, + Height: 0, + ParentWeight: NewInt(0), + StateRoot: stateroot, + Messages: emptyroot, + MessageReceipts: emptyroot, + } + + sb, err := b.ToStorageBlock() + if err != nil { + return nil, err + } + + if err := bs.Put(sb); err != nil { + return nil, err + } + + return &GenesisBootstrap{ + Genesis: b, + MinerKey: minerAddr, + }, nil +} + +type ChainStore struct { + bs bstore.Blockstore + ds datastore.Datastore + + heaviestLk sync.Mutex + heaviest *TipSet + + bestTips *pubsub.PubSub + + headChange func(rev, app []*TipSet) error +} + +func NewChainStore(bs bstore.Blockstore, ds datastore.Batching) *ChainStore { + return &ChainStore{ + bs: bs, + ds: ds, + bestTips: pubsub.New(64), + } +} + +func (cs *ChainStore) SubNewTips() chan interface{} { + return cs.bestTips.Sub("best") +} + +func (cs *ChainStore) SetGenesis(b *BlockHeader) error { + gents, err := NewTipSet([]*BlockHeader{b}) + if err != nil { + return err + } + + fts := &FullTipSet{ + Blocks: []*FullBlock{ + {Header: b}, + }, + } + + cs.heaviest = gents + + if err := cs.PutTipSet(fts); err != nil { + return err + } + + return cs.ds.Put(datastore.NewKey("0"), b.Cid().Bytes()) +} + +func (cs *ChainStore) PutTipSet(ts *FullTipSet) error { + for _, b := range ts.Blocks { + if err := cs.persistBlock(b); err != nil { + return err + } + } + + cs.maybeTakeHeavierTipSet(ts.TipSet()) + return nil +} + +func (cs *ChainStore) maybeTakeHeavierTipSet(ts *TipSet) error { + cs.heaviestLk.Lock() + defer cs.heaviestLk.Unlock() + if cs.heaviest == nil || cs.Weight(ts) > cs.Weight(cs.heaviest) { + revert, apply, err := cs.ReorgOps(cs.heaviest, ts) + if err != nil { + return err + } + cs.headChange(revert, apply) + log.Errorf("New heaviest tipset! %s", ts.Cids()) + cs.heaviest = ts + } + return nil +} + +func (cs *ChainStore) Contains(ts *TipSet) (bool, error) { + for _, c := range ts.cids { + has, err := cs.bs.Has(c) + if err != nil { + return false, err + } + + if !has { + return false, nil + } + } + return true, nil +} + +func (cs *ChainStore) GetBlock(c cid.Cid) (*BlockHeader, error) { + sb, err := cs.bs.Get(c) + if err != nil { + return nil, err + } + + return DecodeBlock(sb.RawData()) +} + +func (cs *ChainStore) LoadTipSet(cids []cid.Cid) (*TipSet, error) { + var blks []*BlockHeader + for _, c := range cids { + b, err := cs.GetBlock(c) + if err != nil { + return nil, err + } + + blks = append(blks, b) + } + + return NewTipSet(blks) +} + +// returns true if 'a' is an ancestor of 'b' +func (cs *ChainStore) IsAncestorOf(a, b *TipSet) (bool, error) { + if b.Height() <= a.Height() { + return false, nil + } + + cur := b + for !a.Equals(cur) && cur.Height() > a.Height() { + next, err := cs.LoadTipSet(b.Parents()) + if err != nil { + return false, err + } + + cur = next + } + + return cur.Equals(a), nil +} + +func (cs *ChainStore) NearestCommonAncestor(a, b *TipSet) (*TipSet, error) { + l, _, err := cs.ReorgOps(a, b) + if err != nil { + return nil, err + } + + return cs.LoadTipSet(l[len(l)-1].Parents()) +} + +func (cs *ChainStore) ReorgOps(a, b *TipSet) ([]*TipSet, []*TipSet, error) { + left := a + right := b + + var leftChain, rightChain []*TipSet + for !left.Equals(right) { + if left.Height() > right.Height() { + leftChain = append(leftChain, left) + par, err := cs.LoadTipSet(left.Parents()) + if err != nil { + return nil, nil, err + } + + left = par + } else { + rightChain = append(rightChain, right) + par, err := cs.LoadTipSet(right.Parents()) + if err != nil { + return nil, nil, err + } + + right = par + } + } + + return leftChain, rightChain, nil +} + +func (cs *ChainStore) Weight(ts *TipSet) uint64 { + return ts.Blocks()[0].ParentWeight.Uint64() + uint64(len(ts.Cids())) +} + +func (cs *ChainStore) GetHeaviestTipSet() *TipSet { + cs.heaviestLk.Lock() + defer cs.heaviestLk.Unlock() + return cs.heaviest +} + +func (cs *ChainStore) persistBlockHeader(b *BlockHeader) error { + sb, err := b.ToStorageBlock() + if err != nil { + return err + } + + return cs.bs.Put(sb) +} + +func (cs *ChainStore) persistBlock(b *FullBlock) error { + if err := cs.persistBlockHeader(b.Header); err != nil { + return err + } + + for _, m := range b.Messages { + if err := cs.PutMessage(m); err != nil { + return err + } + } + return nil +} + +func (cs *ChainStore) PutMessage(m *SignedMessage) error { + sb, err := m.ToStorageBlock() + if err != nil { + return err + } + + return cs.bs.Put(sb) +} + +func (cs *ChainStore) AddBlock(b *BlockHeader) error { + if err := cs.persistBlockHeader(b); err != nil { + return err + } + + ts, _ := NewTipSet([]*BlockHeader{b}) + cs.maybeTakeHeavierTipSet(ts) + + return nil +} + +func (cs *ChainStore) GetGenesis() (*BlockHeader, error) { + data, err := cs.ds.Get(datastore.NewKey("0")) + if err != nil { + return nil, err + } + + c, err := cid.Cast(data) + if err != nil { + return nil, err + } + + genb, err := cs.bs.Get(c) + if err != nil { + return nil, err + } + + return DecodeBlock(genb.RawData()) +} + +func (cs *ChainStore) TipSetState(cids []cid.Cid) (cid.Cid, error) { + ts, err := cs.LoadTipSet(cids) + if err != nil { + log.Error("failed loading tipset: ", cids) + return cid.Undef, err + } + + if len(ts.Blocks()) == 1 { + return ts.Blocks()[0].StateRoot, nil + } + + panic("cant handle multiblock tipsets yet") + +} + +func (cs *ChainStore) GetMessage(c cid.Cid) (*SignedMessage, error) { + sb, err := cs.bs.Get(c) + if err != nil { + return nil, err + } + + return DecodeSignedMessage(sb.RawData()) +} + +func (cs *ChainStore) MessagesForBlock(b *BlockHeader) ([]*SignedMessage, error) { + cst := hamt.CSTFromBstore(cs.bs) + shar, err := sharray.Load(context.TODO(), b.Messages, 4, cst) + if err != nil { + return nil, errors.Wrap(err, "sharray load") + } + + var cids []cid.Cid + err = shar.ForEach(context.TODO(), func(i interface{}) error { + c, ok := i.(cid.Cid) + if !ok { + return fmt.Errorf("value in message sharray was not a cid") + } + + cids = append(cids, c) + return nil + }) + if err != nil { + return nil, err + } + + return cs.LoadMessagesFromCids(cids) +} + +func (cs *ChainStore) LoadMessagesFromCids(cids []cid.Cid) ([]*SignedMessage, error) { + msgs := make([]*SignedMessage, 0, len(cids)) + for _, c := range cids { + m, err := cs.GetMessage(c) + if err != nil { + return nil, err + } + + msgs = append(msgs, m) + } + + return msgs, nil +} diff --git a/chain/messagepool.go b/chain/messagepool.go new file mode 100644 index 00000000000..19d3154e6cb --- /dev/null +++ b/chain/messagepool.go @@ -0,0 +1,140 @@ +package chain + +import ( + "sync" + + "github.com/filecoin-project/go-lotus/chain/address" +) + +type MessagePool struct { + lk sync.Mutex + + pending map[address.Address]*msgSet + + cs *ChainStore +} + +type msgSet struct { + msgs map[uint64]*SignedMessage + startNonce uint64 +} + +func newMsgSet() *msgSet { + return &msgSet{ + msgs: make(map[uint64]*SignedMessage), + } +} + +func (ms *msgSet) add(m *SignedMessage) { + if len(ms.msgs) == 0 || m.Message.Nonce < ms.startNonce { + ms.startNonce = m.Message.Nonce + } + ms.msgs[m.Message.Nonce] = m +} + +func NewMessagePool(cs *ChainStore) *MessagePool { + mp := &MessagePool{ + pending: make(map[address.Address]*msgSet), + cs: cs, + } + cs.headChange = mp.HeadChange + + return mp +} + +func (mp *MessagePool) Add(m *SignedMessage) error { + mp.lk.Lock() + defer mp.lk.Unlock() + + data, err := m.Message.Serialize() + if err != nil { + return err + } + + if err := m.Signature.Verify(m.Message.From, data); err != nil { + return err + } + + msb, err := m.ToStorageBlock() + if err != nil { + return err + } + + if err := mp.cs.bs.Put(msb); err != nil { + return err + } + + mset, ok := mp.pending[m.Message.From] + if !ok { + mset = newMsgSet() + mp.pending[m.Message.From] = mset + } + + mset.add(m) + return nil +} + +func (mp *MessagePool) Remove(m *SignedMessage) { + mp.lk.Lock() + defer mp.lk.Unlock() + + mset, ok := mp.pending[m.Message.From] + if !ok { + return + } + + // NB: This deletes any message with the given nonce. This makes sense + // as two messages with the same sender cannot have the same nonce + delete(mset.msgs, m.Message.Nonce) + + if len(mset.msgs) == 0 { + delete(mp.pending, m.Message.From) + } +} + +func (mp *MessagePool) Pending() []*SignedMessage { + mp.lk.Lock() + defer mp.lk.Unlock() + var out []*SignedMessage + for _, mset := range mp.pending { + for i := mset.startNonce; true; i++ { + m, ok := mset.msgs[i] + if !ok { + break + } + out = append(out, m) + } + } + + return out +} + +func (mp *MessagePool) HeadChange(revert []*TipSet, apply []*TipSet) error { + for _, ts := range revert { + for _, b := range ts.Blocks() { + msgs, err := mp.cs.MessagesForBlock(b) + if err != nil { + return err + } + for _, msg := range msgs { + if err := mp.Add(msg); err != nil { + return err + } + } + } + } + + for _, ts := range apply { + for _, b := range ts.Blocks() { + msgs, err := mp.cs.MessagesForBlock(b) + if err != nil { + return err + } + for _, msg := range msgs { + mp.Remove(msg) + } + } + } + + return nil +} diff --git a/chain/mining.go b/chain/mining.go new file mode 100644 index 00000000000..06a9d10500b --- /dev/null +++ b/chain/mining.go @@ -0,0 +1,245 @@ +package chain + +import ( + "context" + "fmt" + "time" + + cid "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" + "github.com/pkg/errors" + sharray "github.com/whyrusleeping/sharray" + + "github.com/filecoin-project/go-lotus/chain/address" + bls "github.com/filecoin-project/go-lotus/lib/bls-signatures" +) + +type Miner struct { + cs *ChainStore + newBlockCB func(*FullBlock) + + maddr address.Address + mpool *MessagePool + + Delay time.Duration + + candidate *MiningBase +} + +func NewMiner(cs *ChainStore, maddr address.Address, mpool *MessagePool, newBlockCB func(*FullBlock)) *Miner { + return &Miner{ + cs: cs, + newBlockCB: newBlockCB, + maddr: maddr, + mpool: mpool, + Delay: time.Second * 2, + } +} + +type MiningBase struct { + ts *TipSet + tickets []Ticket +} + +func (m *Miner) Mine(ctx context.Context) { + log.Error("mining...") + defer log.Error("left mining...") + for { + base := m.GetBestMiningCandidate() + + b, err := m.mineOne(ctx, base) + if err != nil { + log.Error(err) + continue + } + + if b != nil { + m.submitNewBlock(b) + } + } +} + +func (m *Miner) GetBestMiningCandidate() *MiningBase { + best := m.cs.GetHeaviestTipSet() + if m.candidate == nil { + if best == nil { + panic("no best candidate!") + } + return &MiningBase{ + ts: best, + } + } + + if m.cs.Weight(best) > m.cs.Weight(m.candidate.ts) { + return &MiningBase{ + ts: best, + } + } + + return m.candidate +} + +func (m *Miner) submitNullTicket(base *MiningBase, ticket Ticket) { + panic("nyi") +} + +func (m *Miner) isWinnerNextRound(base *MiningBase) (bool, ElectionProof, error) { + return true, []byte("election prooooof"), nil +} + +func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (Ticket, error) { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(m.Delay): + } + + return []byte("this is a ticket"), nil +} + +func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*FullBlock, error) { + log.Info("mine one") + ticket, err := m.scratchTicket(ctx, base) + if err != nil { + return nil, errors.Wrap(err, "scratching ticket failed") + } + + win, proof, err := m.isWinnerNextRound(base) + if err != nil { + return nil, errors.Wrap(err, "failed to check if we win next round") + } + + if !win { + m.submitNullTicket(base, ticket) + return nil, nil + } + + b, err := m.createBlock(base, ticket, proof) + if err != nil { + return nil, errors.Wrap(err, "failed to create block") + } + fmt.Println("created new block:", b.Cid()) + + return b, nil +} + +func (m *Miner) submitNewBlock(b *FullBlock) { + if err := m.cs.AddBlock(b.Header); err != nil { + log.Error("failed to add new block to chainstore: ", err) + } + m.newBlockCB(b) +} + +func miningRewardForBlock(base *TipSet) BigInt { + return NewInt(10000) +} + +func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof) (*FullBlock, error) { + st, err := m.cs.TipSetState(base.ts.Cids()) + if err != nil { + return nil, errors.Wrap(err, "failed to load tipset state") + } + + height := base.ts.Height() + uint64(len(base.tickets)) + 1 + + vm, err := NewVM(st, height, m.maddr, m.cs) + + // apply miner reward + if err := vm.TransferFunds(NetworkAddress, m.maddr, miningRewardForBlock(base.ts)); err != nil { + return nil, err + } + + next := &BlockHeader{ + Miner: m.maddr, + Parents: base.ts.Cids(), + Tickets: append(base.tickets, ticket), + Height: height, + } + + pending := m.mpool.Pending() + fmt.Printf("adding %d messages to block...", len(pending)) + var msgCids []cid.Cid + var blsSigs []Signature + var receipts []interface{} + for _, msg := range pending { + if msg.Signature.TypeCode() == 2 { + blsSigs = append(blsSigs, msg.Signature) + + blk, err := msg.Message.ToStorageBlock() + if err != nil { + return nil, err + } + if err := m.cs.bs.Put(blk); err != nil { + return nil, err + } + + msgCids = append(msgCids, blk.Cid()) + } else { + msgCids = append(msgCids, msg.Cid()) + } + rec, err := vm.ApplyMessage(&msg.Message) + if err != nil { + return nil, errors.Wrap(err, "apply message failure") + } + + receipts = append(receipts, rec) + } + + cst := hamt.CSTFromBstore(m.cs.bs) + msgroot, err := sharray.Build(context.TODO(), 4, toIfArr(msgCids), cst) + if err != nil { + return nil, err + } + next.Messages = msgroot + + rectroot, err := sharray.Build(context.TODO(), 4, receipts, cst) + if err != nil { + return nil, err + } + next.MessageReceipts = rectroot + + stateRoot, err := vm.Flush(context.TODO()) + if err != nil { + return nil, errors.Wrap(err, "flushing state tree failed") + } + + aggSig, err := aggregateSignatures(blsSigs) + if err != nil { + return nil, err + } + + next.BLSAggregate = aggSig + next.StateRoot = stateRoot + pweight := m.cs.Weight(base.ts) + next.ParentWeight = NewInt(pweight) + + fullBlock := &FullBlock{ + Header: next, + Messages: pending, + } + + return fullBlock, nil +} + +func aggregateSignatures(sigs []Signature) (Signature, error) { + var blsSigs []bls.Signature + for _, s := range sigs { + var bsig bls.Signature + copy(bsig[:], s.Data) + blsSigs = append(blsSigs, bsig) + } + + aggSig := bls.Aggregate(blsSigs) + return Signature{ + Type: KTBLS, + Data: aggSig[:], + }, nil +} + +func toIfArr(cids []cid.Cid) []interface{} { + out := make([]interface{}, 0, len(cids)) + for _, c := range cids { + out = append(out, c) + } + return out +} diff --git a/chain/statetree.go b/chain/statetree.go new file mode 100644 index 00000000000..a16b88be1ac --- /dev/null +++ b/chain/statetree.go @@ -0,0 +1,199 @@ +package chain + +import ( + "context" + "fmt" + + "github.com/filecoin-project/go-lotus/chain/address" + + "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" + cbor "github.com/ipfs/go-ipld-cbor" +) + +var ErrActorNotFound = fmt.Errorf("actor not found") + +type StateTree struct { + root *hamt.Node + store *hamt.CborIpldStore + + actorcache map[address.Address]*Actor + snapshot cid.Cid +} + +func NewStateTree(cst *hamt.CborIpldStore) (*StateTree, error) { + return &StateTree{ + root: hamt.NewNode(cst), + store: cst, + actorcache: make(map[address.Address]*Actor), + }, nil +} + +func LoadStateTree(cst *hamt.CborIpldStore, c cid.Cid) (*StateTree, error) { + nd, err := hamt.LoadNode(context.Background(), cst, c) + if err != nil { + log.Errorf("loading hamt node failed: %s", err) + return nil, err + } + + return &StateTree{ + root: nd, + store: cst, + actorcache: make(map[address.Address]*Actor), + }, nil +} + +func (st *StateTree) SetActor(addr address.Address, act *Actor) error { + if addr.Protocol() != address.ID { + iaddr, err := st.lookupID(addr) + if err != nil { + return err + } + addr = iaddr + } + + cact, ok := st.actorcache[addr] + if ok { + if act == cact { + return nil + } + } + + return st.root.Set(context.TODO(), string(addr.Bytes()), act) +} + +func (st *StateTree) lookupID(addr address.Address) (address.Address, error) { + act, err := st.GetActor(InitActorAddress) + if err != nil { + return address.Undef, err + } + + var ias InitActorState + if err := st.store.Get(context.TODO(), act.Head, &ias); err != nil { + return address.Undef, err + } + + return ias.Lookup(st.store, addr) +} + +func (st *StateTree) GetActor(addr address.Address) (*Actor, error) { + if addr.Protocol() != address.ID { + iaddr, err := st.lookupID(addr) + if err != nil { + if err == hamt.ErrNotFound { + return nil, ErrActorNotFound + } + return nil, err + } + addr = iaddr + } + + cact, ok := st.actorcache[addr] + if ok { + return cact, nil + } + + thing, err := st.root.Find(context.TODO(), string(addr.Bytes())) + if err != nil { + if err == hamt.ErrNotFound { + return nil, ErrActorNotFound + } + return nil, err + } + + var act Actor + badout, err := cbor.DumpObject(thing) + if err != nil { + return nil, err + } + + if err := cbor.DecodeInto(badout, &act); err != nil { + return nil, err + } + + st.actorcache[addr] = &act + + return &act, nil +} + +func (st *StateTree) Flush() (cid.Cid, error) { + for addr, act := range st.actorcache { + if err := st.root.Set(context.TODO(), string(addr.Bytes()), act); err != nil { + return cid.Undef, err + } + } + st.actorcache = make(map[address.Address]*Actor) + + if err := st.root.Flush(context.TODO()); err != nil { + return cid.Undef, err + } + + return st.store.Put(context.TODO(), st.root) +} + +func (st *StateTree) Snapshot() error { + ss, err := st.Flush() + if err != nil { + return err + } + + st.snapshot = ss + return nil +} + +func (st *StateTree) RegisterNewAddress(addr address.Address, act *Actor) (address.Address, error) { + var out address.Address + err := st.MutateActor(InitActorAddress, func(initact *Actor) error { + var ias InitActorState + if err := st.store.Get(context.TODO(), initact.Head, &ias); err != nil { + return err + } + + fvm := &VMContext{cst: st.store} + oaddr, err := ias.AddActor(fvm, addr) + if err != nil { + return err + } + out = oaddr + + ncid, err := st.store.Put(context.TODO(), &ias) + if err != nil { + return err + } + + initact.Head = ncid + return nil + }) + if err != nil { + return address.Undef, err + } + + if err := st.SetActor(out, act); err != nil { + return address.Undef, err + } + + return out, nil +} + +func (st *StateTree) Revert() error { + nd, err := hamt.LoadNode(context.Background(), st.store, st.snapshot) + if err != nil { + return err + } + + st.root = nd + return nil +} + +func (st *StateTree) MutateActor(addr address.Address, f func(*Actor) error) error { + act, err := st.GetActor(addr) + if err != nil { + return err + } + + if err := f(act); err != nil { + return err + } + + return st.SetActor(addr, act) +} diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go new file mode 100644 index 00000000000..d56dd8e402f --- /dev/null +++ b/chain/sub/incoming.go @@ -0,0 +1,63 @@ +package sub + +import ( + "context" + "fmt" + + logging "github.com/ipfs/go-log" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/filecoin-project/go-lotus/chain" +) + +var log = logging.Logger("sub") + +func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer) { + for { + msg, err := bsub.Next(ctx) + if err != nil { + fmt.Println("error from block subscription: ", err) + continue + } + + blk, err := chain.DecodeBlockMsg(msg.GetData()) + if err != nil { + log.Error("got invalid block over pubsub: ", err) + continue + } + + go func() { + msgs, err := s.Bsync.FetchMessagesByCids(blk.Messages) + if err != nil { + log.Errorf("failed to fetch all messages for block received over pubusb: %s", err) + return + } + fmt.Println("inform new block over pubsub") + s.InformNewBlock(msg.GetFrom(), &chain.FullBlock{ + Header: blk.Header, + Messages: msgs, + }) + }() + } +} + +func HandleIncomingMessages(ctx context.Context, mpool *chain.MessagePool, msub *pubsub.Subscription) { + for { + msg, err := msub.Next(ctx) + if err != nil { + fmt.Println("error from message subscription: ", err) + continue + } + + m, err := chain.DecodeSignedMessage(msg.GetData()) + if err != nil { + log.Errorf("got incorrectly formatted Message: %s", err) + continue + } + + if err := mpool.Add(m); err != nil { + log.Errorf("failed to add message from network to message pool: %s", err) + continue + } + } +} diff --git a/chain/sync.go b/chain/sync.go new file mode 100644 index 00000000000..ca0aafa60c1 --- /dev/null +++ b/chain/sync.go @@ -0,0 +1,697 @@ +package chain + +import ( + "context" + "fmt" + "sync" + + "github.com/filecoin-project/go-lotus/chain/address" + + "github.com/ipfs/go-cid" + dstore "github.com/ipfs/go-datastore" + "github.com/ipfs/go-hamt-ipld" + bstore "github.com/ipfs/go-ipfs-blockstore" + peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/pkg/errors" + "github.com/whyrusleeping/sharray" +) + +type Syncer struct { + // The heaviest known tipset in the network. + head *TipSet + + // The interface for accessing and putting tipsets into local storage + store *ChainStore + + // The known Genesis tipset + Genesis *TipSet + + // the current mode the syncer is in + syncMode SyncMode + + syncLock sync.Mutex + + // TipSets known to be invalid + bad BadTipSetCache + + // handle to the block sync service + Bsync *BlockSync + + // peer heads + // Note: clear cache on disconnects + peerHeads map[peer.ID]*TipSet + peerHeadsLk sync.Mutex +} + +func NewSyncer(cs *ChainStore, bsync *BlockSync) (*Syncer, error) { + gen, err := cs.GetGenesis() + if err != nil { + return nil, err + } + + gent, err := NewTipSet([]*BlockHeader{gen}) + if err != nil { + return nil, err + } + + return &Syncer{ + syncMode: Bootstrap, + Genesis: gent, + Bsync: bsync, + peerHeads: make(map[peer.ID]*TipSet), + head: cs.GetHeaviestTipSet(), + store: cs, + }, nil +} + +type SyncMode int + +const ( + Unknown = SyncMode(iota) + Bootstrap + CaughtUp +) + +type BadTipSetCache struct { + badBlocks map[cid.Cid]struct{} +} + +type BlockSet struct { + tset map[uint64]*TipSet + head *TipSet +} + +func (bs *BlockSet) Insert(ts *TipSet) { + if bs.tset == nil { + bs.tset = make(map[uint64]*TipSet) + } + + if bs.head == nil || ts.Height() > bs.head.Height() { + bs.head = ts + } + bs.tset[ts.Height()] = ts +} + +func (bs *BlockSet) GetByHeight(h uint64) *TipSet { + return bs.tset[h] +} + +func (bs *BlockSet) PersistTo(cs *ChainStore) error { + for _, ts := range bs.tset { + for _, b := range ts.Blocks() { + if err := cs.persistBlockHeader(b); err != nil { + return err + } + } + } + return nil +} + +func (bs *BlockSet) Head() *TipSet { + return bs.head +} + +const BootstrapPeerThreshold = 1 + +// InformNewHead informs the syncer about a new potential tipset +// This should be called when connecting to new peers, and additionally +// when receiving new blocks from the network +func (syncer *Syncer) InformNewHead(from peer.ID, fts *FullTipSet) { + if fts == nil { + panic("bad") + } + syncer.peerHeadsLk.Lock() + syncer.peerHeads[from] = fts.TipSet() + syncer.peerHeadsLk.Unlock() + syncer.Bsync.AddPeer(from) + + go func() { + syncer.syncLock.Lock() + defer syncer.syncLock.Unlock() + + switch syncer.syncMode { + case Bootstrap: + syncer.SyncBootstrap() + case CaughtUp: + if err := syncer.SyncCaughtUp(fts); err != nil { + log.Errorf("sync error: %s", err) + } + case Unknown: + panic("invalid syncer state") + } + }() +} + +func (syncer *Syncer) GetPeers() []peer.ID { + syncer.peerHeadsLk.Lock() + defer syncer.peerHeadsLk.Unlock() + var out []peer.ID + for p, _ := range syncer.peerHeads { + out = append(out, p) + } + return out +} + +func (syncer *Syncer) InformNewBlock(from peer.ID, blk *FullBlock) { + // TODO: search for other blocks that could form a tipset with this block + // and then send that tipset to InformNewHead + + fts := &FullTipSet{Blocks: []*FullBlock{blk}} + syncer.InformNewHead(from, fts) +} + +// SyncBootstrap is used to synchronise your chain when first joining +// the network, or when rejoining after significant downtime. +func (syncer *Syncer) SyncBootstrap() { + fmt.Println("Sync bootstrap!") + defer fmt.Println("bye bye sync bootstrap") + ctx := context.Background() + + if syncer.syncMode == CaughtUp { + log.Errorf("Called SyncBootstrap while in caught up mode") + return + } + + selectedHead, err := syncer.selectHead(syncer.peerHeads) + if err != nil { + log.Error("failed to select head: ", err) + return + } + + blockSet := []*TipSet{selectedHead} + cur := selectedHead.Cids() + for /* would be cool to have a terminating condition maybe */ { + // NB: GetBlocks validates that the blocks are in-fact the ones we + // requested, and that they are correctly linked to eachother. It does + // not validate any state transitions + fmt.Println("Get blocks: ", cur) + blks, err := syncer.Bsync.GetBlocks(context.TODO(), cur, 10) + if err != nil { + log.Error("failed to get blocks: ", err) + return + } + + for _, b := range blks { + blockSet = append(blockSet, b) + } + if blks[len(blks)-1].Height() == 0 { + break + } + + cur = blks[len(blks)-1].Parents() + } + + // hacks. in the case that we request X blocks starting at height X+1, we + // won't get the Genesis block in the returned blockset. This hacks around it + if blockSet[len(blockSet)-1].Height() != 0 { + blockSet = append(blockSet, syncer.Genesis) + } + + blockSet = reverse(blockSet) + + genesis := blockSet[0] + if !genesis.Equals(syncer.Genesis) { + // TODO: handle this... + log.Errorf("We synced to the wrong chain! %s != %s", genesis, syncer.Genesis) + return + } + + for _, ts := range blockSet { + for _, b := range ts.Blocks() { + if err := syncer.store.persistBlockHeader(b); err != nil { + log.Errorf("failed to persist synced blocks to the chainstore: %s", err) + return + } + } + } + + // Fetch all the messages for all the blocks in this chain + + windowSize := uint64(10) + for i := uint64(0); i <= selectedHead.Height(); i += windowSize { + bs := bstore.NewBlockstore(dstore.NewMapDatastore()) + cst := hamt.CSTFromBstore(bs) + + nextHeight := i + windowSize - 1 + if nextHeight > selectedHead.Height() { + nextHeight = selectedHead.Height() + } + + next := blockSet[nextHeight] + bstips, err := syncer.Bsync.GetChainMessages(ctx, next, (nextHeight+1)-i) + if err != nil { + log.Errorf("failed to fetch messages: %s", err) + return + } + + for bsi := 0; bsi < len(bstips); bsi++ { + cur := blockSet[i+uint64(bsi)] + bstip := bstips[len(bstips)-(bsi+1)] + fmt.Println("that loop: ", bsi, len(bstips)) + fts, err := zipTipSetAndMessages(cst, cur, bstip.Messages, bstip.MsgIncludes) + if err != nil { + log.Error("zipping failed: ", err, bsi, i) + log.Error("height: ", selectedHead.Height()) + log.Error("bstips: ", bstips) + log.Error("next height: ", nextHeight) + return + } + + if err := syncer.ValidateTipSet(fts); err != nil { + log.Errorf("failed to validate tipset: %s", err) + return + } + } + + for _, bst := range bstips { + for _, m := range bst.Messages { + if _, err := cst.Put(context.TODO(), m); err != nil { + log.Error("failed to persist messages: ", err) + return + } + } + } + + if err := copyBlockstore(bs, syncer.store.bs); err != nil { + log.Errorf("failed to persist temp blocks: %s", err) + return + } + } + + head := blockSet[len(blockSet)-1] + log.Errorf("Finished syncing! new head: %s", head.Cids()) + syncer.store.maybeTakeHeavierTipSet(selectedHead) + syncer.head = head + syncer.syncMode = CaughtUp +} + +func reverse(tips []*TipSet) []*TipSet { + out := make([]*TipSet, len(tips)) + for i := 0; i < len(tips); i++ { + out[i] = tips[len(tips)-(i+1)] + } + return out +} + +func copyBlockstore(from, to bstore.Blockstore) error { + cids, err := from.AllKeysChan(context.TODO()) + if err != nil { + return err + } + + for c := range cids { + b, err := from.Get(c) + if err != nil { + return err + } + + if err := to.Put(b); err != nil { + return err + } + } + + return nil +} + +func zipTipSetAndMessages(cst *hamt.CborIpldStore, ts *TipSet, messages []*SignedMessage, msgincl [][]int) (*FullTipSet, error) { + if len(ts.Blocks()) != len(msgincl) { + return nil, fmt.Errorf("msgincl length didnt match tipset size") + } + fmt.Println("zipping messages: ", msgincl) + fmt.Println("into block: ", ts.Blocks()[0].Height) + + fts := &FullTipSet{} + for bi, b := range ts.Blocks() { + var msgs []*SignedMessage + var msgCids []interface{} + for _, m := range msgincl[bi] { + msgs = append(msgs, messages[m]) + msgCids = append(msgCids, messages[m].Cid()) + } + + mroot, err := sharray.Build(context.TODO(), 4, msgCids, cst) + if err != nil { + return nil, err + } + + fmt.Println("messages: ", msgCids) + fmt.Println("message root: ", b.Messages, mroot) + if b.Messages != mroot { + return nil, fmt.Errorf("messages didnt match message root in header") + } + + fb := &FullBlock{ + Header: b, + Messages: msgs, + } + + fts.Blocks = append(fts.Blocks, fb) + } + + return fts, nil +} + +func (syncer *Syncer) selectHead(heads map[peer.ID]*TipSet) (*TipSet, error) { + var headsArr []*TipSet + for _, ts := range heads { + headsArr = append(headsArr, ts) + } + + sel := headsArr[0] + for i := 1; i < len(headsArr); i++ { + cur := headsArr[i] + + yes, err := syncer.store.IsAncestorOf(cur, sel) + if err != nil { + return nil, err + } + if yes { + continue + } + + yes, err = syncer.store.IsAncestorOf(sel, cur) + if err != nil { + return nil, err + } + if yes { + sel = cur + continue + } + + nca, err := syncer.store.NearestCommonAncestor(cur, sel) + if err != nil { + return nil, err + } + + if sel.Height()-nca.Height() > ForkLengthThreshold { + // TODO: handle this better than refusing to sync + return nil, fmt.Errorf("Conflict exists in heads set") + } + + if syncer.store.Weight(cur) > syncer.store.Weight(sel) { + sel = cur + } + } + return sel, nil +} + +func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, cids []cid.Cid) (*FullTipSet, error) { + if fts, err := syncer.tryLoadFullTipSet(cids); err == nil { + return fts, nil + } + + return syncer.Bsync.GetFullTipSet(ctx, p, cids) +} + +func (syncer *Syncer) tryLoadFullTipSet(cids []cid.Cid) (*FullTipSet, error) { + ts, err := syncer.store.LoadTipSet(cids) + if err != nil { + return nil, err + } + + fts := &FullTipSet{} + for _, b := range ts.Blocks() { + messages, err := syncer.store.MessagesForBlock(b) + if err != nil { + return nil, err + } + + fb := &FullBlock{ + Header: b, + Messages: messages, + } + fts.Blocks = append(fts.Blocks, fb) + } + + return fts, nil +} + +// FullTipSet is an expanded version of the TipSet that contains all the blocks and messages +type FullTipSet struct { + Blocks []*FullBlock + tipset *TipSet + cids []cid.Cid +} + +func NewFullTipSet(blks []*FullBlock) *FullTipSet { + return &FullTipSet{ + Blocks: blks, + } +} + +func (fts *FullTipSet) Cids() []cid.Cid { + if fts.cids != nil { + return fts.cids + } + + var cids []cid.Cid + for _, b := range fts.Blocks { + cids = append(cids, b.Cid()) + } + fts.cids = cids + + return cids +} + +func (fts *FullTipSet) TipSet() *TipSet { + if fts.tipset != nil { + return fts.tipset + } + + var headers []*BlockHeader + for _, b := range fts.Blocks { + headers = append(headers, b.Header) + } + + ts, err := NewTipSet(headers) + if err != nil { + panic(err) + } + + return ts +} + +// SyncCaughtUp is used to stay in sync once caught up to +// the rest of the network. +func (syncer *Syncer) SyncCaughtUp(maybeHead *FullTipSet) error { + ts := maybeHead.TipSet() + if syncer.Genesis.Equals(ts) { + return nil + } + + chain, err := syncer.collectChainCaughtUp(maybeHead) + if err != nil { + return err + } + + for i := len(chain) - 1; i >= 0; i-- { + ts := chain[i] + if err := syncer.ValidateTipSet(ts); err != nil { + return errors.Wrap(err, "validate tipset failed") + } + + syncer.store.PutTipSet(ts) + } + + if err := syncer.store.PutTipSet(maybeHead); err != nil { + return errors.Wrap(err, "failed to put synced tipset to chainstore") + } + + if syncer.store.Weight(chain[0].TipSet()) > syncer.store.Weight(syncer.head) { + fmt.Println("Accepted new head: ", chain[0].Cids()) + syncer.head = chain[0].TipSet() + } + return nil +} + +func (syncer *Syncer) ValidateTipSet(fts *FullTipSet) error { + ts := fts.TipSet() + if ts.Equals(syncer.Genesis) { + return nil + } + + for _, b := range fts.Blocks { + if err := syncer.ValidateBlock(b); err != nil { + return err + } + } + return nil +} + +func (syncer *Syncer) ValidateBlock(b *FullBlock) error { + h := b.Header + stateroot, err := syncer.store.TipSetState(h.Parents) + if err != nil { + log.Error("get tipsetstate failed: ", h.Height, h.Parents, err) + return err + } + baseTs, err := syncer.store.LoadTipSet(b.Header.Parents) + if err != nil { + return err + } + + vm, err := NewVM(stateroot, b.Header.Height, b.Header.Miner, syncer.store) + if err != nil { + return err + } + + if err := vm.TransferFunds(NetworkAddress, b.Header.Miner, miningRewardForBlock(baseTs)); err != nil { + return err + } + + var receipts []interface{} + for _, m := range b.Messages { + receipt, err := vm.ApplyMessage(&m.Message) + if err != nil { + return err + } + + receipts = append(receipts, receipt) + } + + cst := hamt.CSTFromBstore(syncer.store.bs) + recptRoot, err := sharray.Build(context.TODO(), 4, receipts, cst) + if err != nil { + return err + } + if recptRoot != b.Header.MessageReceipts { + return fmt.Errorf("receipts mismatched") + } + + final, err := vm.Flush(context.TODO()) + if err != nil { + return err + } + + if b.Header.StateRoot != final { + return fmt.Errorf("final state root does not match block") + } + + return nil + +} + +func DeductFunds(act *Actor, amt BigInt) error { + if BigCmp(act.Balance, amt) < 0 { + return fmt.Errorf("not enough funds") + } + + act.Balance = BigSub(act.Balance, amt) + return nil +} + +func DepositFunds(act *Actor, amt BigInt) { + act.Balance = BigAdd(act.Balance, amt) +} + +func TryCreateAccountActor(st *StateTree, addr address.Address) (*Actor, error) { + act, err := makeActor(st, addr) + if err != nil { + return nil, err + } + + _, err = st.RegisterNewAddress(addr, act) + if err != nil { + return nil, err + } + + return act, nil +} + +func makeActor(st *StateTree, addr address.Address) (*Actor, error) { + switch addr.Protocol() { + case address.BLS: + return NewBLSAccountActor(st, addr) + case address.SECP256K1: + return NewSecp256k1AccountActor(st, addr) + case address.ID: + return nil, fmt.Errorf("no actor with given ID") + case address.Actor: + return nil, fmt.Errorf("no such actor") + default: + return nil, fmt.Errorf("address has unsupported protocol: %d", addr.Protocol()) + } +} + +func NewBLSAccountActor(st *StateTree, addr address.Address) (*Actor, error) { + var acstate AccountActorState + acstate.Address = addr + + c, err := st.store.Put(context.TODO(), acstate) + if err != nil { + return nil, err + } + + nact := &Actor{ + Code: AccountActorCodeCid, + Balance: NewInt(0), + Head: c, + } + + return nact, nil +} + +func NewSecp256k1AccountActor(st *StateTree, addr address.Address) (*Actor, error) { + nact := &Actor{ + Code: AccountActorCodeCid, + Balance: NewInt(0), + Head: EmptyObjectCid, + } + + return nact, nil +} + +func (syncer *Syncer) Punctual(ts *TipSet) bool { + return true +} + +func (syncer *Syncer) collectChainCaughtUp(fts *FullTipSet) ([]*FullTipSet, error) { + // fetch tipset and messages via bitswap + + chain := []*FullTipSet{fts} + cur := fts.TipSet() + + for { + ts, err := syncer.store.LoadTipSet(cur.Parents()) + if err != nil { + panic("should do something better, like fetch? or error?") + } + + return chain, nil // return the chain because we have this last block in our cache already. + + if ts.Equals(syncer.Genesis) { + break + } + + /* + if !syncer.Punctual(ts) { + syncer.bad.InvalidateChain(chain) + syncer.bad.InvalidateTipSet(ts) + return nil, errors.New("tipset forks too far back from head") + } + */ + + chain = append(chain, fts) + log.Error("received unknown chain in caught up mode...") + panic("for now, we panic...") + + has, err := syncer.store.Contains(ts) + if err != nil { + return nil, err + } + if has { + // Store has record of this tipset. + return chain, nil + } + + /* + parent, err := syncer.FetchTipSet(context.TODO(), ts.Parents()) + if err != nil { + return nil, err + } + ts = parent + */ + } + + return chain, nil +} diff --git a/chain/types.go b/chain/types.go new file mode 100644 index 00000000000..f99154bbac7 --- /dev/null +++ b/chain/types.go @@ -0,0 +1,594 @@ +package chain + +import ( + "bytes" + "encoding/binary" + "fmt" + "math/big" + + "github.com/filecoin-project/go-lotus/chain/address" + + block "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + ipld "github.com/ipfs/go-ipld-format" + "github.com/multiformats/go-multihash" + "github.com/polydawn/refmt/obj/atlas" +) + +func init() { + ipld.Register(0x1f, IpldDecode) + + cbor.RegisterCborType(MessageReceipt{}) + cbor.RegisterCborType(Actor{}) + cbor.RegisterCborType(BlockMsg{}) + + ///* + cbor.RegisterCborType(atlas.BuildEntry(BigInt{}).UseTag(2).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(i BigInt) ([]byte, error) { + if i.Int == nil { + return []byte{}, nil + } + + return i.Bytes(), nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x []byte) (BigInt, error) { + return BigFromBytes(x), nil + })). + Complete()) + //*/ + cbor.RegisterCborType(atlas.BuildEntry(SignedMessage{}).UseTag(45).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(sm SignedMessage) ([]interface{}, error) { + return []interface{}{ + sm.Message, + sm.Signature, + }, nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x []interface{}) (SignedMessage, error) { + sigb, ok := x[1].([]byte) + if !ok { + return SignedMessage{}, fmt.Errorf("signature in signed message was not bytes") + } + + sig, err := SignatureFromBytes(sigb) + if err != nil { + return SignedMessage{}, err + } + + return SignedMessage{ + Message: x[0].(Message), + Signature: sig, + }, nil + })). + Complete()) + cbor.RegisterCborType(atlas.BuildEntry(Signature{}).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(s Signature) ([]byte, error) { + buf := make([]byte, 4) + n := binary.PutUvarint(buf, uint64(s.TypeCode())) + return append(buf[:n], s.Data...), nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x []byte) (Signature, error) { + return SignatureFromBytes(x) + })). + Complete()) + cbor.RegisterCborType(atlas.BuildEntry(Message{}).UseTag(44).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(m Message) ([]interface{}, error) { + return []interface{}{ + m.To.Bytes(), + m.From.Bytes(), + m.Nonce, + m.Value, + m.GasPrice, + m.GasLimit, + m.Method, + m.Params, + }, nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(arr []interface{}) (Message, error) { + to, err := address.NewFromBytes(arr[0].([]byte)) + if err != nil { + return Message{}, err + } + + from, err := address.NewFromBytes(arr[1].([]byte)) + if err != nil { + return Message{}, err + } + + nonce, ok := arr[2].(uint64) + if !ok { + return Message{}, fmt.Errorf("expected uint64 nonce at index 2") + } + + value := arr[3].(BigInt) + gasPrice := arr[4].(BigInt) + gasLimit := arr[5].(BigInt) + method, _ := arr[6].(uint64) + params, _ := arr[7].([]byte) + + if gasPrice.Nil() { + gasPrice = NewInt(0) + } + + if gasLimit.Nil() { + gasLimit = NewInt(0) + } + + return Message{ + To: to, + From: from, + Nonce: nonce, + Value: value, + GasPrice: gasPrice, + GasLimit: gasLimit, + Method: method, + Params: params, + }, nil + })). + Complete()) + cbor.RegisterCborType(atlas.BuildEntry(BlockHeader{}).UseTag(43).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(blk BlockHeader) ([]interface{}, error) { + if blk.Tickets == nil { + blk.Tickets = []Ticket{} + } + if blk.Parents == nil { + blk.Parents = []cid.Cid{} + } + return []interface{}{ + blk.Miner.Bytes(), + blk.Tickets, + blk.ElectionProof, + blk.Parents, + blk.ParentWeight, + blk.Height, + blk.StateRoot, + blk.Messages, + blk.MessageReceipts, + }, nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(arr []interface{}) (BlockHeader, error) { + miner, err := address.NewFromBytes(arr[0].([]byte)) + if err != nil { + return BlockHeader{}, err + } + + tickets := []Ticket{} + ticketarr, _ := arr[1].([]interface{}) + for _, t := range ticketarr { + tickets = append(tickets, Ticket(t.([]byte))) + } + electionProof, _ := arr[2].([]byte) + + parents := []cid.Cid{} + parentsArr, _ := arr[3].([]interface{}) + for _, p := range parentsArr { + parents = append(parents, p.(cid.Cid)) + } + parentWeight := arr[4].(BigInt) + height := arr[5].(uint64) + stateRoot := arr[6].(cid.Cid) + + msgscid := arr[7].(cid.Cid) + recscid := arr[8].(cid.Cid) + + return BlockHeader{ + Miner: miner, + Tickets: tickets, + ElectionProof: electionProof, + Parents: parents, + ParentWeight: parentWeight, + Height: height, + StateRoot: stateRoot, + Messages: msgscid, + MessageReceipts: recscid, + }, nil + })). + Complete()) +} + +type BigInt struct { + *big.Int +} + +func NewInt(i uint64) BigInt { + return BigInt{big.NewInt(0).SetUint64(i)} +} + +func BigFromBytes(b []byte) BigInt { + i := big.NewInt(0).SetBytes(b) + return BigInt{i} +} + +func BigMul(a, b BigInt) BigInt { + return BigInt{big.NewInt(0).Mul(a.Int, b.Int)} +} + +func BigAdd(a, b BigInt) BigInt { + return BigInt{big.NewInt(0).Add(a.Int, b.Int)} +} + +func BigSub(a, b BigInt) BigInt { + return BigInt{big.NewInt(0).Sub(a.Int, b.Int)} +} + +func BigCmp(a, b BigInt) int { + return a.Int.Cmp(b.Int) +} + +func (bi *BigInt) Nil() bool { + return bi.Int == nil +} + +type Actor struct { + Code cid.Cid + Head cid.Cid + Nonce uint64 + Balance BigInt +} + +type BlockHeader struct { + Miner address.Address + + Tickets []Ticket + + ElectionProof []byte + + Parents []cid.Cid + + ParentWeight BigInt + + Height uint64 + + StateRoot cid.Cid + + Messages cid.Cid + + BLSAggregate Signature + + MessageReceipts cid.Cid +} + +func (b *BlockHeader) ToStorageBlock() (block.Block, error) { + data, err := b.Serialize() + if err != nil { + return nil, err + } + + pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31) + c, err := pref.Sum(data) + if err != nil { + return nil, err + } + + return block.NewBlockWithCid(data, c) +} + +func (b *BlockHeader) Cid() cid.Cid { + sb, err := b.ToStorageBlock() + if err != nil { + panic(err) + } + + return sb.Cid() +} + +func DecodeBlock(b []byte) (*BlockHeader, error) { + var blk BlockHeader + if err := cbor.DecodeInto(b, &blk); err != nil { + return nil, err + } + + return &blk, nil +} + +func (blk *BlockHeader) Serialize() ([]byte, error) { + return cbor.DumpObject(blk) +} + +type Message struct { + To address.Address + From address.Address + + Nonce uint64 + + Value BigInt + + GasPrice BigInt + GasLimit BigInt + + Method uint64 + Params []byte +} + +func DecodeMessage(b []byte) (*Message, error) { + var msg Message + if err := cbor.DecodeInto(b, &msg); err != nil { + return nil, err + } + + return &msg, nil +} + +func (m *Message) Serialize() ([]byte, error) { + return cbor.DumpObject(m) +} + +func (m *Message) ToStorageBlock() (block.Block, error) { + data, err := m.Serialize() + if err != nil { + return nil, err + } + + pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31) + c, err := pref.Sum(data) + if err != nil { + return nil, err + } + + return block.NewBlockWithCid(data, c) +} + +func (m *SignedMessage) ToStorageBlock() (block.Block, error) { + data, err := m.Serialize() + if err != nil { + return nil, err + } + + pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31) + c, err := pref.Sum(data) + if err != nil { + return nil, err + } + + return block.NewBlockWithCid(data, c) +} + +func (m *SignedMessage) Cid() cid.Cid { + sb, err := m.ToStorageBlock() + if err != nil { + panic(err) + } + + return sb.Cid() +} + +type MessageReceipt struct { + ExitCode uint8 + + Return []byte + + GasUsed BigInt +} + +func (mr *MessageReceipt) Equals(o *MessageReceipt) bool { + return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && BigCmp(mr.GasUsed, o.GasUsed) == 0 +} + +type SignedMessage struct { + Message Message + Signature Signature +} + +func DecodeSignedMessage(data []byte) (*SignedMessage, error) { + var msg SignedMessage + if err := cbor.DecodeInto(data, &msg); err != nil { + return nil, err + } + + return &msg, nil +} + +func (sm *SignedMessage) Serialize() ([]byte, error) { + data, err := cbor.DumpObject(sm) + if err != nil { + return nil, err + } + return data, nil +} + +type TipSet struct { + cids []cid.Cid + blks []*BlockHeader + height uint64 +} + +func NewTipSet(blks []*BlockHeader) (*TipSet, error) { + var ts TipSet + ts.cids = []cid.Cid{blks[0].Cid()} + ts.blks = blks + for _, b := range blks[1:] { + if b.Height != blks[0].Height { + return nil, fmt.Errorf("cannot create tipset with mismatching heights") + } + ts.cids = append(ts.cids, b.Cid()) + } + ts.height = blks[0].Height + + return &ts, nil +} + +func (ts *TipSet) Cids() []cid.Cid { + return ts.cids +} + +func (ts *TipSet) Height() uint64 { + return ts.height +} + +func (ts *TipSet) Parents() []cid.Cid { + return ts.blks[0].Parents +} + +func (ts *TipSet) Blocks() []*BlockHeader { + return ts.blks +} + +func (ts *TipSet) Equals(ots *TipSet) bool { + if len(ts.blks) != len(ots.blks) { + return false + } + + for i, b := range ts.blks { + if b.Cid() != ots.blks[i].Cid() { + return false + } + } + + return true +} + +type Ticket []byte +type ElectionProof []byte + +func IpldDecode(block block.Block) (ipld.Node, error) { + var i interface{} + if err := cbor.DecodeInto(block.RawData(), &i); err != nil { + panic(err) + } + + fmt.Println("IPLD DECODE!") + return &filecoinIpldNode{i}, nil +} + +type filecoinIpldNode struct { + val interface{} +} + +func (f *filecoinIpldNode) Cid() cid.Cid { + switch t := f.val.(type) { + case BlockHeader: + return t.Cid() + case SignedMessage: + return t.Cid() + default: + panic("whats going on") + } +} + +func (f *filecoinIpldNode) Copy() ipld.Node { + panic("no") +} + +func (f *filecoinIpldNode) Links() []*ipld.Link { + switch t := f.val.(type) { + case BlockHeader: + fmt.Println("block links!", t.StateRoot) + return []*ipld.Link{ + { + Cid: t.StateRoot, + }, + { + Cid: t.Messages, + }, + { + Cid: t.MessageReceipts, + }, + } + case Message: + return nil + default: + panic("whats going on") + } + +} + +func (f *filecoinIpldNode) Resolve(path []string) (interface{}, []string, error) { + /* + switch t := f.val.(type) { + case Block: + switch path[0] { + } + case Message: + default: + panic("whats going on") + } + */ + panic("please dont call this") +} + +// Tree lists all paths within the object under 'path', and up to the given depth. +// To list the entire object (similar to `find .`) pass "" and -1 +func (f *filecoinIpldNode) Tree(path string, depth int) []string { + panic("dont call this either") +} + +func (f *filecoinIpldNode) ResolveLink(path []string) (*ipld.Link, []string, error) { + panic("please no") +} + +func (f *filecoinIpldNode) Stat() (*ipld.NodeStat, error) { + panic("dont call this") + +} + +func (f *filecoinIpldNode) Size() (uint64, error) { + panic("dont call this") +} + +func (f *filecoinIpldNode) Loggable() map[string]interface{} { + return nil +} + +func (f *filecoinIpldNode) RawData() []byte { + switch t := f.val.(type) { + case BlockHeader: + sb, err := t.ToStorageBlock() + if err != nil { + panic(err) + } + return sb.RawData() + case SignedMessage: + sb, err := t.ToStorageBlock() + if err != nil { + panic(err) + } + return sb.RawData() + default: + panic("whats going on") + } +} + +func (f *filecoinIpldNode) String() string { + return "cats" +} + +type FullBlock struct { + Header *BlockHeader + Messages []*SignedMessage +} + +func (fb *FullBlock) Cid() cid.Cid { + return fb.Header.Cid() +} + +type BlockMsg struct { + Header *BlockHeader + Messages []cid.Cid +} + +func DecodeBlockMsg(b []byte) (*BlockMsg, error) { + var bm BlockMsg + if err := cbor.DecodeInto(b, &bm); err != nil { + return nil, err + } + + return &bm, nil +} + +func (bm *BlockMsg) Cid() cid.Cid { + return bm.Header.Cid() +} + +func (bm *BlockMsg) Serialize() ([]byte, error) { + return cbor.DumpObject(bm) +} diff --git a/chain/vm.go b/chain/vm.go new file mode 100644 index 00000000000..22a96bb918c --- /dev/null +++ b/chain/vm.go @@ -0,0 +1,208 @@ +package chain + +import ( + "context" + "fmt" + "math/big" + + "github.com/filecoin-project/go-lotus/chain/address" + + bserv "github.com/ipfs/go-blockservice" + cid "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" + ipld "github.com/ipfs/go-ipld-format" + dag "github.com/ipfs/go-merkledag" + "github.com/pkg/errors" +) + +type VMContext struct { + state *StateTree + msg *Message + height uint64 + cst *hamt.CborIpldStore +} + +// Message is the message that kicked off the current invocation +func (vmc *VMContext) Message() *Message { + return vmc.msg +} + +/* +// Storage provides access to the VM storage layer +func (vmc *VMContext) Storage() Storage { + panic("nyi") +} +*/ + +func (vmc *VMContext) Ipld() *hamt.CborIpldStore { + return vmc.cst +} + +// Send allows the current execution context to invoke methods on other actors in the system +func (vmc *VMContext) Send(to address.Address, method string, value *big.Int, params []interface{}) ([][]byte, uint8, error) { + panic("nyi") +} + +// BlockHeight returns the height of the block this message was added to the chain in +func (vmc *VMContext) BlockHeight() uint64 { + return vmc.height +} + +func (vmc *VMContext) GasUsed() BigInt { + return NewInt(0) +} + +func makeVMContext(state *StateTree, msg *Message, height uint64) *VMContext { + return &VMContext{ + state: state, + msg: msg, + height: height, + } +} + +type VM struct { + cstate *StateTree + base cid.Cid + cs *ChainStore + buf *BufferedBS + blockHeight uint64 + blockMiner address.Address +} + +func NewVM(base cid.Cid, height uint64, maddr address.Address, cs *ChainStore) (*VM, error) { + buf := NewBufferedBstore(cs.bs) + cst := hamt.CSTFromBstore(buf) + state, err := LoadStateTree(cst, base) + if err != nil { + return nil, err + } + + return &VM{ + cstate: state, + base: base, + cs: cs, + buf: buf, + blockHeight: height, + blockMiner: maddr, + }, nil +} + +func (vm *VM) ApplyMessage(msg *Message) (*MessageReceipt, error) { + st := vm.cstate + st.Snapshot() + fromActor, err := st.GetActor(msg.From) + if err != nil { + return nil, errors.Wrap(err, "from actor not found") + } + + gascost := BigMul(msg.GasLimit, msg.GasPrice) + totalCost := BigAdd(gascost, msg.Value) + if BigCmp(fromActor.Balance, totalCost) < 0 { + return nil, fmt.Errorf("not enough funds") + } + + if msg.Nonce != fromActor.Nonce { + return nil, fmt.Errorf("invalid nonce") + } + fromActor.Nonce++ + + toActor, err := st.GetActor(msg.To) + if err != nil { + if err == ErrActorNotFound { + a, err := TryCreateAccountActor(st, msg.To) + if err != nil { + return nil, err + } + toActor = a + } else { + return nil, err + } + } + + if err := DeductFunds(fromActor, totalCost); err != nil { + return nil, errors.Wrap(err, "failed to deduct funds") + } + DepositFunds(toActor, msg.Value) + + vmctx := makeVMContext(st, msg, vm.blockHeight) + + var errcode byte + var ret []byte + if msg.Method != 0 { + ret, errcode, err = vm.Invoke(toActor, vmctx, msg.Method, msg.Params) + if err != nil { + return nil, err + } + + if errcode != 0 { + // revert all state changes since snapshot + st.Revert() + gascost := BigMul(vmctx.GasUsed(), msg.GasPrice) + if err := DeductFunds(fromActor, gascost); err != nil { + panic("invariant violated: " + err.Error()) + } + } else { + // refund unused gas + refund := BigMul(BigSub(msg.GasLimit, vmctx.GasUsed()), msg.GasPrice) + DepositFunds(fromActor, refund) + } + } + + // reward miner gas fees + miner, err := st.GetActor(vm.blockMiner) + if err != nil { + return nil, errors.Wrap(err, "getting block miner actor failed") + } + + gasReward := BigMul(msg.GasPrice, vmctx.GasUsed()) + DepositFunds(miner, gasReward) + + return &MessageReceipt{ + ExitCode: errcode, + Return: ret, + GasUsed: vmctx.GasUsed(), + }, nil +} + +func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { + from := dag.NewDAGService(bserv.New(vm.buf, nil)) + to := dag.NewDAGService(bserv.New(vm.buf.read, nil)) + + root, err := vm.cstate.Flush() + if err != nil { + return cid.Undef, err + } + + if err := ipld.Copy(ctx, from, to, root); err != nil { + return cid.Undef, err + } + + return root, nil +} + +func (vm *VM) TransferFunds(from, to address.Address, amt BigInt) error { + if from == to { + return nil + } + + fromAct, err := vm.cstate.GetActor(from) + if err != nil { + return err + } + + toAct, err := vm.cstate.GetActor(from) + if err != nil { + return err + } + + if err := DeductFunds(fromAct, amt); err != nil { + return errors.Wrap(err, "failed to deduct funds") + } + DepositFunds(toAct, amt) + + return nil +} + +func (vm *VM) Invoke(act *Actor, vmctx *VMContext, method uint64, params []byte) ([]byte, byte, error) { + panic("Implement me") +} diff --git a/chain/wallet.go b/chain/wallet.go new file mode 100644 index 00000000000..96fc4f92466 --- /dev/null +++ b/chain/wallet.go @@ -0,0 +1,195 @@ +package chain + +import ( + "encoding/binary" + "fmt" + + "github.com/filecoin-project/go-lotus/chain/address" + "github.com/filecoin-project/go-lotus/lib/bls-signatures" + "github.com/filecoin-project/go-lotus/lib/crypto" + + "github.com/minio/blake2b-simd" +) + +const ( + KTSecp256k1 = "secp256k1" + KTBLS = "bls" +) + +type Wallet struct { + keys map[address.Address]*KeyInfo +} + +func NewWallet() *Wallet { + return &Wallet{keys: make(map[address.Address]*KeyInfo)} +} + +type Signature struct { + Type string + Data []byte +} + +func SignatureFromBytes(x []byte) (Signature, error) { + val, nr := binary.Uvarint(x) + if nr != 1 { + return Signature{}, fmt.Errorf("signatures with type field longer than one byte are invalid") + } + var ts string + switch val { + case 1: + ts = KTSecp256k1 + default: + return Signature{}, fmt.Errorf("unsupported signature type: %d", val) + } + + return Signature{ + Type: ts, + Data: x[1:], + }, nil +} + +func (s *Signature) Verify(addr address.Address, msg []byte) error { + b2sum := blake2b.Sum256(msg) + + switch s.Type { + case KTSecp256k1: + pubk, err := crypto.EcRecover(b2sum[:], s.Data) + if err != nil { + return err + } + + maybeaddr, err := address.NewSecp256k1Address(pubk) + if err != nil { + return err + } + + if addr != maybeaddr { + return fmt.Errorf("signature did not match") + } + + return nil + default: + return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type) + } +} + +func (s *Signature) TypeCode() int { + switch s.Type { + case KTSecp256k1: + return 1 + case KTBLS: + return 2 + default: + panic("unsupported signature type") + } +} + +func (w *Wallet) Sign(addr address.Address, msg []byte) (*Signature, error) { + ki, err := w.findKey(addr) + if err != nil { + return nil, err + } + + switch ki.Type { + case KTSecp256k1: + b2sum := blake2b.Sum256(msg) + sig, err := crypto.Sign(ki.PrivateKey, b2sum[:]) + if err != nil { + return nil, err + } + + return &Signature{ + Type: KTSecp256k1, + Data: sig, + }, nil + case KTBLS: + var pk bls.PrivateKey + copy(pk[:], ki.PrivateKey) + sig := bls.PrivateKeySign(pk, msg) + + return &Signature{ + Type: KTBLS, + Data: sig[:], + }, nil + + default: + panic("cant do it sir") + } +} + +func (w *Wallet) findKey(addr address.Address) (*KeyInfo, error) { + ki, ok := w.keys[addr] + if !ok { + return nil, fmt.Errorf("key not for given address not found in wallet") + } + return ki, nil +} + +func (w *Wallet) Export(addr address.Address) ([]byte, error) { + panic("nyi") +} + +func (w *Wallet) Import(kdata []byte) (address.Address, error) { + panic("nyi") +} + +func (w *Wallet) GenerateKey(typ string) (address.Address, error) { + switch typ { + case KTSecp256k1: + k, err := crypto.GenerateKey() + if err != nil { + return address.Undef, err + } + ki := &KeyInfo{ + PrivateKey: k, + Type: typ, + } + + addr := ki.Address() + w.keys[addr] = ki + return addr, nil + case KTBLS: + priv := bls.PrivateKeyGenerate() + + ki := &KeyInfo{ + PrivateKey: priv[:], + Type: KTBLS, + } + + addr := ki.Address() + w.keys[addr] = ki + return addr, nil + default: + return address.Undef, fmt.Errorf("invalid key type: %s", typ) + } +} + +type KeyInfo struct { + PrivateKey []byte + + Type string +} + +func (ki *KeyInfo) Address() address.Address { + switch ki.Type { + case KTSecp256k1: + pub := crypto.PublicKey(ki.PrivateKey) + addr, err := address.NewSecp256k1Address(pub) + if err != nil { + panic(err) + } + + return addr + case KTBLS: + var pk bls.PrivateKey + copy(pk[:], ki.PrivateKey) + pub := bls.PrivateKeyPublicKey(pk) + a, err := address.NewBLSAddress(pub[:]) + if err != nil { + panic(err) + } + return a + default: + panic("unsupported key type") + } +} diff --git a/daemon/rpc.go b/daemon/rpc.go index 78df124c27a..1426f38ceba 100644 --- a/daemon/rpc.go +++ b/daemon/rpc.go @@ -4,11 +4,11 @@ import ( "net/http" "github.com/filecoin-project/go-lotus/api" - "github.com/filecoin-project/go-lotus/rpclib" + "github.com/filecoin-project/go-lotus/lib/jsonrpc" ) func serveRPC(api api.API) error { - rpcServer := rpclib.NewServer() + rpcServer := jsonrpc.NewServer() rpcServer.Register("Filecoin", api) http.Handle("/rpc/v0", rpcServer) return http.ListenAndServe(":1234", http.DefaultServeMux) diff --git a/go.mod b/go.mod index 9cf2fc07d46..2164e1cecb7 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,20 @@ go 1.12 require ( github.com/BurntSushi/toml v0.3.1 - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.3.1 // indirect + github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543 + github.com/ipfs/go-bitswap v0.1.5 + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-blockservice v0.0.2 + github.com/ipfs/go-cid v0.0.2 github.com/ipfs/go-datastore v0.0.5 + github.com/ipfs/go-hamt-ipld v0.0.0-20190613164304-cd074602062f + github.com/ipfs/go-ipfs-blockstore v0.0.1 + github.com/ipfs/go-ipfs-exchange-interface v0.0.1 github.com/ipfs/go-ipfs-routing v0.1.0 + github.com/ipfs/go-ipld-cbor v0.0.2 + github.com/ipfs/go-ipld-format v0.0.2 github.com/ipfs/go-log v0.0.2-0.20190703113630-0c3cfb1eccc4 + github.com/ipfs/go-merkledag v0.0.2 github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 github.com/libp2p/go-libp2p v0.2.0 github.com/libp2p/go-libp2p-circuit v0.1.0 @@ -27,13 +36,19 @@ require ( github.com/libp2p/go-libp2p-tls v0.1.0 github.com/libp2p/go-libp2p-yamux v0.2.1 github.com/libp2p/go-maddr-filter v0.0.4 + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/multiformats/go-multiaddr v0.0.4 github.com/multiformats/go-multihash v0.0.5 + github.com/pkg/errors v0.8.1 + github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14 github.com/stretchr/testify v1.3.0 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 + github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d + github.com/whyrusleeping/sharray v0.0.0-20190520213710-bd32aab369f8 + go.opencensus.io v0.22.0 // indirect go.uber.org/dig v1.7.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/goleak v0.10.0 // indirect gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8 - gopkg.in/yaml.v2 v2.2.2 // indirect + launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect ) diff --git a/go.sum b/go.sum index 1eaf7caebfe..d4ab70432d9 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,16 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 h1:PqzgE6kAMi81xWQA2QIVxjWkFHptGgC547vchpUbtFo= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Kubuxu/go-os-helper v0.0.1 h1:EJiD2VUQyh5A9hWJLmc6iWg6yIcJ7jpBcwC8GMGXfDk= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50 h1:4i3KsuVA0o0KoBxAC5x+MY7RbteiMK1V7gf/G08NGIQ= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -18,8 +22,11 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,9 +34,15 @@ 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/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0= github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f h1:6itBiEUtu+gOzXZWn46bM5/qm8LlV6/byR7Yflx/y6M= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f h1:dDxpBYafY/GYpcl+LS4Bn3ziLPuEdGRkRjYAbSlWxSA= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/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/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= +github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543 h1:aMJGfgqe1QDhAVwxRg5fjCRF533xHidiKsugk7Vvzug= +github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543/go.mod h1:mjrHv1cDGJWDlGmC0eDc1E5VJr8DmL9XMUcaFwiuKg8= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= @@ -48,12 +61,17 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= @@ -63,9 +81,21 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ipfs/bbloom v0.0.1 h1:s7KkiBPfxCeDVo47KySjK0ACPc5GJRUxFpdyWEuDjhw= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/go-bitswap v0.0.1/go.mod h1:z+tP3h+HTJ810n1R5yMy2ccKFffJ2F6Vqm/5Bf7vs2c= +github.com/ipfs/go-bitswap v0.1.5 h1:pgajlrTCFbbPgYJ234M1pssneLuIsVuxtfpx1I4cz3Y= +github.com/ipfs/go-bitswap v0.1.5/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.0.1/go.mod h1:2Ao89U7jV1KIqqNk5EdhSTBG/Pgc1vMFr0bhkx376j4= +github.com/ipfs/go-blockservice v0.0.2 h1:ZiKTWdZAPifdWhjjO7HjAF8grUVE86IPzcUtGCTYw4w= +github.com/ipfs/go-blockservice v0.0.2/go.mod h1:2Ao89U7jV1KIqqNk5EdhSTBG/Pgc1vMFr0bhkx376j4= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -74,23 +104,59 @@ github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6Nri github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2 h1:7ToQt7QByBhOTuZF2USMv+PGlMcBC7FW7FdgQ4FCsoo= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-hamt-ipld v0.0.0-20190613164304-cd074602062f h1:CpQZA1HsuaRQaFIUq7h/KqSyclyp/LrpcyifPnKRT2k= +github.com/ipfs/go-hamt-ipld v0.0.0-20190613164304-cd074602062f/go.mod h1:WrX60HHX2SeMb602Z1s9Ztnf/4fzNHzwH9gxNTVpEmk= +github.com/ipfs/go-ipfs-blockstore v0.0.1 h1:O9n3PbmTYZoNhkgkEyrXTznbmktIXif62xLX+8dPHzc= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-flags v0.0.1 h1:OH5cEkJYL0QgA+bvD55TNG9ud8HA2Nqaav47b2c/UJk= +github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= +github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8= +github.com/ipfs/go-ipld-cbor v0.0.2 h1:amzFztBQQQ69UA5+f7JRfoXF/z2l//MGfEDHVkS20+s= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= 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/ipfs/go-log v0.0.2-0.20190703113630-0c3cfb1eccc4 h1:4GUopYwyu/8kX0UxYB7QDYOUbnt9HCg/j6J0sMqVvNQ= github.com/ipfs/go-log v0.0.2-0.20190703113630-0c3cfb1eccc4/go.mod h1:YTiqro5xwLoGra88hB8tMBlN+7ByaT3Kdaa0UqwCmI0= +github.com/ipfs/go-merkledag v0.0.2 h1:U3Q74RLOwpbtERjCv/MODC99qSxHBw33ZeMfiGXl7ts= +github.com/ipfs/go-merkledag v0.0.2/go.mod h1:CRdtHMROECqaehAGeJ0Wd9TtlmWv/ta5cUnvbTnniEI= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-peertaskqueue v0.1.1 h1:+gPjbI+V3NktXZOqJA1kzbms2pYmhjgQQal0MzZrOAY= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-todocounter v0.0.1 h1:kITWA5ZcQZfrUnDNkRn04Xzh0YFaDFXsoO2A81Eb6Lw= github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= @@ -105,6 +171,8 @@ github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr1 github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -120,64 +188,95 @@ github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpz github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= +github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= github.com/libp2p/go-eventbus v0.0.2 h1:L9eslON8FjFBJlyUs9fyEZKnxSqZd2AMDUNldPrqmZI= github.com/libp2p/go-eventbus v0.0.2/go.mod h1:Hr/yGlwxA/stuLnpMiu82lpNKpvRy3EaJxPu40XYOwk= github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-libp2p v0.0.1/go.mod h1:bmRs8I0vwn6iRaVssZnJx/epY6WPSKiLoK1vyle4EX0= github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= github.com/libp2p/go-libp2p v0.2.0 h1:hYJgMZYdcwHzDHKb/nLePrtuSP3LqkGIFOQ2aIbKOCM= github.com/libp2p/go-libp2p v0.2.0/go.mod h1:5nXHmf4Hs+NmkaMsmWcFJgUHTbYNpCfxr20lwus0p1c= +github.com/libp2p/go-libp2p-autonat v0.0.1/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= github.com/libp2p/go-libp2p-autonat v0.1.0 h1:aCWAu43Ri4nU0ZPO7NyLzUvvfqd0nE3dX0R/ZGYVgOU= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.3 h1:0KycuXvPDhmehw0ASsg+s1o3IfXgCUDqfzAl94KEBOg= github.com/libp2p/go-libp2p-blankhost v0.1.3/go.mod h1:KML1//wiKR8vuuJO0y3LUd1uLv+tlkGTAr3jC0S5cLg= +github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE= github.com/libp2p/go-libp2p-circuit v0.1.0 h1:eniLL3Y9aq/sryfyV1IAHj5rlvuyj3b7iz8tSiZpdhY= github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= github.com/libp2p/go-libp2p-connmgr v0.1.0 h1:vp0t0F0EuT3rrlTtnMnIyyzCnly7nIlRoEbhJpgp0qU= github.com/libp2p/go-libp2p-connmgr v0.1.0/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= github.com/libp2p/go-libp2p-core v0.0.6 h1:SsYhfWJ47vLP1Rd9/0hqEm/W/PlFbC/3YLZyLCcvo1w= github.com/libp2p/go-libp2p-core v0.0.6/go.mod h1:0d9xmaYAVY5qmbp/fcgxHT3ZJsLjYeYPMJAUKpaCHrE= +github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= github.com/libp2p/go-libp2p-discovery v0.1.0 h1:j+R6cokKcGbnZLf4kcNwpx6mDEUPF3N6SrqMymQhmvs= github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-host v0.0.1 h1:dnqusU+DheGcdxrE718kG4XgHNuL2n9eEv8Rg5zy8hQ= +github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1 h1:Q9EkNSLAOF+u90L88qmE9z/fTdjLh8OsJwGw74mkwk4= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= github.com/libp2p/go-libp2p-kad-dht v0.1.1 h1:IH6NQuoUv5w5e1O8Jc3KyVDtr0rNd0G9aaADpLI1xVo= github.com/libp2p/go-libp2p-kad-dht v0.1.1/go.mod h1:1kj2Rk5pX3/0RwqMm9AMNCT7DzcMHYhgDN5VTi+cY0M= github.com/libp2p/go-libp2p-kbucket v0.2.0 h1:FB2a0VkOTNGTP5gu/I444u4WabNM9V1zCkQcWb7zajI= github.com/libp2p/go-libp2p-kbucket v0.2.0/go.mod h1:JNymBToym3QXKBMKGy3m29+xprg0EVr/GJFHxFEdgh8= +github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU= +github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-nat v0.0.1/go.mod h1:4L6ajyUIlJvx1Cbh5pc6Ma6vMDpKXf3GgLO5u7W0oQ4= github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-net v0.0.1 h1:xJ4Vh4yKF/XKb8fd1Ev0ebAGzVjMxXzrxG2kjtU+F5Q= +github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= github.com/libp2p/go-libp2p-peerstore v0.1.1 h1:AJZF2sPpVo+0aAr3IrRiGVsPjJm1INlUQ9EGClgXJ4M= github.com/libp2p/go-libp2p-peerstore v0.1.1/go.mod h1:ojEWnwG7JpJLkJ9REWYXQslyu9ZLrPWPEcCdiZzEbSM= github.com/libp2p/go-libp2p-pnet v0.1.0 h1:kRUES28dktfnHNIRW4Ro78F7rKBHBiw5MJpl0ikrLIA= github.com/libp2p/go-libp2p-pnet v0.1.0/go.mod h1:ZkyZw3d0ZFOex71halXRihWf9WH/j3OevcJdTmD0lyE= +github.com/libp2p/go-libp2p-protocol v0.0.1 h1:+zkEmZ2yFDi5adpVE3t9dqh/N9TbpFWywowzeEzBbLM= +github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-pubsub v0.1.0 h1:SmQeMa7IUv5vadh0fYgYsafWCBA1sCy5d/68kIYqGcU= github.com/libp2p/go-libp2p-pubsub v0.1.0/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-quic-transport v0.1.1 h1:MFMJzvsxIEDEVKzO89BnB/FgvMj9WI4GDGUW2ArDPUA= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= +github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0 h1:wHwBGbFzymoIl69BpgwIu0O6ta3TXGcMPvHUAcodzRc= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing v0.1.0 h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU= github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= github.com/libp2p/go-libp2p-routing-helpers v0.1.0 h1:BaFvpyv8TyhCN7TihawTiKuzeu8/Pyw7ZnMA4IvqIN8= github.com/libp2p/go-libp2p-routing-helpers v0.1.0/go.mod h1:oUs0h39vNwYtYXnQWOTU5BaafbedSyWCCal3gqHuoOQ= +github.com/libp2p/go-libp2p-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs= github.com/libp2p/go-libp2p-secio v0.1.0 h1:NNP5KLxuP97sE5Bu3iuwOWyT/dKEGMN5zSLMWdB7GTQ= github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs= github.com/libp2p/go-libp2p-swarm v0.1.0 h1:HrFk2p0awrGEgch9JXK/qp/hfjqQfgNxpLWnCiWPg5s= github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -186,16 +285,22 @@ github.com/libp2p/go-libp2p-testing v0.0.4 h1:Qev57UR47GcLPXWjrunv5aLIQGO4n9mhI/ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-tls v0.1.0 h1:o4bjjAdnUjNgJoPoDd0wUaZH7K+EenlNWJpgyXB3ulA= github.com/libp2p/go-libp2p-tls v0.1.0/go.mod h1:VZdoSWQDeNpIIAFJFv+6uqTqpnIIDHcqZQSTC/A1TT0= +github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= +github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c= github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI= github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= @@ -204,13 +309,19 @@ github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw= github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs= github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-testutil v0.0.1 h1:Xg+O0G2HIMfHqBOBDcMS1iSZJ3GEcId4qOxCQvsGZHk= +github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= +github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= github.com/libp2p/go-ws-transport v0.1.0 h1:F+0OvvdmPTDsVc4AjPHjV7L7Pk1B7D5QwtDcKE2oag4= github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= @@ -222,8 +333,11 @@ github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNA github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= 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-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 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/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12 h1:WMhc1ik4LNkTg8U9l3hI1LvxKmIL+f1+WV/SZtCbDDA= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= @@ -254,6 +368,7 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -265,20 +380,33 @@ github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 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/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14 h1:2m16U/rLwVaRdz7ANkHtHTodP3zTP3N451MADg64x5k= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 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= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= @@ -287,16 +415,26 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6 github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4= +github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ= +github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30 h1:nMCC9Pwz1pxfC1Y6mYncdk+kq8d5aLx0Q+/gyZGE44M= github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d h1:wnjWu1N8UTNf2zzF5FWlEyNNbNw5GMVHaHaaLdvdTdA= +github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A= +github.com/whyrusleeping/sharray v0.0.0-20190520213710-bd32aab369f8 h1:n89ErB+0d4SBbyD8ykr7Q/j+C41ysUttZG3l9/2ufC4= +github.com/whyrusleeping/sharray v0.0.0-20190520213710-bd32aab369f8/go.mod h1:c1pwhNePDPlcYJZinQlfLTOKwTmVf45nfdTg73yOOcA= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= +github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/dig v1.7.0 h1:E5/L92iQTNJTjfgJF2KgU+/JpMaiuvK2DHLBj0+kSZk= @@ -316,11 +454,15 @@ golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -330,6 +472,8 @@ golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -345,13 +489,20 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09 h1:IlD35wZE03o2qJy2o37WIskL33b7PT6cHdGnE8bieZs= golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae h1:xiXzMMEQdQcric9hXtr1QU98MHunKK7OTtsoU6bYWs4= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -359,7 +510,9 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -374,3 +527,5 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/lib/cborrpc/rpc.go b/lib/cborrpc/rpc.go new file mode 100644 index 00000000000..9aa8cd2f17a --- /dev/null +++ b/lib/cborrpc/rpc.go @@ -0,0 +1,29 @@ +package cborrpc + +import ( + "io" + "io/ioutil" + + cbor "github.com/ipfs/go-ipld-cbor" +) + +const MessageSizeLimit = 1 << 20 + +func WriteCborRPC(w io.Writer, obj interface{}) error { + data, err := cbor.DumpObject(obj) + if err != nil { + return err + } + + _, err = w.Write(data) + return err +} + +func ReadCborRPC(r io.Reader, out interface{}) error { + b, err := ioutil.ReadAll(r) + if err != nil { + return err + } + + return cbor.DecodeInto(b, out) +} diff --git a/rpclib/rpc_client.go b/lib/jsonrpc/rpc_client.go similarity index 99% rename from rpclib/rpc_client.go rename to lib/jsonrpc/rpc_client.go index f8116c825a9..e9418040b73 100644 --- a/rpclib/rpc_client.go +++ b/lib/jsonrpc/rpc_client.go @@ -1,4 +1,4 @@ -package rpclib +package jsonrpc import ( "bytes" diff --git a/rpclib/rpc_server.go b/lib/jsonrpc/rpc_server.go similarity index 99% rename from rpclib/rpc_server.go rename to lib/jsonrpc/rpc_server.go index 5ef1560e7af..10438086149 100644 --- a/rpclib/rpc_server.go +++ b/lib/jsonrpc/rpc_server.go @@ -1,4 +1,4 @@ -package rpclib +package jsonrpc import ( "bytes" diff --git a/rpclib/rpc_test.go b/lib/jsonrpc/rpc_test.go similarity index 99% rename from rpclib/rpc_test.go rename to lib/jsonrpc/rpc_test.go index 4879a3e3e13..d496e25c5b1 100644 --- a/rpclib/rpc_test.go +++ b/lib/jsonrpc/rpc_test.go @@ -1,4 +1,4 @@ -package rpclib +package jsonrpc import ( "context" diff --git a/node/builder.go b/node/builder.go index 7a2cc4f8a62..e4b2b7f1fb7 100644 --- a/node/builder.go +++ b/node/builder.go @@ -7,21 +7,27 @@ import ( "time" "github.com/ipfs/go-datastore" + blockstore "github.com/ipfs/go-ipfs-blockstore" + exchange "github.com/ipfs/go-ipfs-exchange-interface" ci "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" "github.com/libp2p/go-libp2p-core/routing" "github.com/libp2p/go-libp2p-peerstore/pstoremem" + pubsub "github.com/libp2p/go-libp2p-pubsub" record "github.com/libp2p/go-libp2p-record" "go.uber.org/fx" "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/build" + "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/node/config" + "github.com/filecoin-project/go-lotus/node/hello" "github.com/filecoin-project/go-lotus/node/modules" "github.com/filecoin-project/go-lotus/node/modules/helpers" "github.com/filecoin-project/go-lotus/node/modules/lp2p" + "github.com/filecoin-project/go-lotus/node/modules/testing" ) // special is a type used to give keys to modules which @@ -44,13 +50,22 @@ var ( type invoke int +//nolint:golint const ( - // PstoreAddSelfKeysKey is a key for Override for PstoreAddSelfKeys - PstoreAddSelfKeysKey = invoke(iota) + // libp2p - // StartListeningKey is a key for Override for StartListening + PstoreAddSelfKeysKey = invoke(iota) StartListeningKey + // filecoin + SetGenisisKey + + RunHelloKey + RunBlockSyncKey + + HandleIncomingBlocksKey + HandleIncomingMessagesKey + _nInvokes // keep this last ) @@ -97,8 +112,13 @@ var defaults = []Option{ randomIdentity(), - Override(new(datastore.Batching), datastore.NewMapDatastore), + Override(new(datastore.Batching), testing.MapDatastore), + Override(new(blockstore.Blockstore), testing.MapBlockstore), // NOT on top of ds above Override(new(record.Validator), modules.RecordValidator), + + // Filecoin modules + + Override(new(*chain.ChainStore), chain.NewChainStore), } // Online sets up basic libp2p node @@ -132,8 +152,32 @@ func Online() Option { Override(NatPortMapKey, lp2p.NatPortMap), Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second)), + Override(new(*pubsub.PubSub), lp2p.GossipSub()), + Override(PstoreAddSelfKeysKey, lp2p.PstoreAddSelfKeys), Override(StartListeningKey, lp2p.StartListening(defConf.Libp2p.ListenAddresses)), + + // + + Override(new(blockstore.GCLocker), blockstore.NewGCLocker), + Override(new(blockstore.GCBlockstore), blockstore.NewGCBlockstore), + Override(new(exchange.Interface), modules.Bitswap), + + // Filecoin services + Override(new(*chain.Syncer), chain.NewSyncer), + Override(new(*chain.BlockSync), chain.NewBlockSyncClient), + Override(new(*chain.Wallet), chain.NewWallet), + Override(new(*chain.MessagePool), chain.NewMessagePool), + + Override(new(modules.Genesis), testing.MakeGenesis), + Override(SetGenisisKey, modules.SetGenesis), + + Override(new(*hello.Service), hello.NewHelloService), + Override(new(*chain.BlockSyncService), chain.NewBlockSyncService), + Override(RunHelloKey, modules.RunHello), + Override(RunBlockSyncKey, modules.RunBlockSync), + Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), + Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), ) } diff --git a/node/fxlog.go b/node/fxlog.go new file mode 100644 index 00000000000..3f0e18d642e --- /dev/null +++ b/node/fxlog.go @@ -0,0 +1,17 @@ +package node + +import ( + logging "github.com/ipfs/go-log" + + "go.uber.org/fx" +) + +type debugPrinter struct { + l logging.StandardLogger +} + +func (p *debugPrinter) Printf(f string, a ...interface{}) { + p.l.Debugf(f, a...) +} + +var _ fx.Printer = new(debugPrinter) diff --git a/node/hello/hello.go b/node/hello/hello.go new file mode 100644 index 00000000000..974d6e6814a --- /dev/null +++ b/node/hello/hello.go @@ -0,0 +1,102 @@ +package hello + +import ( + "context" + "fmt" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log" + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/filecoin-project/go-lotus/chain" + "github.com/filecoin-project/go-lotus/lib/cborrpc" +) + +const ProtocolID = "/fil/hello/1.0.0" + +var log = logging.Logger("hello") + +func init() { + cbor.RegisterCborType(Message{}) +} + +type Message struct { + HeaviestTipSet []cid.Cid + HeaviestTipSetWeight uint64 + GenesisHash cid.Cid +} + +type Service struct { + newStream chain.NewStreamFunc + + cs *chain.ChainStore + syncer *chain.Syncer +} + +func NewHelloService(h host.Host, cs *chain.ChainStore, syncer *chain.Syncer) *Service { + return &Service{ + newStream: h.NewStream, + + cs: cs, + syncer: syncer, + } +} + +func (hs *Service) HandleStream(s inet.Stream) { + defer s.Close() + + var hmsg Message + if err := cborrpc.ReadCborRPC(s, &hmsg); err != nil { + log.Infow("failed to read hello message", "error", err) + return + } + log.Debugw("genesis from hello", + "tipset", hmsg.HeaviestTipSet, + "peer", s.Conn().RemotePeer(), + "hash", hmsg.GenesisHash) + + if hmsg.GenesisHash != hs.syncer.Genesis.Cids()[0] { + log.Error("other peer has different genesis!") + s.Conn().Close() + return + } + + ts, err := hs.syncer.FetchTipSet(context.Background(), s.Conn().RemotePeer(), hmsg.HeaviestTipSet) + if err != nil { + log.Errorf("failed to fetch tipset from peer during hello: %s", err) + return + } + + hs.syncer.InformNewHead(s.Conn().RemotePeer(), ts) +} + +func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { + s, err := hs.newStream(ctx, pid, ProtocolID) + if err != nil { + return err + } + + hts := hs.cs.GetHeaviestTipSet() + weight := hs.cs.Weight(hts) + gen, err := hs.cs.GetGenesis() + if err != nil { + return err + } + + hmsg := &Message{ + HeaviestTipSet: hts.Cids(), + HeaviestTipSetWeight: weight, + GenesisHash: gen.Cid(), + } + fmt.Println("SENDING HELLO MESSAGE: ", hts.Cids()) + fmt.Println("hello message genesis: ", gen.Cid()) + + if err := cborrpc.WriteCborRPC(s, hmsg); err != nil { + return err + } + + return nil +} diff --git a/node/modules/core.go b/node/modules/core.go index 5bc21fcf5c5..91aadd65904 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -1,13 +1,45 @@ package modules import ( + "context" + + "github.com/ipfs/go-bitswap" + "github.com/ipfs/go-bitswap/network" + blockstore "github.com/ipfs/go-ipfs-blockstore" + exchange "github.com/ipfs/go-ipfs-exchange-interface" + logging "github.com/ipfs/go-log" + "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" record "github.com/libp2p/go-libp2p-record" + "go.uber.org/fx" + + "github.com/filecoin-project/go-lotus/chain" + "github.com/filecoin-project/go-lotus/node/modules/helpers" ) +var log = logging.Logger("modules") + +type Genesis *chain.BlockHeader + // RecordValidator provides namesys compatible routing record validator func RecordValidator(ps peerstore.Peerstore) record.Validator { return record.NamespacedValidator{ "pk": record.PublicKeyValidator{}, } } + +func Bitswap(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs blockstore.GCBlockstore) exchange.Interface { + bitswapNetwork := network.NewFromIpfsHost(host, rt) + exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, bs) + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return exch.Close() + }, + }) + return exch +} + +func SetGenesis(cs *chain.ChainStore, g Genesis) error { + return cs.SetGenesis(g) +} diff --git a/node/modules/services.go b/node/modules/services.go new file mode 100644 index 00000000000..099b9e12558 --- /dev/null +++ b/node/modules/services.go @@ -0,0 +1,55 @@ +package modules + +import ( + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.uber.org/fx" + + "github.com/filecoin-project/go-lotus/chain" + "github.com/filecoin-project/go-lotus/chain/sub" + "github.com/filecoin-project/go-lotus/node/hello" + "github.com/filecoin-project/go-lotus/node/modules/helpers" +) + +func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.Service) { + h.SetStreamHandler(hello.ProtocolID, svc.HandleStream) + + bundle := inet.NotifyBundle{ + ConnectedF: func(_ inet.Network, c inet.Conn) { + go func() { + if err := svc.SayHello(helpers.LifecycleCtx(mctx, lc), c.RemotePeer()); err != nil { + log.Warnw("failed to say hello", "error", err) + return + } + }() + }, + } + h.Network().Notify(&bundle) +} + +func RunBlockSync(h host.Host, svc *chain.BlockSyncService) { + h.SetStreamHandler(chain.BlockSyncProtocolID, svc.HandleStream) +} + +func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, pubsub *pubsub.PubSub, s *chain.Syncer) { + ctx := helpers.LifecycleCtx(mctx, lc) + + blocksub, err := pubsub.Subscribe("/fil/blocks") + if err != nil { + panic(err) + } + + go sub.HandleIncomingBlocks(ctx, blocksub, s) +} + +func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, pubsub *pubsub.PubSub, mpool *chain.MessagePool) { + ctx := helpers.LifecycleCtx(mctx, lc) + + msgsub, err := pubsub.Subscribe("/fil/messages") + if err != nil { + panic(err) + } + + go sub.HandleIncomingMessages(ctx, mpool, msgsub) +} diff --git a/node/modules/testing/genesis.go b/node/modules/testing/genesis.go new file mode 100644 index 00000000000..094302286cc --- /dev/null +++ b/node/modules/testing/genesis.go @@ -0,0 +1,16 @@ +package testing + +import ( + blockstore "github.com/ipfs/go-ipfs-blockstore" + + "github.com/filecoin-project/go-lotus/chain" + "github.com/filecoin-project/go-lotus/node/modules" +) + +func MakeGenesis(bs blockstore.Blockstore, w *chain.Wallet) (modules.Genesis, error) { + genb, err := chain.MakeGenesisBlock(bs, w) + if err != nil { + return nil, err + } + return genb.Genesis, nil +} diff --git a/node/modules/testing/storage.go b/node/modules/testing/storage.go new file mode 100644 index 00000000000..6d00bd94bca --- /dev/null +++ b/node/modules/testing/storage.go @@ -0,0 +1,18 @@ +package testing + +import ( + "github.com/ipfs/go-datastore" + dsync "github.com/ipfs/go-datastore/sync" + blockstore "github.com/ipfs/go-ipfs-blockstore" +) + +func MapBlockstore() blockstore.Blockstore { + // TODO: proper datastore + bds := dsync.MutexWrap(datastore.NewMapDatastore()) + bs := blockstore.NewBlockstore(bds) + return blockstore.NewIdStore(bs) +} + +func MapDatastore() datastore.Batching { + return dsync.MutexWrap(datastore.NewMapDatastore()) +} diff --git a/scripts/README b/scripts/README new file mode 100644 index 00000000000..43eedb8003d --- /dev/null +++ b/scripts/README @@ -0,0 +1,3 @@ +From https://github.com/filecoin-project/go-filecoin/tree/master/scripts + +Try to keep in sync \ No newline at end of file diff --git a/scripts/install-bls-signatures.sh b/scripts/install-bls-signatures.sh new file mode 100755 index 00000000000..59ed6f734d7 --- /dev/null +++ b/scripts/install-bls-signatures.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -Eeo pipefail + +source "$(dirname "${BASH_SOURCE[0]}")/install-shared.bash" + +subm_dir="lib/bls-signatures/bls-signatures" + +git submodule update --init --recursive $subm_dir + +if download_release_tarball tarball_path "${subm_dir}"; then + tmp_dir=$(mktemp -d) + tar -C $tmp_dir -xzf $tarball_path + + cp -R "${tmp_dir}/include" lib/bls-signatures + cp -R "${tmp_dir}/lib" lib/bls-signatures +else + (>&2 echo "failed to find or obtain precompiled assets for ${subm_dir}, falling back to local build") + build_from_source "${subm_dir}" + + mkdir -p lib/bls-signatures/include + mkdir -p lib/bls-signatures/lib/pkgconfig + + find "${subm_dir}" -type f -name libbls_signatures.h -exec mv -- "{}" ./lib/bls-signatures/include/ \; + find "${subm_dir}" -type f -name libbls_signatures_ffi.a -exec cp -- "{}" ./lib/bls-signatures/lib/ \; + find "${subm_dir}" -type f -name libbls_signatures.pc -exec cp -- "{}" ./lib/bls-signatures/lib/pkgconfig/ \; +fi diff --git a/scripts/install-shared.bash b/scripts/install-shared.bash new file mode 100755 index 00000000000..19474a0b2f8 --- /dev/null +++ b/scripts/install-shared.bash @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +download_release_tarball() { + __resultvar=$1 + __submodule_path=$2 + __repo_name=$(echo $2 | cut -d '/' -f 2) + __release_name="${__repo_name}-$(uname)" + __release_sha1=$(git rev-parse @:"${__submodule_path}") + __release_tag="${__release_sha1:0:16}" + __release_tag_url="https://api.github.com/repos/filecoin-project/${__repo_name}/releases/tags/${__release_tag}" + + echo "acquiring release @ ${__release_tag}" + + __release_response=$(curl \ + --retry 3 \ + --location $__release_tag_url) + + __release_url=$(echo $__release_response | jq -r ".assets[] | select(.name | contains(\"${__release_name}\")) | .url") + + if [[ -z "$__release_url" ]]; then + (>&2 echo "failed to download release (tag URL: ${__release_tag_url}, response: ${__release_response})") + return 1 + fi + + __tar_path="/tmp/${__release_name}_$(basename ${__release_url}).tar.gz" + + if [[ ! -f "${__tar_path}" ]]; then + __asset_url=$(curl \ + --head \ + --retry 3 \ + --header "Accept:application/octet-stream" \ + --location \ + --output /dev/null \ + -w %{url_effective} \ + "$__release_url") + + curl --retry 3 --output "${__tar_path}" "$__asset_url" + if [[ $? -ne "0" ]]; then + (>&2 echo "failed to download release asset (tag URL: ${__release_tag_url}, asset URL: ${__asset_url})") + return 1 + fi + fi + + eval $__resultvar="'$__tar_path'" +} + +build_from_source() { + __submodule_path=$1 + __submodule_sha1=$(git rev-parse @:"${__submodule_path}") + __submodule_sha1_truncated="${__submodule_sha1:0:16}" + + echo "building from source @ ${__submodule_sha1_truncated}" + + if ! [ -x "$(command -v cargo)" ]; then + (>&2 echo 'Error: cargo is not installed.') + (>&2 echo 'Install Rust toolchain to resolve this problem.') + exit 1 + fi + + if ! [ -x "$(command -v rustup)" ]; then + (>&2 echo 'Error: rustup is not installed.') + (>&2 echo 'Install Rust toolchain installer to resolve this problem.') + exit 1 + fi + + pushd $__submodule_path + + cargo --version + cargo update + + if [[ -f "./scripts/build-release.sh" ]]; then + ./scripts/build-release.sh $(cat rust-toolchain) + else + cargo build --release --all + fi + + popd +}