Merge pull request #130 from filecoin-project/feat/pond-trasfers

More Pond inspections
This commit is contained in:
Łukasz Magiera 2019-08-12 19:09:59 +02:00 committed by GitHub
commit 2194f52852
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 553 additions and 124 deletions

View File

@ -52,6 +52,11 @@ type SectorInfo struct {
CommR []byte
}
type ActorState struct {
Balance types.BigInt
State interface{}
}
type Common interface {
// Auth
AuthVerify(ctx context.Context, token string) ([]string, error)
@ -85,6 +90,8 @@ type FullNode interface {
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
ChainGetBlockReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
// if tipset is nil, we'll use heaviest
ChainCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
@ -111,6 +118,7 @@ type FullNode interface {
WalletList(context.Context) ([]address.Address, error)
WalletBalance(context.Context, address.Address) (types.BigInt, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error)
WalletDefaultAddress(context.Context) (address.Address, error)
// Other
@ -135,6 +143,8 @@ type FullNode interface {
type StorageMiner interface {
Common
ActorAddresses(context.Context) ([]address.Address, error)
// Temp api for testing
StoreGarbageData(context.Context) (uint64, error)

View File

@ -48,6 +48,8 @@ type FullNodeStruct struct {
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetBlockReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
ChainGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
ChainReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
@ -55,13 +57,14 @@ type FullNodeStruct struct {
MinerStart func(context.Context, address.Address) error `perm:"admin"`
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"`
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"`
WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
ClientImport func(ctx context.Context, path string) (cid.Cid, error) `perm:"write"`
ClientListImports func(ctx context.Context) ([]Import, error) `perm:"read"`
@ -76,6 +79,8 @@ type StorageMinerStruct struct {
CommonStruct
Internal struct {
ActorAddresses func(context.Context) ([]address.Address, error) `perm:"read"`
StoreGarbageData func(context.Context) (uint64, error) `perm:"write"`
SectorsStatus func(context.Context, uint64) (sectorbuilder.SectorSealingStatus, error) `perm:"read"`
@ -170,6 +175,14 @@ func (c *FullNodeStruct) ChainCall(ctx context.Context, msg *types.Message, ts *
return c.Internal.ChainCall(ctx, msg, ts)
}
func (c *FullNodeStruct) ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
return c.Internal.ChainGetActor(ctx, actor, ts)
}
func (c *FullNodeStruct) ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) {
return c.Internal.ChainReadState(ctx, act, ts)
}
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ string) (address.Address, error) {
return c.Internal.WalletNew(ctx, typ)
}
@ -190,6 +203,10 @@ func (c *FullNodeStruct) WalletSign(ctx context.Context, k address.Address, msg
return c.Internal.WalletSign(ctx, k, msg)
}
func (c *FullNodeStruct) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
return c.Internal.WalletSignMessage(ctx, k, msg)
}
func (c *FullNodeStruct) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
return c.Internal.WalletDefaultAddress(ctx)
}
@ -222,6 +239,10 @@ func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.
return c.Internal.StateMinerProvingSet(ctx, addr)
}
func (c *StorageMinerStruct) ActorAddresses(ctx context.Context) ([]address.Address, error) {
return c.Internal.ActorAddresses(ctx)
}
func (c *StorageMinerStruct) StoreGarbageData(ctx context.Context) (uint64, error) {
return c.Internal.StoreGarbageData(ctx)
}

View File

@ -1,6 +1,7 @@
package chain
import (
"encoding/base64"
"sync"
"github.com/filecoin-project/go-lotus/chain/address"
@ -54,6 +55,8 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
return err
}
log.Info("mpooladd: %s", base64.StdEncoding.EncodeToString(data))
if err := m.Signature.Verify(m.Message.From, data); err != nil {
return err
}

View File

@ -15,7 +15,7 @@ import (
)
func main() {
logging.SetLogLevel("*", "INFO")
logging.SetLogLevel("*", "DEBUG")
local := []*cli.Command{
DaemonCmd,
}

1
go.mod
View File

@ -62,7 +62,6 @@ require (
github.com/polydawn/refmt v0.0.0-20190731040541-eff0b363297a
github.com/smartystreets/assertions v1.0.1 // indirect
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
github.com/stretchr/objx v0.1.1 // indirect
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

View File

@ -212,6 +212,7 @@ func (h handlers) handle(ctx context.Context, req request, w func(func(io.Writer
if handler.errOut != -1 {
err := callResult[handler.errOut].Interface()
if err != nil {
log.Warnf("error in RPC call: %s", err)
resp.Error = &respError{
Code: 1,
Message: err.(error).Error(),
@ -232,7 +233,7 @@ func (h handlers) handle(ctx context.Context, req request, w func(func(io.Writer
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
fmt.Println(err)
log.Error(err)
return
}
})

View File

@ -73,6 +73,7 @@ func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func rpcError(wf func(func(io.Writer)), req *request, code int, err error) {
log.Errorf("RPC Error: %s", err)
wf(func(w io.Writer) {
if hw, ok := w.(http.ResponseWriter); ok {
hw.WriteHeader(500)

View File

@ -2435,6 +2435,14 @@
}
}
},
"base-x": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz",
"integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"base64-js": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
@ -2458,11 +2466,21 @@
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
},
"bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
},
"binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
},
"blakejs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz",
"integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U="
},
"bluebird": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
@ -2533,6 +2551,18 @@
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"borc": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/borc/-/borc-2.1.1.tgz",
"integrity": "sha512-vPLLC2/gS0QN4O3cnPh+8jLshkMMD4qIfs+B1TPGPh30WrtcfItaO6j4k9alsqu/hIgKi8dVdmMvTcbq4tIF7A==",
"requires": {
"bignumber.js": "^9.0.0",
"commander": "^2.15.0",
"ieee754": "^1.1.8",
"iso-url": "~0.4.4",
"json-text-sequence": "~0.1.0"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -2669,6 +2699,14 @@
"node-releases": "^1.1.25"
}
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "^3.0.2"
}
},
"bser": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz",
@ -3368,6 +3406,17 @@
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
},
"cids": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cids/-/cids-0.7.1.tgz",
"integrity": "sha512-qEM4j2GKE/BiT6WdUi6cfW8dairhSLTUE8tIdxJG6SvY33Mp/UPjw+xcO0n1zsllgo72BupzKF/44v+Bg8YPPg==",
"requires": {
"class-is": "^1.1.0",
"multibase": "~0.6.0",
"multicodec": "~0.5.1",
"multihashes": "~0.4.14"
}
},
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@ -3382,6 +3431,11 @@
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz",
"integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ=="
},
"class-is": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
"integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw=="
},
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@ -4223,6 +4277,11 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delimit-stream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz",
"integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@ -4495,6 +4554,11 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"err-code": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
"integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA="
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@ -6265,6 +6329,18 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
"ipld-dag-cbor": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.15.0.tgz",
"integrity": "sha512-wc9nrDtV4Le76UUhG4LXX57NVi5d7JS2kLid2nOYZAcr0SFhiXZL2ZyV3bfmNohO50KvgPEessSaBBSm9bflGA==",
"requires": {
"borc": "^2.1.0",
"cids": "~0.7.0",
"is-circular": "^1.0.2",
"multicodec": "~0.5.0",
"multihashing-async": "~0.7.0"
}
},
"is-absolute-url": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
@ -6314,6 +6390,11 @@
"ci-info": "^2.0.0"
}
},
"is-circular": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-circular/-/is-circular-1.0.2.tgz",
"integrity": "sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA=="
},
"is-class": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/is-class/-/is-class-0.0.4.tgz",
@ -6511,6 +6592,11 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"iso-url": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.6.tgz",
"integrity": "sha512-YQO7+aIe6l1aSJUKOx+Vrv08DlhZeLFIVfehG2L29KLSEb9RszqPXilxJRVpp57px36BddKR5ZsebacO5qG0tg=="
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
@ -7642,6 +7728,11 @@
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
"integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="
},
"js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -7780,6 +7871,14 @@
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json-text-sequence": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz",
"integrity": "sha1-py8hfcSvxGKf/1/rME3BvVGi89I=",
"requires": {
"delimit-stream": "0.1.0"
}
},
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@ -8397,6 +8496,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"multibase": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.0.tgz",
"integrity": "sha512-R9bNLQhbD7MsitPm1NeY7w9sDgu6d7cuj25snAWH7k5PSNPSwIQQBpcpj8jx1W96dLbdigZqmUWOdQRMnAmgjA==",
"requires": {
"base-x": "3.0.4"
}
},
"multicast-dns": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
@ -8411,6 +8518,52 @@
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
},
"multicodec": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.5.tgz",
"integrity": "sha512-1kOifvwAqp9IdiiTKmpK2tS+LY6GHZdKpk3S2EvW4T32vlwDyA3hJoZtGauzqdedUPVNGChnTksEotVOCVlC+Q==",
"requires": {
"varint": "^5.0.0"
}
},
"multihashes": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.15.tgz",
"integrity": "sha512-G/Smj1GWqw1RQP3dRuRRPe3oyLqvPqUaEDIaoi7JF7Loxl4WAWvhJNk84oyDEodSucv0MmSW/ZT0RKUrsIFD3g==",
"requires": {
"bs58": "^4.0.1",
"varint": "^5.0.0"
}
},
"multihashing-async": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.7.0.tgz",
"integrity": "sha512-SCbfl3f+DzJh+/5piukga9ofIOxwfT05t8R4jfzZIJ88YE9zU9+l3K2X+XB19MYyxqvyK9UJRNWbmQpZqQlbRA==",
"requires": {
"blakejs": "^1.1.0",
"buffer": "^5.2.1",
"err-code": "^1.1.2",
"js-sha3": "~0.8.0",
"multihashes": "~0.4.13",
"murmurhash3js-revisited": "^3.0.0"
},
"dependencies": {
"buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
}
}
},
"murmurhash3js-revisited": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz",
"integrity": "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g=="
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
@ -12325,6 +12478,11 @@
"spdx-expression-parse": "^3.0.0"
}
},
"varint": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
"integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@ -3,7 +3,11 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"borc": "^2.1.1",
"cids": "^0.7.1",
"ipld-dag-cbor": "^0.15.0",
"jsonrpc-websocket-client": "^0.5.0",
"multihashes": "^0.4.15",
"react": "^16.8.6",
"react-cristal": "^0.0.12",
"react-dom": "^16.8.6",

View File

@ -0,0 +1,66 @@
import React from 'react'
import CID from 'cids'
import * as multihash from "multihashes";
import State from "./State";
function truncAddr(addr) {
if (addr.length > 21) {
return <abbr title={addr}>{addr.substr(0, 18) + '..'}</abbr>
}
return addr
}
class Address extends React.Component {
constructor(props) {
super(props)
this.openState = this.openState.bind(this)
this.state = {balance: -2}
this.refresh = this.refresh.bind(this)
}
componentDidMount() {
this.refresh()
if(!this.props.ts)
setInterval(this.refresh, 2050)
}
async refresh() {
let balance = 0
let actor = {}
try {
balance = await this.props.client.call('Filecoin.WalletBalance', [this.props.addr])
actor = await this.props.client.call('Filecoin.ChainGetActor', [this.props.addr, this.props.ts || null])
} catch (err) {
balance = -1
}
this.setState({balance, actor})
}
openState() {
this.props.mountWindow((onClose) => <State addr={this.props.addr} actor={this.state.actor} client={this.props.client} onClose={onClose}/>)
}
render() {
let add1k = <span/>
if(this.props.add1k) {
add1k = <a href="#" onClick={() => this.props.add1k(this.props.addr)}>[+1k]</a>
}
let addr = truncAddr(this.props.addr)
let actInfo = <span>(?)</span>
if(this.state.balance >= 0) {
const c = new CID(this.state.actor.Code['/'])
const mh = multihash.decode(c.multihash) // TODO: check identity
actInfo = <span>({mh.digest.toString()})</span>
addr = <a href="#" onClick={this.openState}>{addr}</a>
}
return <span>{addr}:&nbsp;{this.state.balance}&nbsp;{actInfo}&nbsp;{add1k}</span>
}
}
export default Address

View File

@ -28,6 +28,22 @@
display: inline-block;
}
.Block {
background: #f9be77;
user-select: text;
font-family: monospace;
min-width: 40em;
display: inline-block;
}
.State {
background: #f9be77;
user-select: text;
font-family: monospace;
min-width: 40em;
display: inline-block;
}
.CristalScroll {
display: flex;
min-width: 100%;

View File

@ -1,6 +1,7 @@
import React from 'react';
import {Cristal} from "react-cristal";
import {BlockLinks} from "./BlockLink";
import Address from "./Address";
class Block extends React.Component {
constructor(props) {
@ -13,7 +14,9 @@ class Block extends React.Component {
async loadHeader() {
const header = await this.props.conn.call('Filecoin.ChainGetBlock', [this.props.cid])
this.setState({header: header})
const messages = await this.props.conn.call('Filecoin.ChainGetBlockMessages', [this.props.cid])
console.log(messages)
this.setState({header: header, messages: messages})
}
render() {
@ -21,17 +24,30 @@ class Block extends React.Component {
if (this.state.header) {
let head = this.state.header
content = (
let messages = [
...(this.state.messages.BlsMessages.map(m => ({...m, type: 'BLS'}))),
...(this.state.messages.SecpkMessages.map(m => ({...(m.Message), type: 'Secpk'})))
].map(m => (
<div>
<Address client={this.props.conn} addr={m.From} mountWindow={this.props.mountWindow}/><b>=>&nbsp;</b>
<Address client={this.props.conn} addr={m.To} mountWindow={this.props.mountWindow}/>
{m.Value}FIL&nbsp;M{m.Method}
</div>
))
content = (
<div className="Block">
<div>Height: {head.Height}</div>
<div>Parents: <BlockLinks cids={head.Parents} conn={this.props.conn} mountWindow={this.props.mountWindow}/></div>
<div>Weight: {head.ParentWeight}</div>
<div>Miner: {head.Miner}</div>
<div>Miner: {<Address client={this.props.conn} addr={head.Miner} mountWindow={this.props.mountWindow}/>}</div>
<div>Messages: {head.Messages['/']} {/*TODO: link to message explorer */}</div>
<div>Receipts: {head.MessageReceipts['/']}</div>
<div>State Root: {head.StateRoot['/']}</div>
<div>State Root:&nbsp;{head.StateRoot['/']}</div>
<div>----</div>
<div>{messages}</div>
</div>
)
}

View File

@ -4,7 +4,7 @@ import Block from "./Block";
export class BlockLinks extends React.Component {
render() {
return this.props.cids.map(c => <BlockLink conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>)
return this.props.cids.map(c => <BlockLink key={c} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>)
}
}

View File

@ -26,7 +26,7 @@ class ConnMgr extends React.Component {
let keys = Object.keys(nodes)
const newConns = await keys.filter((_, i) => i > 0).map(async (kfrom, i) => {
return await keys.filter((_, j) => i >= j).map(async kto => {
return keys.filter((_, j) => i >= j).map(async kto => {
const fromNd = this.props.nodes[kfrom]
const toNd = this.props.nodes[kto]

View File

@ -3,30 +3,17 @@ import { Client } from 'rpc-websockets'
import Cristal from 'react-cristal'
import { BlockLinks } from "./BlockLink";
import StorageNodeInit from "./StorageNodeInit";
const stateConnected = 'connected'
const stateConnecting = 'connecting'
const stateGettingToken = 'getting-token'
import Address from "./Address";
async function awaitListReducer(prev, c) {
return [...await prev, await c]
}
function truncAddr(addr) {
if (addr.length > 41) {
return <abbr title={addr}>{addr.substr(0, 38) + '...'}</abbr>
}
return addr
}
class FullNode extends React.Component {
constructor(props) {
super(props)
this.state = {
state: stateGettingToken,
id: "~",
mining: false,
}
@ -34,69 +21,45 @@ class FullNode extends React.Component {
this.startMining = this.startMining.bind(this)
this.newScepAddr = this.newScepAddr.bind(this)
this.startStorageMiner = this.startStorageMiner.bind(this)
this.add1k = this.add1k.bind(this)
this.connect()
}
async connect() {
const token = await this.props.pondClient.call('Pond.TokenFor', [this.props.node.ID])
this.setState(() => ({
state: stateConnecting,
token: token,
}))
const client = new Client(`ws://127.0.0.1:${this.props.node.ApiPort}/rpc/v0?token=${token}`)
client.on('open', async () => {
this.setState(() => ({
state: stateConnected,
client: client,
version: {Version: "~version~"},
id: "~peerid~",
peers: -1,
balances: []
}))
const id = await this.state.client.call("Filecoin.ID", [])
this.setState(() => ({id: id}))
this.props.onConnect(client, id)
this.loadInfo()
setInterval(this.loadInfo, 2050)
})
console.log(token) // todo: use
this.loadInfo()
setInterval(this.loadInfo, 2050)
}
async loadInfo() {
const version = await this.state.client.call("Filecoin.Version", [])
this.setState(() => ({version: version}))
const id = await this.props.client.call("Filecoin.ID", [])
const peers = await this.state.client.call("Filecoin.NetPeers", [])
this.setState(() => ({peers: peers.length}))
const version = await this.props.client.call("Filecoin.Version", [])
const tipset = await this.state.client.call("Filecoin.ChainHead", [])
this.setState(() => ({tipset: tipset}))
const peers = await this.props.client.call("Filecoin.NetPeers", [])
const addrss = await this.state.client.call('Filecoin.WalletList', [])
const tipset = await this.props.client.call("Filecoin.ChainHead", [])
const addrs = await this.props.client.call('Filecoin.WalletList', [])
let defaultAddr = ""
if (addrss.length > 0) {
defaultAddr = await this.state.client.call('Filecoin.WalletDefaultAddress', [])
if (addrs.length > 0) {
defaultAddr = await this.props.client.call('Filecoin.WalletDefaultAddress', [])
}
const balances = await addrss.map(async addr => {
/* const balances = await addrss.map(async addr => {
let balance = 0
try {
balance = await this.state.client.call('Filecoin.WalletBalance', [addr])
balance = await this.props.client.call('Filecoin.WalletBalance', [addr])
} catch {
balance = -1
}
return [addr, balance]
}).reduce(awaitListReducer, Promise.resolve([]))
}).reduce(awaitListReducer, Promise.resolve([]))*/
this.setState(() => ({balances: balances, defaultAddr: defaultAddr}))
this.setState(() => ({
id: id,
version: version,
peers: peers.length,
tipset: tipset,
addrs: addrs,
defaultAddr: defaultAddr}))
}
async startMining() {
@ -109,28 +72,33 @@ class FullNode extends React.Component {
}
this.setState({mining: true})
await this.state.client.call("Filecoin.MinerStart", [addr])
await this.props.client.call("Filecoin.MinerStart", [addr])
}
async newScepAddr() {
const t = "secp256k1"
await this.state.client.call("Filecoin.WalletNew", [t])
await this.props.client.call("Filecoin.WalletNew", [t])
this.loadInfo()
}
async startStorageMiner() {
this.props.mountWindow((onClose) => <StorageNodeInit fullRepo={this.props.node.Repo} fullConn={this.props.conn} pondClient={this.props.pondClient} onClose={onClose} mountWindow={this.props.mountWindow}/>)
this.props.mountWindow((onClose) => <StorageNodeInit fullRepo={this.props.node.Repo} fullConn={this.props.client} pondClient={this.props.pondClient} onClose={onClose} mountWindow={this.props.mountWindow}/>)
}
async add1k(to) {
await this.props.give1k(to)
}
render() {
let runtime = <div></div>
if (this.state.state === stateConnected) {
if (this.state.id) {
let chainInfo = <div></div>
if (this.state.tipset !== undefined) {
chainInfo = (
<div>
Head: {
<BlockLinks cids={this.state.tipset.Cids} conn={this.state.client} mountWindow={this.props.mountWindow} />
<BlockLinks cids={this.state.tipset.Cids} conn={this.props.client} mountWindow={this.props.mountWindow} />
} H:{this.state.tipset.Height}
</div>
)
@ -143,17 +111,17 @@ class FullNode extends React.Component {
let storageMine = <a href="#" onClick={this.startStorageMiner}>[Spawn Storage Miner]</a>
let balances = this.state.balances.map(([addr, balance]) => {
let line = <span>{truncAddr(addr)}:&nbsp;{balance}&nbsp;(ActTyp)</span>
let addresses = this.state.addrs.map((addr) => {
let line = <Address client={this.props.client} add1k={this.add1k} addr={addr} mountWindow={this.props.mountWindow}/>
if (this.state.defaultAddr === addr) {
line = <b>{line}</b>
}
return <div>{line}</div>
return <div key={addr}>{line}</div>
})
runtime = (
<div>
<div>v{this.state.version.Version}, <abbr title={this.state.id}>{this.state.id.substr(-8)}</abbr>, {this.state.peers} peers</div>
<div>{this.props.node.ID} - v{this.state.version.Version}, <abbr title={this.state.id}>{this.state.id.substr(-8)}</abbr>, {this.state.peers} peers</div>
<div>Repo: LOTUS_PATH={this.props.node.Repo}</div>
{chainInfo}
<div>
@ -161,7 +129,7 @@ class FullNode extends React.Component {
</div>
<div>
<div>Balances: [New <a href="#" onClick={this.newScepAddr}>[Secp256k1]</a>]</div>
<div>{balances}</div>
<div>{addresses}</div>
</div>
</div>
@ -174,7 +142,6 @@ class FullNode extends React.Component {
initialPosition={{x: this.props.node.ID*30, y: this.props.node.ID * 30}} >
<div className="CristalScroll">
<div className="FullNode">
<div>{this.props.node.ID} - {this.state.state}</div>
{runtime}
</div>
</div>

View File

@ -4,6 +4,8 @@ import ConnMgr from "./ConnMgr";
import Consensus from "./Consensus";
import {Cristal} from "react-cristal";
import StorageNode from "./StorageNode";
import {Client} from "rpc-websockets";
import pushMessage from "./chain/send";
class NodeList extends React.Component {
constructor(props) {
@ -20,29 +22,40 @@ class NodeList extends React.Component {
this.spawnNode = this.spawnNode.bind(this)
this.connMgr = this.connMgr.bind(this)
this.consensus = this.consensus.bind(this)
this.transfer1kFrom1 = this.transfer1kFrom1.bind(this)
this.getNodes()
}
mountNode(node) {
if (!node.Storage) {
this.props.mountWindow((onClose) =>
<FullNode key={node.ID}
node={{...node}}
pondClient={this.props.client}
onConnect={(conn, id) => this.setState(prev => ({
nodes: {
...prev.nodes,
[node.ID]: {...node, conn: conn, peerid: id}
}
}))}
mountWindow={this.props.mountWindow}/>)
} else {
this.props.mountWindow((onClose) =>
<StorageNode node={{...node}}
pondClient={this.props.client}
mountWindow={this.props.mountWindow}/>)
}
async mountNode(node) {
const token = await this.props.client.call('Pond.TokenFor', [node.ID])
const client = new Client(`ws://127.0.0.1:${node.ApiPort}/rpc/v0?token=${token}`)
client.on('open', async () => {
const id = await client.call("Filecoin.ID", [])
this.setState(prev => ({
nodes: {
...prev.nodes,
[node.ID]: {...node, conn: client, peerid: id}
}
}))
if (!node.Storage) {
this.props.mountWindow((onClose) =>
<FullNode key={node.ID}
node={{...node}}
client={client}
pondClient={this.props.client}
give1k={this.transfer1kFrom1}
mountWindow={this.props.mountWindow}/>)
} else {
this.props.mountWindow((onClose) =>
<StorageNode node={{...node}}
pondClient={this.props.client}
mountWindow={this.props.mountWindow}/>)
}
})
}
async getNodes() {
@ -55,10 +68,29 @@ class NodeList extends React.Component {
this.setState({existingLoaded: true, nodes: nodes})
}
async transfer1kFrom1(to) {
const addrss = await this.state.nodes[1].conn.call('Filecoin.WalletList', [])
const [bestaddr, bal] = await addrss.map(async addr => {
let balance = 0
try {
balance = await this.state.nodes[1].conn.call('Filecoin.WalletBalance', [addr])
} catch {
balance = -1
}
return [addr, balance]
}).reduce(async (c, n) => (await c)[1] > (await n)[1] ? await c : await n, Promise.resolve(['', -2]))
pushMessage(this.state.nodes[1].conn, bestaddr, {
To: to,
From: bestaddr,
Value: "1000",
})
}
async spawnNode() {
const node = await this.props.client.call('Pond.Spawn')
console.log(node)
this.mountNode(node)
await this.mountNode(node)
this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}}))
}

View File

@ -0,0 +1,30 @@
import React from 'react'
import {Cristal} from "react-cristal";
class State extends React.Component {
constructor(props) {
super(props)
this.state = {Balance: -2, State: {}}
}
async componentDidMount() {
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
const actstate = await this.props.client.call('Filecoin.ChainReadState', [this.props.actor, tipset])
this.setState(actstate)
}
render() {
const content = <div className="State">
<div>Balance: {this.state.Balance}</div>
<div>---</div>
<div>{Object.keys(this.state.State).map(k => <div key={k}>{k}: <span>{JSON.stringify(this.state.State[k])}</span></div>)}</div>
</div>
return <Cristal onClose={this.props.onClose} title={`Actor ${this.props.addr} @{this.props.ts.Height}`}>
{content}
</Cristal>
}
}
export default State

View File

@ -1,6 +1,7 @@
import React from 'react';
import {Cristal} from "react-cristal";
import { Client } from 'rpc-websockets'
import Address from "./Address";
const stateConnected = 'connected'
const stateConnecting = 'connecting'
@ -66,20 +67,10 @@ class StorageNode extends React.Component {
async loadInfo() {
const version = await this.state.client.call("Filecoin.Version", [])
this.setState(() => ({version: version}))
const peers = await this.state.client.call("Filecoin.NetPeers", [])
this.setState(() => ({peers: peers.length}))
/*const addrss = await this.state.client.call('Filecoin.WalletList', [])
let defaultAddr = ""
if (addrss.length > 0) {
defaultAddr = await this.state.client.call('Filecoin.WalletDefaultAddress', [])
}
this.setState(() => ({defaultAddr: defaultAddr}))
*/
const [actor] = await this.state.client.call("Filecoin.ActorAddresses", [])
this.setState({version: version, peers: peers.length, actor: actor})
await this.stagedList()
}
@ -100,7 +91,7 @@ class StorageNode extends React.Component {
render() {
let runtime = <div></div>
if (this.state.state === stateConnected) {
if (this.state.actor) {
const sealGarbage = <a href="#" onClick={this.sealGarbage}>[Seal Garbage]</a>
runtime = (
@ -110,6 +101,9 @@ class StorageNode extends React.Component {
<div>
{sealGarbage}
</div>
<div>
<Address client={this.props.fullConn} addr={this.state.actor} mountWindow={this.props.mountWindow}/>
</div>
<div>{this.state.statusCounts.map((c, i) => <span>{sealCodes[i]}: {c} | </span>)}</div>
<div>
{this.state.staged ? this.state.staged.map(s => (

View File

@ -0,0 +1,46 @@
import util from 'ipld-dag-cbor'
import { Buffer } from 'buffer'
import { Tagged } from 'borc'
async function pushMessage(client, from, inmsg) {
if(!inmsg.GasLimit) {
inmsg.GasLimit = "0"
}
if(!inmsg.GasPrice) {
inmsg.GasPrice = "0"
}
if(!inmsg.Params) {
inmsg.Params = "oA==" // 0b101_00000: empty cbor map: {}
}
if(!inmsg.Value) {
inmsg.Value = "0"
}
if(!inmsg.Method) {
inmsg.Method = 0
}
inmsg.Nonce = await client.call('Filecoin.MpoolGetNonce', [from])
/* const msg = [
inmsg.To,
inmsg.From,
inmsg.Nonce,
inmsg.Value,
inmsg.GasPrice,
inmsg.GasLimit,
inmsg.Method,
Buffer.from(inmsg.Params, 'base64'),
]*/
const signed = await client.call('Filecoin.WalletSignMessage', [from, inmsg])
console.log(signed)
await client.call('Filecoin.MpoolPush', [signed])
}
export default pushMessage

View File

@ -3,6 +3,7 @@ package impl
import (
"context"
"fmt"
"github.com/filecoin-project/go-lotus/lib/bufbstore"
"strconv"
"github.com/filecoin-project/go-lotus/api"
@ -20,7 +21,7 @@ import (
"github.com/filecoin-project/go-lotus/node/client"
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p-core/peer"
@ -191,6 +192,47 @@ func (a *FullNodeAPI) ChainCall(ctx context.Context, msg *types.Message, ts *typ
return &ret.MessageReceipt, err
}
func (a *FullNodeAPI) stateForTs(ts *types.TipSet) (*state.StateTree, error) {
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
st, err := a.Chain.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore())
cst := hamt.CSTFromBstore(buf)
return state.LoadStateTree(cst, st)
}
func (a *FullNodeAPI) ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
return state.GetActor(actor)
}
func (a *FullNodeAPI) ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*api.ActorState, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
var oif interface{}
if err := state.Store.Get(context.TODO(), act.Head, &oif); err != nil {
return nil, err
}
return &api.ActorState{
Balance: act.Balance,
State: oif,
}, nil
}
func (a *FullNodeAPI) MpoolPending(ctx context.Context, ts *types.TipSet) ([]*types.SignedMessage, error) {
// TODO: need to make sure we don't return messages that were already included in the referenced chain
// also need to accept ts == nil just fine, assume nil == chain.Head()
@ -260,6 +302,23 @@ func (a *FullNodeAPI) WalletSign(ctx context.Context, k address.Address, msg []b
return a.Wallet.Sign(k, msg)
}
func (a *FullNodeAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
msgbytes, err := msg.Serialize()
if err != nil {
return nil, err
}
sig, err := a.WalletSign(ctx, k, msgbytes)
if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w", err)
}
return &types.SignedMessage{
Message: *msg,
Signature: *sig,
}, nil
}
func (a *FullNodeAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
addrs, err := a.Wallet.ListAddrs()
if err != nil {

View File

@ -3,6 +3,7 @@ package impl
import (
"context"
"fmt"
"github.com/filecoin-project/go-lotus/chain/address"
"io/ioutil"
"math/rand"
@ -14,11 +15,16 @@ import (
type StorageMinerAPI struct {
CommonAPI
SectorBuilder *sectorbuilder.SectorBuilder
SectorBuilderConfig *sectorbuilder.SectorBuilderConfig
SectorBuilder *sectorbuilder.SectorBuilder
Miner *storage.Miner
}
func (sm *StorageMinerAPI) ActorAddresses(context.Context) ([]address.Address, error) {
return []address.Address{sm.SectorBuilderConfig.Miner}, nil
}
func (sm *StorageMinerAPI) StoreGarbageData(ctx context.Context) (uint64, error) {
maxSize := uint64(1016) // this is the most data we can fit in a 1024 byte sector
data := make([]byte, maxSize)