From 0a35e9659b7a4c7f5ed7402bdea6d6b7e3f328d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 1 Feb 2023 17:51:12 +0100 Subject: [PATCH 01/49] feat: shed: Add a tool to read data from sectors --- cmd/lotus-shed/sectors.go | 140 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/cmd/lotus-shed/sectors.go b/cmd/lotus-shed/sectors.go index 52d07f5b6..ee2f58c6b 100644 --- a/cmd/lotus-shed/sectors.go +++ b/cmd/lotus-shed/sectors.go @@ -18,6 +18,7 @@ import ( "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" "golang.org/x/xerrors" + "gopkg.in/cheggaaa/pb.v1" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" @@ -31,6 +32,11 @@ import ( "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/lib/parmap" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/fr32" + "github.com/filecoin-project/lotus/storage/sealer/fsutil" + "github.com/filecoin-project/lotus/storage/sealer/storiface" ) var sectorsCmd = &cli.Command{ @@ -42,6 +48,7 @@ var sectorsCmd = &cli.Command{ terminateSectorPenaltyEstimationCmd, visAllocatedSectorsCmd, dumpRLESectorCmd, + sectorReadCmd, }, } @@ -563,3 +570,136 @@ func rleToPng(rleBytes []byte) ([]byte, error) { return buf.Bytes(), nil } + +var sectorReadCmd = &cli.Command{ + Name: "read", + Usage: "read data from a sector into stdout", + ArgsUsage: "[sector num] [padded length] [padded offset]", + Description: `Read data from a sector. + +TIP: to get sectornum/len/offset for a piece you can use 'boostd pieces piece-info [cid]' + +fr32 padding is removed from the output.`, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 3 { + return xerrors.Errorf("must pass sectornum/len/offset") + } + + sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("parsing sector number: %w", err) + } + + length, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return xerrors.Errorf("parsing length: %w", err) + } + + offset, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64) + if err != nil { + return xerrors.Errorf("parsing offset: %w", err) + } + + ctx := lcli.ReqContext(cctx) + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + + maddr, err := api.ActorAddress(ctx) + if err != nil { + return xerrors.Errorf("getting miner actor address: %w", err) + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return xerrors.Errorf("getting miner id: %w", err) + } + + sid := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(sectorNum), + } + + si, err := api.SectorsStatus(ctx, sid.Number, false) + if err != nil { + return xerrors.Errorf("getting sector status: %w", err) + } + + sref := storiface.SectorRef{ + ID: sid, + ProofType: si.SealProof, + } + + defer closer() + + // Setup remote sector store + sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner) + if err != nil { + return xerrors.Errorf("could not get api info: %w", err) + } + + localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{}) + if err != nil { + return err + } + + remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10, + &paths.DefaultPartialFileHandler{}) + + readStarter, err := remote.Reader(ctx, sref, abi.PaddedPieceSize(offset), abi.PaddedPieceSize(length)) + if err != nil { + return xerrors.Errorf("getting reader: %w", err) + } + + rd, err := readStarter(0) + if err != nil { + return xerrors.Errorf("starting reader: %w", err) + } + + upr, err := fr32.NewUnpadReaderBuf(rd, abi.PaddedPieceSize(length), make([]byte, 1<<20)) + if err != nil { + return xerrors.Errorf("creating unpadded reader: %w", err) + } + + l := int64(abi.PaddedPieceSize(length).Unpadded()) + + bar := pb.New64(l) + br := bar.NewProxyReader(upr) + bar.ShowTimeLeft = true + bar.ShowPercent = true + bar.ShowSpeed = true + bar.Units = pb.U_BYTES + bar.Output = os.Stderr + bar.Start() + + _, err = io.CopyN(os.Stdout, br, l) + if err != nil { + return xerrors.Errorf("reading data: %w", err) + } + + return nil + }, +} + +type emptyLocalStorage struct { +} + +func (e *emptyLocalStorage) GetStorage() (storiface.StorageConfig, error) { + return storiface.StorageConfig{}, nil +} + +func (e *emptyLocalStorage) SetStorage(f func(*storiface.StorageConfig)) error { + panic("don't call") +} + +func (e *emptyLocalStorage) Stat(path string) (fsutil.FsStat, error) { + //TODO implement me + panic("don't call") +} + +func (e *emptyLocalStorage) DiskUsage(path string) (int64, error) { + panic("don't call") +} + +var _ paths.LocalStorage = &emptyLocalStorage{} From 81e056be1a3a8cdcab3b4bf7e8ab611c6d06cae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 7 Feb 2023 11:51:04 +0100 Subject: [PATCH 02/49] sp cli: make sectors list much faster --- cmd/lotus-miner/sectors.go | 39 ++++++++++++++++++++++++++--- documentation/en/cli-lotus-miner.md | 15 +++++------ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index da07901f7..a5c88d15c 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -9,6 +9,7 @@ import ( "sort" "strconv" "strings" + "sync" "time" "github.com/docker/go-units" @@ -33,11 +34,14 @@ import ( "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/lib/result" "github.com/filecoin-project/lotus/lib/strle" "github.com/filecoin-project/lotus/lib/tablewriter" sealing "github.com/filecoin-project/lotus/storage/pipeline" ) +const parallelSectorChecks = 300 + var sectorsCmd = &cli.Command{ Name: "sectors", Usage: "interact with sector store", @@ -306,9 +310,14 @@ var sectorsListCmd = &cli.Command{ Usage: "only show sectors which aren't in the 'Proving' state", Aliases: []string{"u"}, }, + &cli.Int64Flag{ + Name: "check-parallelism", + Usage: "number of parallel requests to make for checking sector states", + Value: parallelSectorChecks, + }, }, Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp) if err != nil { return err } @@ -407,16 +416,38 @@ var sectorsListCmd = &cli.Command{ fast := cctx.Bool("fast") + throttle := make(chan struct{}, cctx.Int64("check-parallelism")) + + resCh := make(chan result.Result[api.SectorInfo], len(list)) + var wg sync.WaitGroup for _, s := range list { - st, err := minerApi.SectorsStatus(ctx, s, !fast) - if err != nil { + throttle <- struct{}{} + wg.Add(1) + go func(s abi.SectorNumber) { + defer wg.Done() + defer func() { <-throttle }() + r := result.Wrap(minerApi.SectorsStatus(ctx, s, !fast)) + if r.Error != nil { + r.Value.SectorID = s + } + resCh <- r + }(s) + } + wg.Wait() + close(resCh) + + for rsn := range resCh { + if rsn.Error != nil { tw.Write(map[string]interface{}{ - "ID": s, + "ID": rsn.Value.SectorID, "Error": err, }) continue } + st := rsn.Value + s := st.SectorID + if !showRemoved && st.State == api.SectorState(sealing.Removed) { continue } diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 0e8e17773..a02315636 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -1717,13 +1717,14 @@ USAGE: lotus-miner sectors list [command options] [arguments...] OPTIONS: - --events, -e display number of events the sector has received (default: false) - --fast, -f don't show on-chain info for better performance (default: false) - --initial-pledge, -p display initial pledge (default: false) - --seal-time, -t display how long it took for the sector to be sealed (default: false) - --show-removed, -r show removed sectors (default: false) - --states value filter sectors by a comma-separated list of states - --unproven, -u only show sectors which aren't in the 'Proving' state (default: false) + --check-parallelism value number of parallel requests to make for checking sector states (default: 300) + --events, -e display number of events the sector has received (default: false) + --fast, -f don't show on-chain info for better performance (default: false) + --initial-pledge, -p display initial pledge (default: false) + --seal-time, -t display how long it took for the sector to be sealed (default: false) + --show-removed, -r show removed sectors (default: false) + --states value filter sectors by a comma-separated list of states + --unproven, -u only show sectors which aren't in the 'Proving' state (default: false) ``` From 17adcb77c3758d5493e73d12f71eb2418662d960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 9 Feb 2023 17:02:41 +0100 Subject: [PATCH 03/49] sp cli: correct order in parallel sectors list --- cmd/lotus-miner/sectors.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index a5c88d15c..2dad7fc0f 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -418,25 +418,24 @@ var sectorsListCmd = &cli.Command{ throttle := make(chan struct{}, cctx.Int64("check-parallelism")) - resCh := make(chan result.Result[api.SectorInfo], len(list)) + slist := make([]result.Result[api.SectorInfo], len(list)) var wg sync.WaitGroup - for _, s := range list { + for i, s := range list { throttle <- struct{}{} wg.Add(1) - go func(s abi.SectorNumber) { + go func(i int, s abi.SectorNumber) { defer wg.Done() defer func() { <-throttle }() r := result.Wrap(minerApi.SectorsStatus(ctx, s, !fast)) if r.Error != nil { r.Value.SectorID = s } - resCh <- r - }(s) + slist[i] = r + }(i, s) } wg.Wait() - close(resCh) - for rsn := range resCh { + for _, rsn := range slist { if rsn.Error != nil { tw.Write(map[string]interface{}{ "ID": rsn.Value.SectorID, From 3177f63a176f92a32f3d34b2f792ae37143a54e5 Mon Sep 17 00:00:00 2001 From: Mike Seiler Date: Wed, 8 Feb 2023 20:26:55 +0000 Subject: [PATCH 04/49] add test for transparent delegate proxy from openzeppelin --- .../contracts/TransparentUpgradeableProxy.hex | 1 + .../contracts/TransparentUpgradeableProxy.sol | 590 ++++++++++++++++++ itests/contracts/compile.sh | 6 +- itests/fevm_test.go | 12 + 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 itests/contracts/TransparentUpgradeableProxy.hex create mode 100644 itests/contracts/TransparentUpgradeableProxy.sol diff --git a/itests/contracts/TransparentUpgradeableProxy.hex b/itests/contracts/TransparentUpgradeableProxy.hex new file mode 100644 index 000000000..d3430beee --- /dev/null +++ b/itests/contracts/TransparentUpgradeableProxy.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061256c806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200003a5760003560e01c806320965255146200003f578063f8a8fd6d1462000061575b600080fd5b620000496200006d565b604051620000589190620002a6565b60405180910390f35b6200006b62000234565b005b6000806040516200007e9062000253565b604051809103906000f0801580156200009b573d6000803e3d6000fd5b509050600081604051620000af9062000261565b620000bb919062000308565b604051809103906000f080158015620000d8573d6000803e3d6000fd5b5090506000604051620000eb906200026f565b604051809103906000f08015801562000108573d6000803e3d6000fd5b5090508173ffffffffffffffffffffffffffffffffffffffff16633659cfe6826040518263ffffffff1660e01b815260040162000146919062000308565b600060405180830381600087803b1580156200016157600080fd5b505af115801562000176573d6000803e3d6000fd5b5050505060006040516200018a906200027d565b604051809103906000f080158015620001a7573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff16633ccc0522846040518263ffffffff1660e01b8152600401620001e5919062000308565b6020604051808303816000875af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b91906200035b565b94505050505090565b6200023e6200006d565b6000146200025157620002506200038d565b5b565b6103f780620003bd83390190565b61174480620007b483390190565b6103ef8062001ef883390190565b61025080620022e783390190565b6000819050919050565b620002a0816200028b565b82525050565b6000602082019050620002bd600083018462000295565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002f082620002c3565b9050919050565b6200030281620002e3565b82525050565b60006020820190506200031f6000830184620002f7565b92915050565b600080fd5b62000335816200028b565b81146200034157600080fd5b50565b60008151905062000355816200032a565b92915050565b60006020828403121562000374576200037362000325565b5b6000620003848482850162000344565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfe608060405234801561001057600080fd5b506103d7806100206000396000f3fe608060405234801561001057600080fd5b50600436106100455760003560e01c8063209652551461004e578063552410771461006c5780638129fc1c1461008857610046565b5b600180819055005b610056610092565b6040516100639190610218565b60405180910390f35b61008660048036038101906100819190610264565b61009c565b005b6100906100a6565b005b6000600154905090565b8060018190555050565b60008060019054906101000a900460ff161590508080156100d75750600160008054906101000a900460ff1660ff16105b8061010457506100e6306101dc565b1580156101035750600160008054906101000a900460ff1660ff16145b5b610143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161013a90610314565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610180576001600060016101000a81548160ff0219169083151502179055505b80156101d95760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516101d09190610386565b60405180910390a15b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b610212816101ff565b82525050565b600060208201905061022d6000830184610209565b92915050565b600080fd5b610241816101ff565b811461024c57600080fd5b50565b60008135905061025e81610238565b92915050565b60006020828403121561027a57610279610233565b5b60006102888482850161024f565b91505092915050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006102fe602e83610291565b9150610309826102a2565b604082019050919050565b6000602082019050818103600083015261032d816102f1565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061037061036b61036684610334565b61034b565b61033e565b9050919050565b61038081610355565b82525050565b600060208201905061039b6000830184610377565b9291505056fea2646970667358221220934a8ba055f2e0df7da7dde7999f38a4972809a218a2a064683da10ad547f1fd64736f6c63430008110033608060405260405162001744380380620017448339818101604052810190620000299190620005c7565b80604051806020016040528060008152506200004e828260006200006860201b60201c565b50506200006133620000ab60201b60201c565b50620008fd565b62000079836200010960201b60201c565b600082511180620000875750805b15620000a657620000a483836200016060201b620003361760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000dc6200019660201b60201c565b82604051620000ed9291906200060a565b60405180910390a16200010681620001fa60201b60201c565b50565b6200011a81620002ea60201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200018e83836040518060600160405280602781526020016200171d60279139620003c060201b60201c565b905092915050565b6000620001d17fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b6200045260201b620003631760201c565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036200026c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200026390620006be565b60405180910390fd5b80620002a67fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b6200045260201b620003631760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b62000300816200045c60201b6200036d1760201c565b62000342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003399062000756565b60405180910390fd5b806200037c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200045260201b620003631760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620003ec9190620007f1565b600060405180830381855af49150503d806000811462000429576040519150601f19603f3d011682016040523d82523d6000602084013e6200042e565b606091505b509150915062000447868383876200047f60201b60201c565b925050509392505050565b6000819050919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60608315620004ef576000835103620004e657620004a3856200045c60201b60201c565b620004e5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620004dc906200085a565b60405180910390fd5b5b82905062000502565b6200050183836200050a60201b60201c565b5b949350505050565b6000825111156200051e5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005549190620008d9565b60405180910390fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200058f8262000562565b9050919050565b620005a18162000582565b8114620005ad57600080fd5b50565b600081519050620005c18162000596565b92915050565b600060208284031215620005e057620005df6200055d565b5b6000620005f084828501620005b0565b91505092915050565b620006048162000582565b82525050565b6000604082019050620006216000830185620005f9565b620006306020830184620005f9565b9392505050565b600082825260208201905092915050565b7f455243313936373a206e65772061646d696e20697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000620006a660268362000637565b9150620006b38262000648565b604082019050919050565b60006020820190508181036000830152620006d98162000697565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006200073e602d8362000637565b91506200074b82620006e0565b604082019050919050565b6000602082019050818103600083015262000771816200072f565b9050919050565b600081519050919050565b600081905092915050565b60005b83811015620007ae57808201518184015260208101905062000791565b60008484015250505050565b6000620007c78262000778565b620007d3818562000783565b9350620007e58185602086016200078e565b80840191505092915050565b6000620007ff8284620007ba565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600062000842601d8362000637565b91506200084f826200080a565b602082019050919050565b60006020820190508181036000830152620008758162000833565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b6000620008a5826200087c565b620008b1818562000637565b9350620008c38185602086016200078e565b620008ce8162000887565b840191505092915050565b60006020820190508181036000830152620008f5818462000898565b905092915050565b610e10806200090d6000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100675780634f1ef286146100835780635c60da1b1461009f5780638f283970146100bd578063f851a440146100d95761005d565b3661005d5761005b6100f7565b005b6100656100f7565b005b610081600480360381019061007c9190610916565b610111565b005b61009d600480360381019061009891906109a8565b61017f565b005b6100a761021c565b6040516100b49190610a17565b60405180910390f35b6100d760048036038101906100d29190610916565b61027b565b005b6100e16102d7565b6040516100ee9190610a17565b60405180910390f35b6100ff610390565b61010f61010a61040f565b61041e565b565b610119610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036101735761015361049b565b61016e816040518060200160405280600081525060006104aa565b61017c565b61017b6100f7565b5b50565b610187610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361020e576102098383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060016104aa565b610217565b6102166100f7565b5b505050565b6000610226610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361026f5761026061049b565b61026861040f565b9050610278565b6102776100f7565b5b90565b610283610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036102cb576102bd61049b565b6102c6816104d6565b6102d4565b6102d36100f7565b5b50565b60006102e1610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361032a5761031b61049b565b610323610444565b9050610333565b6103326100f7565b5b90565b606061035b8383604051806060016040528060278152602001610db460279139610522565b905092915050565b6000819050919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b610398610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603610405576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103fc90610adb565b60405180910390fd5b61040d6105a8565b565b60006104196105aa565b905090565b3660008037600080366000845af43d6000803e806000811461043f573d6000f35b3d6000fd5b60006104727fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b610363565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600034146104a857600080fd5b565b6104b383610601565b6000825111806104c05750805b156104d1576104cf8383610336565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104ff610444565b8260405161050e929190610afb565b60405180910390a161051f81610650565b50565b60606000808573ffffffffffffffffffffffffffffffffffffffff168560405161054c9190610b95565b600060405180830381855af49150503d8060008114610587576040519150601f19603f3d011682016040523d82523d6000602084013e61058c565b606091505b509150915061059d86838387610730565b925050509392505050565b565b60006105d87f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610363565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61060a816107a5565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036106bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b690610c1e565b60405180910390fd5b806106ec7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b610363565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060831561079257600083510361078a5761074a8561036d565b610789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078090610c8a565b60405180910390fd5b5b82905061079d565b61079c838361085e565b5b949350505050565b6107ae8161036d565b6107ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e490610d1c565b60405180910390fd5b8061081a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610363565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000825111156108715781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a59190610d91565b60405180910390fd5b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006108e3826108b8565b9050919050565b6108f3816108d8565b81146108fe57600080fd5b50565b600081359050610910816108ea565b92915050565b60006020828403121561092c5761092b6108ae565b5b600061093a84828501610901565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261096857610967610943565b5b8235905067ffffffffffffffff81111561098557610984610948565b5b6020830191508360018202830111156109a1576109a061094d565b5b9250929050565b6000806000604084860312156109c1576109c06108ae565b5b60006109cf86828701610901565b935050602084013567ffffffffffffffff8111156109f0576109ef6108b3565b5b6109fc86828701610952565b92509250509250925092565b610a11816108d8565b82525050565b6000602082019050610a2c6000830184610a08565b92915050565b600082825260208201905092915050565b7f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60008201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760208201527f6574000000000000000000000000000000000000000000000000000000000000604082015250565b6000610ac5604283610a32565b9150610ad082610a43565b606082019050919050565b60006020820190508181036000830152610af481610ab8565b9050919050565b6000604082019050610b106000830185610a08565b610b1d6020830184610a08565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610b58578082015181840152602081019050610b3d565b60008484015250505050565b6000610b6f82610b24565b610b798185610b2f565b9350610b89818560208601610b3a565b80840191505092915050565b6000610ba18284610b64565b915081905092915050565b7f455243313936373a206e65772061646d696e20697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000610c08602683610a32565b9150610c1382610bac565b604082019050919050565b60006020820190508181036000830152610c3781610bfb565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610c74601d83610a32565b9150610c7f82610c3e565b602082019050919050565b60006020820190508181036000830152610ca381610c67565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b6000610d06602d83610a32565b9150610d1182610caa565b604082019050919050565b60006020820190508181036000830152610d3581610cf9565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b6000610d6382610d3c565b610d6d8185610a32565b9350610d7d818560208601610b3a565b610d8681610d47565b840191505092915050565b60006020820190508181036000830152610dab8184610d58565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e09e1af8aa595ace2cac727dfa78b8a1c201fdfb2f2b3364541017dec279304b64736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564608060405234801561001057600080fd5b506103cf806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063209652551461004657806355241077146100645780638129fc1c14610080575b600080fd5b61004e61008a565b60405161005b9190610210565b60405180910390f35b61007e6004803603810190610079919061025c565b610094565b005b61008861009e565b005b6000600154905090565b8060018190555050565b60008060019054906101000a900460ff161590508080156100cf5750600160008054906101000a900460ff1660ff16105b806100fc57506100de306101d4565b1580156100fb5750600160008054906101000a900460ff1660ff16145b5b61013b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101329061030c565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610178576001600060016101000a81548160ff0219169083151502179055505b80156101d15760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516101c8919061037e565b60405180910390a15b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b61020a816101f7565b82525050565b60006020820190506102256000830184610201565b92915050565b600080fd5b610239816101f7565b811461024457600080fd5b50565b60008135905061025681610230565b92915050565b6000602082840312156102725761027161022b565b5b600061028084828501610247565b91505092915050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006102f6602e83610289565b91506103018261029a565b604082019050919050565b60006020820190508181036000830152610325816102e9565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061036861036361035e8461032c565b610343565b610336565b9050919050565b6103788161034d565b82525050565b6000602082019050610393600083018461036f565b9291505056fea2646970667358221220f2a2169e9ff5b35281e8323276adc729174eda42cfb39d55a7943efc6c70485164736f6c63430008110033608060405234801561001057600080fd5b50610230806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80633ccc052214610030575b600080fd5b61004a60048036038101906100459190610140565b610060565b6040516100579190610186565b60405180910390f35b6000808290508073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d591906101cd565b915050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061010d826100e2565b9050919050565b61011d81610102565b811461012857600080fd5b50565b60008135905061013a81610114565b92915050565b600060208284031215610156576101556100dd565b5b60006101648482850161012b565b91505092915050565b6000819050919050565b6101808161016d565b82525050565b600060208201905061019b6000830184610177565b92915050565b6101aa8161016d565b81146101b557600080fd5b50565b6000815190506101c7816101a1565b92915050565b6000602082840312156101e3576101e26100dd565b5b60006101f1848285016101b8565b9150509291505056fea2646970667358221220b98dab0efb759c0eea90d951be7f01d309e1c04588076d429d10680bddf1351864736f6c63430008110033a264697066735822122024666606126645f287960fe9548cc80d17258ad514d74180c7af0e1ee954bd4364736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/TransparentUpgradeableProxy.sol b/itests/contracts/TransparentUpgradeableProxy.sol new file mode 100644 index 000000000..5bb3d0e5d --- /dev/null +++ b/itests/contracts/TransparentUpgradeableProxy.sol @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +abstract contract Initializable { + uint8 private _initialized; + + bool private _initializing; + + event Initialized(uint8 version); + + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || + (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + modifier reinitializer(uint8 version) { + require( + !_initializing && _initialized < version, + "Initializable: contract is already initialized" + ); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +abstract contract Proxy { + function _delegate(address implementation) internal virtual { + assembly { + calldatacopy(0, 0, calldatasize()) + + let result := delegatecall( + gas(), + implementation, + 0, + calldatasize(), + 0, + 0 + ) + + returndatacopy(0, 0, returndatasize()) + + switch result + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + function _implementation() internal view virtual returns (address); + + function _fallback() internal virtual { + _beforeFallback(); + _delegate(_implementation()); + } + + fallback() external payable virtual { + _fallback(); + } + + receive() external payable virtual { + _fallback(); + } + + function _beforeFallback() internal virtual {} +} + +interface IBeacon { + function implementation() external view returns (address); +} + +interface IERC1822Proxiable { + function proxiableUUID() external view returns (bytes32); +} + +library Address { + function isContract(address account) internal view returns (bool) { + return account.code.length > 0; + } + + function sendValue(address payable recipient, uint256 amount) internal { + require( + address(this).balance >= amount, + "Address: insufficient balance" + ); + + (bool success, ) = recipient.call{value: amount}(""); + require( + success, + "Address: unable to send value, recipient may have reverted" + ); + } + + function functionCall( + address target, + bytes memory data + ) internal returns (bytes memory) { + return + functionCallWithValue( + target, + data, + 0, + "Address: low-level call failed" + ); + } + + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return + functionCallWithValue( + target, + data, + value, + "Address: low-level call with value failed" + ); + } + + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require( + address(this).balance >= value, + "Address: insufficient balance for call" + ); + (bool success, bytes memory returndata) = target.call{value: value}( + data + ); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function functionStaticCall( + address target, + bytes memory data + ) internal view returns (bytes memory) { + return + functionStaticCall( + target, + data, + "Address: low-level static call failed" + ); + } + + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function functionDelegateCall( + address target, + bytes memory data + ) internal returns (bytes memory) { + return + functionDelegateCall( + target, + data, + "Address: low-level delegate call failed" + ); + } + + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert( + bytes memory returndata, + string memory errorMessage + ) private pure { + if (returndata.length > 0) { + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + function getAddressSlot( + bytes32 slot + ) internal pure returns (AddressSlot storage r) { + assembly { + r.slot := slot + } + } + + function getBooleanSlot( + bytes32 slot + ) internal pure returns (BooleanSlot storage r) { + assembly { + r.slot := slot + } + } + + function getBytes32Slot( + bytes32 slot + ) internal pure returns (Bytes32Slot storage r) { + assembly { + r.slot := slot + } + } + + function getUint256Slot( + bytes32 slot + ) internal pure returns (Uint256Slot storage r) { + assembly { + r.slot := slot + } + } +} + +abstract contract ERC1967Upgrade { + bytes32 private constant _ROLLBACK_SLOT = + 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + bytes32 internal constant _IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + event Upgraded(address indexed implementation); + + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + function _setImplementation(address newImplementation) private { + require( + Address.isContract(newImplementation), + "ERC1967: new implementation is not a contract" + ); + StorageSlot + .getAddressSlot(_IMPLEMENTATION_SLOT) + .value = newImplementation; + } + + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + function _upgradeToAndCall( + address newImplementation, + bytes memory data, + bool forceCall + ) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + function _upgradeToAndCallUUPS( + address newImplementation, + bytes memory data, + bool forceCall + ) internal { + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns ( + bytes32 slot + ) { + require( + slot == _IMPLEMENTATION_SLOT, + "ERC1967Upgrade: unsupported proxiableUUID" + ); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + event AdminChanged(address previousAdmin, address newAdmin); + + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + function _setAdmin(address newAdmin) private { + require( + newAdmin != address(0), + "ERC1967: new admin is the zero address" + ); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + bytes32 internal constant _BEACON_SLOT = + 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + event BeaconUpgraded(address indexed beacon); + + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + function _setBeacon(address newBeacon) private { + require( + Address.isContract(newBeacon), + "ERC1967: new beacon is not a contract" + ); + require( + Address.isContract(IBeacon(newBeacon).implementation()), + "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + function _upgradeBeaconToAndCall( + address newBeacon, + bytes memory data, + bool forceCall + ) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall( + IBeacon(newBeacon).implementation(), + data + ); + } + } +} + +contract ERC1967Proxy is Proxy, ERC1967Upgrade { + constructor(address _logic, bytes memory _data) payable { + _upgradeToAndCall(_logic, _data, false); + } + + function _implementation() + internal + view + virtual + override + returns (address impl) + { + return ERC1967Upgrade._getImplementation(); + } +} + +contract TransparentUpgradeableProxy is ERC1967Proxy { + constructor(address _logic) payable ERC1967Proxy(_logic, "") { + _changeAdmin(msg.sender); + } + + modifier ifAdmin() { + if (msg.sender == _getAdmin()) { + _; + } else { + _fallback(); + } + } + + function admin() external payable ifAdmin returns (address admin_) { + _requireZeroValue(); + admin_ = _getAdmin(); + } + + function implementation() + external + payable + ifAdmin + returns (address implementation_) + { + _requireZeroValue(); + implementation_ = _implementation(); + } + + function changeAdmin(address newAdmin) external payable virtual ifAdmin { + _requireZeroValue(); + _changeAdmin(newAdmin); + } + + function upgradeTo(address newImplementation) external payable ifAdmin { + _requireZeroValue(); + _upgradeToAndCall(newImplementation, bytes(""), false); + } + + function upgradeToAndCall( + address newImplementation, + bytes calldata data + ) external payable ifAdmin { + _upgradeToAndCall(newImplementation, data, true); + } + + function _admin() internal view virtual returns (address) { + return _getAdmin(); + } + + function _beforeFallback() internal virtual override { + require( + msg.sender != _getAdmin(), + "TransparentUpgradeableProxy: admin cannot fallback to proxy target" + ); + super._beforeFallback(); + } + + function _requireZeroValue() private { + require(msg.value == 0); + } +} + +contract TestHelper { + function getValue(address proxyAddress) public returns (uint256) { + Implementation2 proxyInstance2 = Implementation2(proxyAddress); + return proxyInstance2.getValue(); + } +} + +contract TransparentUpgradeableProxyTestRunner { + function test() public { + assert(0 == getValue()); + } + + function getValue() public returns (uint256) { + Implementation4 instance4 = new Implementation4(); + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(instance4) + ); + Implementation2 instance2 = new Implementation2(); + proxy.upgradeTo(address(instance2)); + //use helper because proxy admin can't call getValue() + TestHelper h = new TestHelper(); + return h.getValue(address(proxy)); + } +} diff --git a/itests/contracts/compile.sh b/itests/contracts/compile.sh index 029bff46c..31bff4b68 100644 --- a/itests/contracts/compile.sh +++ b/itests/contracts/compile.sh @@ -5,7 +5,7 @@ set -o pipefail # to compile all of the .sol files to their corresponding evm binary files stored as .hex # solc outputs to stdout a format that we just want to grab the last line of and then remove the trailing newline on that line -find . -name \*.sol -print0 | +find . -maxdepth 1 -name \*.sol -print0 | xargs -0 -I{} bash -euc -o pipefail 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)' @@ -17,3 +17,7 @@ for filename in Constructor TestApp ValueSender Create2Factory DeployValueTest; solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex done +for filename in TransparentUpgradeableProxy ; do + echo $filename + solc --bin $filename.sol | tail -n1| tr -d "\n" > $filename.hex +done diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 2b2a3a6d3..074f66f12 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -843,3 +843,15 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) { // The receive() function emits one log, that's how we know we hit it. require.Len(t, receipt.Logs, 1) } + +func TestFEVMProxyUpgradeable(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install transparently upgradeable proxy + proxyFilename := "contracts/TransparentUpgradeableProxy.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, proxyFilename) + + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "test()", []byte{}) + require.NoError(t, err) +} From 77fbc60cb820ddd845c02492ec6edb55ee74f1f8 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 10:06:59 -0800 Subject: [PATCH 05/49] fix: stmgr: copy the message before modifying it --- chain/stmgr/call.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index ea2758705..901fc2d12 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -31,6 +31,10 @@ var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at e // tipset's parent. In the presence of null blocks, the height at which the message is invoked may // be less than the specified tipset. func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { + // Copy the message as we modify it below. + msgCopy := *msg + msg = &msgCopy + if msg.GasLimit == 0 { msg.GasLimit = build.BlockGasLimit } From f427c2b566311798063362c437e9187af82ef857 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 10:33:59 -0800 Subject: [PATCH 06/49] fix: eth: correctly convert filecoin message <-> eth txn (#10257) 1. We do allow deploying with empty initcode. 2. Make sure that the encoded "code" is non-empty, if specified. Basically, this makes everything consistent (and it's how I specified it in the FIP). --- chain/types/ethtypes/eth_transactions.go | 71 ++++++++++-------------- node/impl/full/eth.go | 25 +++------ 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/chain/types/ethtypes/eth_transactions.go b/chain/types/ethtypes/eth_transactions.go index 7c065928e..000295cc0 100644 --- a/chain/types/ethtypes/eth_transactions.go +++ b/chain/types/ethtypes/eth_transactions.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/go-address" gocrypto "github.com/filecoin-project/go-crypto" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" builtintypes "github.com/filecoin-project/go-state-types/builtin" typescrypto "github.com/filecoin-project/go-state-types/crypto" @@ -97,24 +98,31 @@ func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) { func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) { var ( - to *EthAddress - params []byte - paramsReader = bytes.NewReader(msg.Params) - err error + to *EthAddress + params []byte + err error ) if msg.Version != 0 { return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version) } + if len(msg.Params) > 0 { + paramsReader := bytes.NewReader(msg.Params) + params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) + if err != nil { + return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err) + } + if paramsReader.Len() != 0 { + return EthTxArgs{}, xerrors.Errorf("extra data found in params") + } + if len(params) == 0 { + return EthTxArgs{}, xerrors.Errorf("non-empty params encode empty byte array") + } + } + if msg.To == builtintypes.EthereumAddressManagerActorAddr { - switch msg.Method { - case builtintypes.MethodsEAM.CreateExternal: - params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) - if err != nil { - return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err) - } - default: + if msg.Method != builtintypes.MethodsEAM.CreateExternal { return EthTxArgs{}, fmt.Errorf("unsupported EAM method") } } else if msg.Method == builtintypes.MethodsEVM.InvokeContract { @@ -123,23 +131,12 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) { return EthTxArgs{}, err } to = &addr - - if len(msg.Params) > 0 { - params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) - if err != nil { - return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err) - } - } } else { return EthTxArgs{}, xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)", msg.Method, builtintypes.MethodsEVM.InvokeContract) } - if paramsReader.Len() != 0 { - return EthTxArgs{}, xerrors.Errorf("extra data found in params") - } - return EthTxArgs{ ChainID: build.Eip155ChainId, Nonce: int(msg.Nonce), @@ -159,34 +156,26 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er var err error var params []byte - var to address.Address - method := builtintypes.MethodsEVM.InvokeContract - // nil indicates the EAM, only CreateExternal is allowed - if tx.To == nil { - to = builtintypes.EthereumAddressManagerActorAddr - method = builtintypes.MethodsEAM.CreateExternal - if len(tx.Input) == 0 { - return nil, xerrors.New("cannot call CreateExternal without params") - } - + if len(tx.Input) > 0 { buf := new(bytes.Buffer) if err = cbg.WriteByteArray(buf, tx.Input); err != nil { - return nil, xerrors.Errorf("failed to serialize Create params: %w", err) + return nil, xerrors.Errorf("failed to write input args: %w", err) } - params = buf.Bytes() + } + + var to address.Address + var method abi.MethodNum + // nil indicates the EAM, only CreateExternal is allowed + if tx.To == nil { + method = builtintypes.MethodsEAM.CreateExternal + to = builtintypes.EthereumAddressManagerActorAddr } else { + method = builtintypes.MethodsEVM.InvokeContract to, err = tx.To.ToFilecoinAddress() if err != nil { return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err) } - if len(tx.Input) > 0 { - buf := new(bytes.Buffer) - if err = cbg.WriteByteArray(buf, tx.Input); err != nil { - return nil, xerrors.Errorf("failed to write input args: %w", err) - } - params = buf.Bytes() - } } return &types.Message{ diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 9576dee40..eb7240d62 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -751,18 +751,20 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et } var params []byte + if len(tx.Data) > 0 { + initcode := abi.CborBytes(tx.Data) + params2, err := actors.SerializeParams(&initcode) + if err != nil { + return nil, fmt.Errorf("failed to serialize params: %w", err) + } + params = params2 + } + var to address.Address var method abi.MethodNum if tx.To == nil { // this is a contract creation to = builtintypes.EthereumAddressManagerActorAddr - - initcode := abi.CborBytes(tx.Data) - params2, err := actors.SerializeParams(&initcode) - if err != nil { - return nil, fmt.Errorf("failed to serialize Create params: %w", err) - } - params = params2 method = builtintypes.MethodsEAM.CreateExternal } else { addr, err := tx.To.ToFilecoinAddress() @@ -770,15 +772,6 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) } to = addr - - if len(tx.Data) > 0 { - var buf bytes.Buffer - if err := cbg.WriteByteArray(&buf, tx.Data); err != nil { - return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string") - } - params = buf.Bytes() - } - method = builtintypes.MethodsEVM.InvokeContract } From 2bbd1fbbb610645650bc439abb2984f8c38ded61 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 10:59:20 -0800 Subject: [PATCH 07/49] fix: stmgr: check message validity before invoking vm Otherwise we may, e.g., try to estimate gas on a message to an f4 address before the nv18 migration. I'm _not_ checking the "prior messages" here as this is just a sanity check. --- chain/stmgr/call.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index ea2758705..e6b742255 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -107,6 +107,14 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr } } + // This isn't strictly necessary, but the underlying VM will assume that the message is + // valid and may not return helpful debugging information. Checking here makes message + // validity issues easier to debug. + nv := sm.GetNetworkVersion(ctx, ts.Height()) + if err := msg.ValidForBlockInclusion(0, nv); err != nil { + return nil, xerrors.Errorf("message not valid for network version %d: %w", nv, err) + } + // Unless executing on a specific state cid, apply all the messages from the current tipset // first. Unfortunately, we can't just execute the tipset, because that will run cron. We // don't want to apply miner messages after cron runs in a given epoch. From a16c54051cb371ae90c9c15d7830b1059c7e0821 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 15:29:13 -0800 Subject: [PATCH 08/49] fix: eth: rename yParity to v in transaction return values (#10264) fixes https://github.com/filecoin-project/ref-fvm/issues/1662 --- build/openrpc/full.json.gz | Bin 33137 -> 33132 bytes build/openrpc/gateway.json.gz | Bin 8492 -> 8487 bytes chain/types/ethtypes/eth_transactions.go | 2 +- documentation/en/api-v1-unstable-methods.md | 6 +- itests/specs/eth_openrpc.json | 60 ++++++++++---------- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index f5d6f67476a6e66ceec559c37a3fc13063f38bb7..f309b4eda78eeb63f71f07b22b77cedfa74b1a33 100644 GIT binary patch delta 23285 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 diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index dac0e82fc693aa08128f98369c238af810fc9b41..4389ca2300369ab73deaf2704bd8feceebe6325f 100644 GIT binary patch delta 7842 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 ArvLx| delta 7850 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 IYjxBC0KK3&00000 diff --git a/chain/types/ethtypes/eth_transactions.go b/chain/types/ethtypes/eth_transactions.go index 000295cc0..6c13c5bf6 100644 --- a/chain/types/ethtypes/eth_transactions.go +++ b/chain/types/ethtypes/eth_transactions.go @@ -39,7 +39,7 @@ type EthTx struct { MaxFeePerGas EthBigInt `json:"maxFeePerGas"` MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"` AccessList []EthHash `json:"accessList"` - V EthBigInt `json:"yParity"` + V EthBigInt `json:"v"` R EthBigInt `json:"r"` S EthBigInt `json:"s"` } diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 11466ee1b..f4b39e4be 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -2643,7 +2643,7 @@ Response: "accessList": [ "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" ], - "yParity": "0x0", + "v": "0x0", "r": "0x0", "s": "0x0" } @@ -2682,7 +2682,7 @@ Response: "accessList": [ "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" ], - "yParity": "0x0", + "v": "0x0", "r": "0x0", "s": "0x0" } @@ -2720,7 +2720,7 @@ Response: "accessList": [ "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" ], - "yParity": "0x0", + "v": "0x0", "r": "0x0", "s": "0x0" } diff --git a/itests/specs/eth_openrpc.json b/itests/specs/eth_openrpc.json index ed13614e9..1947bbd32 100644 --- a/itests/specs/eth_openrpc.json +++ b/itests/specs/eth_openrpc.json @@ -178,7 +178,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -253,8 +253,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -285,7 +285,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -354,8 +354,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -649,7 +649,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -724,8 +724,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -756,7 +756,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -825,8 +825,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3009,7 +3009,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3084,8 +3084,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3116,7 +3116,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3185,8 +3185,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3359,7 +3359,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3434,8 +3434,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3466,7 +3466,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3535,8 +3535,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3726,7 +3726,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3801,8 +3801,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." @@ -3833,7 +3833,7 @@ "s", "type", "value", - "yParity" + "v" ], "properties": { "type": { @@ -3902,8 +3902,8 @@ "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "Chain ID that this transaction is valid on." }, - "yParity": { - "title": "yParity", + "v": { + "title": "v", "type": "string", "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." From 0d92c746bd627495fd42b97af2b0012ea9b55648 Mon Sep 17 00:00:00 2001 From: ychiao Date: Mon, 13 Feb 2023 20:02:37 -0500 Subject: [PATCH 09/49] Eth JSON-RPC: populate reward in eth_feeHistory (#10245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Magiera Co-authored-by: Raúl Kripalani --- chain/types/ethtypes/eth_transactions.go | 8 ++ itests/eth_fee_history_test.go | 19 ++++- node/impl/full/eth.go | 101 ++++++++++++++++++++--- node/impl/full/eth_test.go | 64 ++++++++++++++ 4 files changed, 178 insertions(+), 14 deletions(-) diff --git a/chain/types/ethtypes/eth_transactions.go b/chain/types/ethtypes/eth_transactions.go index 6c13c5bf6..7afde4bd2 100644 --- a/chain/types/ethtypes/eth_transactions.go +++ b/chain/types/ethtypes/eth_transactions.go @@ -44,6 +44,14 @@ type EthTx struct { S EthBigInt `json:"s"` } +func (tx *EthTx) Reward(blkBaseFee big.Int) EthBigInt { + availablePriorityFee := big.Sub(big.Int(tx.MaxFeePerGas), blkBaseFee) + if big.Cmp(big.Int(tx.MaxPriorityFeePerGas), availablePriorityFee) <= 0 { + return tx.MaxPriorityFeePerGas + } + return EthBigInt(availablePriorityFee) +} + type EthTxArgs struct { ChainID int `json:"chainId"` Nonce int `json:"nonce"` diff --git a/itests/eth_fee_history_test.go b/itests/eth_fee_history_test.go index 9b256c527..33b4c8ae3 100644 --- a/itests/eth_fee_history_test.go +++ b/itests/eth_fee_history_test.go @@ -37,6 +37,7 @@ func TestEthFeeHistory(t *testing.T) { require.Equal(6, len(history.BaseFeePerGas)) require.Equal(5, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( json.Marshal([]interface{}{"5", "0x10"}), @@ -45,6 +46,7 @@ func TestEthFeeHistory(t *testing.T) { require.Equal(6, len(history.BaseFeePerGas)) require.Equal(5, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( json.Marshal([]interface{}{"0x10", "0x12"}), @@ -53,6 +55,7 @@ func TestEthFeeHistory(t *testing.T) { require.Equal(17, len(history.BaseFeePerGas)) require.Equal(16, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock) + require.Nil(history.Reward) history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( json.Marshal([]interface{}{5, "0x10"}), @@ -61,6 +64,7 @@ func TestEthFeeHistory(t *testing.T) { require.Equal(6, len(history.BaseFeePerGas)) require.Equal(5, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( json.Marshal([]interface{}{5, "10"}), @@ -69,19 +73,28 @@ func TestEthFeeHistory(t *testing.T) { require.Equal(6, len(history.BaseFeePerGas)) require.Equal(5, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) + require.Nil(history.Reward) history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( - json.Marshal([]interface{}{5, "10", &[]float64{0.25, 0.50, 0.75}}), + json.Marshal([]interface{}{5, "10", &[]float64{25, 50, 75}}), ).Assert(require.NoError)) require.NoError(err) require.Equal(6, len(history.BaseFeePerGas)) require.Equal(5, len(history.GasUsedRatio)) require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) require.NotNil(history.Reward) - require.Equal(0, len(*history.Reward)) + require.Equal(5, len(*history.Reward)) + for _, arr := range *history.Reward { + require.Equal(3, len(arr)) + } history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( - json.Marshal([]interface{}{1025, "10", &[]float64{0.25, 0.50, 0.75}}), + json.Marshal([]interface{}{1025, "10", &[]float64{25, 50, 75}}), ).Assert(require.NoError)) require.Error(err) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10", &[]float64{}}), + ).Assert(require.NoError)) + require.NoError(err) } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index eb7240d62..69571ca1f 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "sort" "strconv" "sync" "time" @@ -601,6 +602,18 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth if params.BlkCount > 1024 { return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024") } + rewardPercentiles := make([]float64, 0) + if params.RewardPercentiles != nil { + rewardPercentiles = append(rewardPercentiles, *params.RewardPercentiles...) + } + for i, rp := range rewardPercentiles { + if rp < 0 || rp > 100 { + return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be between 0 and 100", rp) + } + if i > 0 && rp < rewardPercentiles[i-1] { + return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be larger than %f", rp, rewardPercentiles[i-1]) + } + } ts, err := a.parseBlkParam(ctx, params.NewestBlkNum) if err != nil { @@ -619,18 +632,40 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth // we can do is duplicate the last value. baseFeeArray := []ethtypes.EthBigInt{ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)} gasUsedRatioArray := []float64{} + rewardsArray := make([][]ethtypes.EthBigInt, 0) for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) { // Unfortunately we need to rebuild the full message view so we can // totalize gas used in the tipset. - block, err := newEthBlockFromFilecoinTipSet(ctx, ts, false, a.Chain, a.StateAPI) + msgs, err := a.Chain.MessagesForTipset(ctx, ts) if err != nil { - return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err) + return ethtypes.EthFeeHistory{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) } - // both arrays should be reversed at the end + txGasRewards := gasRewardSorter{} + for txIdx, msg := range msgs { + msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false) + if err != nil || msgLookup == nil { + return ethtypes.EthFeeHistory{}, nil + } + + tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, a.Chain, a.StateAPI) + if err != nil { + return ethtypes.EthFeeHistory{}, nil + } + + txGasRewards = append(txGasRewards, gasRewardTuple{ + reward: tx.Reward(ts.Blocks()[0].ParentBaseFee), + gas: uint64(msgLookup.Receipt.GasUsed), + }) + } + + rewards, totalGasUsed := calculateRewardsAndGasUsed(rewardPercentiles, txGasRewards) + + // arrays should be reversed at the end baseFeeArray = append(baseFeeArray, ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)) - gasUsedRatioArray = append(gasUsedRatioArray, float64(block.GasUsed)/float64(build.BlockGasLimit)) + gasUsedRatioArray = append(gasUsedRatioArray, float64(totalGasUsed)/float64(build.BlockGasLimit)) + rewardsArray = append(rewardsArray, rewards) parentTsKey := ts.Parents() ts, err = a.Chain.LoadTipSet(ctx, parentTsKey) @@ -646,6 +681,9 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth for i, j := 0, len(gasUsedRatioArray)-1; i < j; i, j = i+1, j-1 { gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i] } + for i, j := 0, len(rewardsArray)-1; i < j; i, j = i+1, j-1 { + rewardsArray[i], rewardsArray[j] = rewardsArray[j], rewardsArray[i] + } ret := ethtypes.EthFeeHistory{ OldestBlock: ethtypes.EthUint64(oldestBlkHeight), @@ -653,13 +691,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth GasUsedRatio: gasUsedRatioArray, } if params.RewardPercentiles != nil { - // TODO: Populate reward percentiles - // https://github.com/filecoin-project/lotus/issues/10236 - // We need to calculate the requested percentiles of effective gas premium - // based on the newest block (I presume it's the newest, we need to dig in - // as it's underspecified). Effective means we're clamped at the gas_fee_cap - base_fee. - reward := make([][]ethtypes.EthBigInt, 0) - ret.Reward = &reward + ret.Reward = &rewardsArray } return ret, nil } @@ -2128,3 +2160,50 @@ func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) { } return keys, nil } + +func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) { + var totalGasUsed uint64 + for _, tx := range txGasRewards { + totalGasUsed += tx.gas + } + + rewards := make([]ethtypes.EthBigInt, len(rewardPercentiles)) + for i := range rewards { + rewards[i] = ethtypes.EthBigIntZero + } + + if len(txGasRewards) == 0 { + return rewards, totalGasUsed + } + + sort.Stable(txGasRewards) + + var idx int + var sum uint64 + for i, percentile := range rewardPercentiles { + threshold := uint64(float64(totalGasUsed) * percentile / 100) + for sum < threshold && idx < len(txGasRewards)-1 { + sum += txGasRewards[idx].gas + idx++ + } + rewards[i] = txGasRewards[idx].reward + } + + return rewards, totalGasUsed +} + +type gasRewardTuple struct { + gas uint64 + reward ethtypes.EthBigInt +} + +// sorted in ascending order +type gasRewardSorter []gasRewardTuple + +func (g gasRewardSorter) Len() int { return len(g) } +func (g gasRewardSorter) Swap(i, j int) { + g[i], g[j] = g[j], g[i] +} +func (g gasRewardSorter) Less(i, j int) bool { + return g[i].reward.Int.Cmp(g[j].reward.Int) == -1 +} diff --git a/node/impl/full/eth_test.go b/node/impl/full/eth_test.go index 027becf34..67a8b0500 100644 --- a/node/impl/full/eth_test.go +++ b/node/impl/full/eth_test.go @@ -6,6 +6,8 @@ import ( "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" ) @@ -100,3 +102,65 @@ func TestEthLogFromEvent(t *testing.T) { require.Len(t, topics, 1) require.Equal(t, topics[0], ethtypes.EthHash{}) } + +func TestReward(t *testing.T) { + baseFee := big.NewInt(100) + testcases := []struct { + maxFeePerGas, maxPriorityFeePerGas big.Int + answer big.Int + }{ + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(200)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(300), answer: big.NewInt(300)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(500), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(600), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(1000), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(50), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(-50)}, + } + for _, tc := range testcases { + tx := ethtypes.EthTx{ + MaxFeePerGas: ethtypes.EthBigInt(tc.maxFeePerGas), + MaxPriorityFeePerGas: ethtypes.EthBigInt(tc.maxPriorityFeePerGas), + } + reward := tx.Reward(baseFee) + require.Equal(t, 0, reward.Int.Cmp(tc.answer.Int), reward, tc.answer) + } +} + +func TestRewardPercentiles(t *testing.T) { + testcases := []struct { + percentiles []float64 + txGasRewards gasRewardSorter + answer []int64 + }{ + { + percentiles: []float64{25, 50, 75}, + txGasRewards: []gasRewardTuple{}, + answer: []int64{0, 0, 0}, + }, + { + percentiles: []float64{25, 50, 75, 100}, + txGasRewards: []gasRewardTuple{ + {gas: uint64(0), reward: ethtypes.EthBigInt(big.NewInt(300))}, + {gas: uint64(100), reward: ethtypes.EthBigInt(big.NewInt(200))}, + {gas: uint64(350), reward: ethtypes.EthBigInt(big.NewInt(100))}, + {gas: uint64(500), reward: ethtypes.EthBigInt(big.NewInt(600))}, + {gas: uint64(300), reward: ethtypes.EthBigInt(big.NewInt(700))}, + }, + answer: []int64{200, 700, 700, 700}, + }, + } + for _, tc := range testcases { + rewards, totalGasUsed := calculateRewardsAndGasUsed(tc.percentiles, tc.txGasRewards) + gasUsed := uint64(0) + for _, tx := range tc.txGasRewards { + gasUsed += tx.gas + } + ans := []ethtypes.EthBigInt{} + for _, bi := range tc.answer { + ans = append(ans, ethtypes.EthBigInt(big.NewInt(bi))) + } + require.Equal(t, totalGasUsed, gasUsed) + require.Equal(t, len(ans), len(tc.percentiles)) + require.Equal(t, ans, rewards) + } +} From 9f2f9154d2fa77303f91d4444d0c61fdf3ccefd1 Mon Sep 17 00:00:00 2001 From: snissn Date: Mon, 13 Feb 2023 19:29:11 -0700 Subject: [PATCH 10/49] itest for block.difficulty (#10263) --- itests/contracts/GetDifficulty.hex | 1 + itests/contracts/GetDifficulty.sol | 9 +++++++++ itests/fevm_test.go | 13 +++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 itests/contracts/GetDifficulty.hex create mode 100644 itests/contracts/GetDifficulty.sol diff --git a/itests/contracts/GetDifficulty.hex b/itests/contracts/GetDifficulty.hex new file mode 100644 index 000000000..6d584b233 --- /dev/null +++ b/itests/contracts/GetDifficulty.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060b58061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063b6baffe314602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea2646970667358221220c113f1abaabaed6a0324d363896b0d15a8bca7b9a540948a5be5b636a12a534f64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/GetDifficulty.sol b/itests/contracts/GetDifficulty.sol new file mode 100644 index 000000000..155e7cfd1 --- /dev/null +++ b/itests/contracts/GetDifficulty.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract GetDifficulty { + function getDifficulty () public view returns (uint256) { + return block.difficulty; + } +} + diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 074f66f12..3018bf63d 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -855,3 +855,16 @@ func TestFEVMProxyUpgradeable(t *testing.T) { _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "test()", []byte{}) require.NoError(t, err) } + +func TestFEVMGetBlockDifficulty(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/GetDifficulty.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDifficulty()", []byte{}) + require.NoError(t, err) + require.Equal(t, len(ret), 32) +} From 2ed92c222d79557702e15e0bde96b9a03e7beddb Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 18:42:29 -0800 Subject: [PATCH 11/49] chore: ffi: update the FFI This: - Improves error handling when the FFI is passed invalid messages. - Updates the FVM. --- extern/filecoin-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 4c503e5e2..7efaa7b47 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 4c503e5e2291b5d541f89d982d975e7994536a54 +Subproject commit 7efaa7b47fe9d4bdb4ba0b2a0fafa4e573864ee5 From abeb4fadc4dd34cda4d781d1831bbf4860005c63 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 13 Feb 2023 18:42:44 -0800 Subject: [PATCH 12/49] fix: itest: EthFeeHistory flake (#10265) --- itests/eth_fee_history_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/eth_fee_history_test.go b/itests/eth_fee_history_test.go index 33b4c8ae3..72302f298 100644 --- a/itests/eth_fee_history_test.go +++ b/itests/eth_fee_history_test.go @@ -28,7 +28,7 @@ func TestEthFeeHistory(t *testing.T) { defer cancel() // Wait for the network to create 20 blocks - <-time.After(20 * blockTime) + client.WaitTillChain(ctx, kit.HeightAtLeast(20)) history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( json.Marshal([]interface{}{5, "0x10"}), From 11ac325d1a1763eea9f63cfa64f59c0962827502 Mon Sep 17 00:00:00 2001 From: raulk Date: Tue, 14 Feb 2023 14:06:33 +0000 Subject: [PATCH 13/49] Revert "fix: stmgr: check message validity before invoking vm" (#10270) This reverts commit 2bbd1fbbb610645650bc439abb2984f8c38ded61. --- chain/stmgr/call.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index e6b742255..ea2758705 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -107,14 +107,6 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr } } - // This isn't strictly necessary, but the underlying VM will assume that the message is - // valid and may not return helpful debugging information. Checking here makes message - // validity issues easier to debug. - nv := sm.GetNetworkVersion(ctx, ts.Height()) - if err := msg.ValidForBlockInclusion(0, nv); err != nil { - return nil, xerrors.Errorf("message not valid for network version %d: %w", nv, err) - } - // Unless executing on a specific state cid, apply all the messages from the current tipset // first. Unfortunately, we can't just execute the tipset, because that will run cron. We // don't want to apply miner messages after cron runs in a given epoch. From 7150243cda9509b69b42844f3f3ab8bc93259281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 14 Feb 2023 17:15:42 +0100 Subject: [PATCH 14/49] feat: ethrpc: Support newPendingTransactions in eth_subscribe (#10269) --- itests/eth_filter_test.go | 107 ++++++++++++++++++++++++++++++++++++++ node/impl/full/eth.go | 23 +++++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go index 9540c5ebe..1104bec13 100644 --- a/itests/eth_filter_test.go +++ b/itests/eth_filter_test.go @@ -136,6 +136,113 @@ func TestEthNewPendingTransactionFilter(t *testing.T) { } } +func TestEthNewPendingTransactionSub(t *testing.T) { + require := require.New(t) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + kit.QuietAllLogsExcept("events", "messagepool") + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(err) + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(err) + + // install filter + subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "newPendingTransactions"})).Assert(require.NoError)) + require.NoError(err) + + var subResponses []ethtypes.EthSubscriptionResponse + err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error { + subResponses = append(subResponses, *resp) + return nil + }) + require.NoError(err) + + const iterations = 100 + + // we'll send half our balance (saving the other half for gas), + // in `iterations` increments. + toSend := big.Div(bal, big.NewInt(2)) + each := big.Div(toSend, big.NewInt(iterations)) + + waitAllCh := make(chan struct{}) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(err) + <-headChangeCh // skip hccurrent + + defer func() { + close(waitAllCh) + }() + + count := 0 + for { + select { + case <-ctx.Done(): + return + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply { + msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key()) + require.NoError(err) + count += len(msgs) + if count == iterations { + return + } + } + } + } + } + }() + + var sms []*types.SignedMessage + for i := 0; i < iterations; i++ { + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: each, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(err) + require.EqualValues(i, sm.Message.Nonce) + + sms = append(sms, sm) + } + + select { + case <-waitAllCh: + case <-ctx.Done(): + t.Errorf("timeout waiting to pack messages") + } + + expected := make(map[string]bool) + for _, sm := range sms { + hash, err := ethtypes.EthHashFromCid(sm.Cid()) + require.NoError(err) + expected[hash.String()] = false + } + + // expect to have seen iteration number of mpool messages + require.Equal(len(subResponses), len(expected), "expected number of filter results to equal number of messages") + + for _, txid := range subResponses { + expected[txid.Result.(string)] = true + } + + for _, found := range expected { + require.True(found) + } +} + func TestEthNewBlockFilter(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 69571ca1f..775550be2 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -1271,8 +1271,9 @@ func (e *EthEvent) uninstallFilter(ctx context.Context, f filter.Filter) error { } const ( - EthSubscribeEventTypeHeads = "newHeads" - EthSubscribeEventTypeLogs = "logs" + EthSubscribeEventTypeHeads = "newHeads" + EthSubscribeEventTypeLogs = "logs" + EthSubscribeEventTypePendingTransactions = "newPendingTransactions" ) func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { @@ -1334,6 +1335,15 @@ func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethty _, _ = e.EthUnsubscribe(ctx, sub.id) return ethtypes.EthSubscriptionID{}, err } + sub.addFilter(ctx, f) + case EthSubscribeEventTypePendingTransactions: + f, err := e.MemPoolFilterManager.Install(ctx) + if err != nil { + // clean up any previous filters added and stop the sub + _, _ = e.EthUnsubscribe(ctx, sub.id) + return ethtypes.EthSubscriptionID{}, err + } + sub.addFilter(ctx, f) default: return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType) @@ -1654,6 +1664,15 @@ func (e *ethSubscription) start(ctx context.Context) { } e.send(ctx, ev) + case *types.SignedMessage: // mpool txid + evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}, e.StateAPI) + if err != nil { + continue + } + + for _, r := range evs.Results { + e.send(ctx, r) + } default: log.Warnf("unexpected subscription value type: %T", vt) } From 30fe2c7c69b680a917eafc5842e44c03b02d8f08 Mon Sep 17 00:00:00 2001 From: jennijuju Date: Tue, 14 Feb 2023 18:48:23 -0500 Subject: [PATCH 15/49] - add calibration nv18 upgade epoch - bump version to v1.20.0-rc1 --- build/openrpc/full.json.gz | Bin 33132 -> 33131 bytes build/openrpc/gateway.json.gz | Bin 8487 -> 8485 bytes build/openrpc/miner.json.gz | Bin 16044 -> 16043 bytes build/openrpc/worker.json.gz | Bin 5225 -> 5224 bytes build/params_calibnet.go | 4 ++-- build/version.go | 2 +- documentation/en/cli-lotus-miner.md | 2 +- documentation/en/cli-lotus-worker.md | 2 +- documentation/en/cli-lotus.md | 2 +- 9 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index f309b4eda78eeb63f71f07b22b77cedfa74b1a33..dabb581c2497e0d343d2e6e60a77f16f33a092da 100644 GIT binary patch literal 33131 zcmV*3Kz6?$iwFP!00000|LnbcbKAI*2l`b|x_?ZPQarNc*s*V&x)nc?c*jY+wlmq? zIJ*Opkc2S>@DPw~O)B6079M;*1X7eO%b0U&#v*}60|dH%-Dos^cBqd?;5(gz&h}P+ zYq!(wU^1eegP$FaxraIjoioa33|yQafp_Ppoo?qA1q@T7YV@{xuLEbh^Q+sLB0ixm z>l}Rl*&%Q$s=mh_awsNSM-zz2p+}t?#%X{~MHAhQiH-u5 zGQ+_$~eHw7& zikiQ~zjWp524DESm)GRiHTmnWzdGFxn@y)Mn0F33Ma(IR3@|!HUpY-73OE)ees;EAiGM@al`KOq z`IZMW)a~%OFSw<{zmdZ`zkY>JzK4%~{1Tn}_Y4Qf4J*0G50C@7crt<>L%#~1bvx)@ zeZOPsNN&t`1=$xj)LEzkAL?AdO!caF(O-I`v0755B7INpGsEP(F8d+@lcUxt4-o7GYEg8AG9{x)#1yLE)!MRPl%)5@$)awWK^nA35?uKbGu zLR|y`G(rI)PCO&W_!bdxbb4HC0!E|mZ|4SB4^6oY521n_Pr|{eiwMUfjDj4kBkY1e z%sz$)X8;0*ywPh_W++yXqiI0b4G?3<1vsL%1x`7@42Z?7It;;|3XXIE1V_|G4tQ}l z!OjF=;$ktwMH|zZ$FU>czV@MWgWRYUv3gztNL&EHCsAqw*<`EJO{=Bf#kj%Iyg&R0 zItUK#m^;~>58z;z4+rc9P5r;={lER$oKF3}htm<7j|MvvD=D>0yKOP2nKpo@Zqm@*_@EG!82YJq-^v#WPVG$GD{s|KlbPhVB-gbYm)9H4u zuyccC>wjLnKMyD!bq+fJO}yU!Tpmsw@*flQpa1%ouo_Q1kg=;hls1 z?xMzLMG3q~{7pNs%#R=q&%)?>avEi@tU zEgI=2y-16KrwQNcjapWc#E|FVmSoW)OXxY1MU#d?&BS?%z~Uy8@T#?Lr$5JrxqWvA zZw(CKNd7Hl2!~V*4B}LIV`Dh1(7sWeVBOF-j(7=;D$iCkgfF7g3r;OpDhlC(3AP+bN6L^cRiHk?lCCKBxi~>4U-GEaB7$PnT0Oau_ zLWzU6z_$q^inR&!eMDIIno!~?AHfI*ETRcs$hMU`;STc&@aP?49B?TGUq+pAC}G$| zf%u4mb99fKnV6Px1ixIJ9Du8jr~Rx;p**0em{SynOfJ@%5 zA0T^=&=K_Gm*)YR;@MO`_$2r4I|s_iASY$s2<~={PLK08{BY>IXnY$C@Qy@j$Qyp*jvx- zrmhQGzbAT4)~*%`fOZ@`YN|hT8#NPzZ3TPc^`K6tGy2= zx6%XH)a{_EFZMTl|DpCLWqA{KgCblJ%9)~AKY}yK`(lTK<|ervkJO`?GRTSg4c>ja z0s*DmZpd%6A(@(dxgpNJU2H~v|Jga2V$M;}IoR&?dfiTPXZ*bf$E zw^HJFJ95<1HdMjJ_pcv6x*=xxUQ1R-oSA68C3hEfUrbukqheB24%^SXB8hb7gE_Jj zlTej<+S+BeSFK$>Ac7cfu3mKg;==+u zMO&TyF}sT~RM>uiper#!^g9~{9q-s2ogPO!AlF0&_b0;oEx_7XfR&!!WwI=OZ6eH` zfm^zs7uWiAtY0VCJeSAYzLAb*r{qckuVs~WM5s(_CxO==XfE9$^%Zy2Or=vq7jEPb zDd>-}T93KQgkz{^3>om?%mNwQpzv;M$~!Z>rUrK_;mkR??GM<52V`e(vo{{hNPygb z_D1()XZ-h@!N48RodN$h>HB@`-``JyTW4~MI?^<6A43;AF3MDD@{Q5>3B1&HocS}^ zJ#Oxc(Su$yM7Ghc&yr15dEYnJA+kTH);&UvG}brbS(%PepFkLfr@rTYk;7}ETm;Ql zO+w9Nx#DO^>gzdYBCOI5(^k!tc(C&}O6r}Vx1~La`epdHT!r;af<}v8HT8^BJG|*t zrFO`LBsLZRX)-3eZZ%+Ln)u2BM*v&5(Pp}hEWEYw z*23G>>ACHyG%t~)j?Tj^r{_X4CVDRI5Y{!#wO-g%rPeEKV+kFY=%1+$jQ9+7U=ThS z(I8fc1)A`h6rF_uR}&P|&p0N!0H-C8 zC91E^u1F@1uxmB)25aQPWmBM^%gUKW&)j1!#vk^Wj4al3A0Ye61k3x~j*9AP zGatheK{hE~>S?98^M>0hY6MIQheNqsh|K0H#QuWpM(2=EmQaIyVz{T!1%AJ9pW)R< z1l^+vB&J3npHwTsm|jEGC;KG&Ab4J+^!OxFbwd71n=U}NDB!K{&{Kf(WA6B&E}0Dt#RJpSMC zF+Y4K3%@(OCg6WxzkdDd_3QuD74?7l#f7H)jm|t*cLV(OU9tayAHI9p1+o(__`Acz z-|t@j_{(mNtax)IUbBAR4%%`GJ{Ac@YCZMVXdJJSY9tDC{S$iHZd(|V)?5uoM+*u< zMeA3Q$!y-&U_35voeIy8jXJyx6AGttUf5wXQ13@)z~BJ%h=L zy4pc$HokUs0%d1GvJ^GC??xO2dW4pfEeT3xVg?SeYW~Eh&ZGorHLN%m$gj0J@BYtX7V1mK=Yx;Ml1e z-NSh+LOdk%7!o{edj;Y<(XBeNJK|{7f;&kN5`bXfVJoYxthTcHY02unszaO~A!~eb zhpM}H`*ujFw@~6LV#Q)sjb&Xy8?m>*Qr9iZduABGBLL&1`vBcz7H^%}6Kc<9V^d7p z+{o&Oi^Y&=DZ!1Xhah?4g5+)0;nUqfF?EeKaEp2=o8yR-4s$wZG5pQlm z>dMA}B-PqkQ)@*%$DAz?Kw+aJ8aQY)^8|!OoJBUJg5AQh+yY;j4%By`ysyDVi#&$s z`q=@BovL6kVcRqY6uR;PKp{8wVsPz700;LOw!RAWUe? zICdC-LpoENaN_{_lMLwijSm0*O>N)(HiQiQCik>FMq?-zeBntzoXg&u*hUHkV)mPr2R5$h8eZk$qjD&+{BA@iT}}Oh|e&&VdBr4t}9*7 zKgt8f2{PCRubX)@=vtCZ|QoKt?YOOx<4RIqfX%?v@41c^DCX1U=`7PN(Pf zWkrxq4Vwjx%(Zo}Ea% z5kSe93Lq187Pz9s5HjQfN`UHgYvQbUOjjn&-ZYhFc1@mb@Ab+8rh*Qvvwl-u z!ijm98{qUi6U*-$&OHiUWkcp9~5SWY?>acmPwf6&**xN1i$s{$VAtl zoiVxBFN=tbq*vjDGZ)^Xx|!fMm)fG_0*SqZxYism64enS2}vEG5FJHQ+6v@N7RaU2 zxIIz)AcFI`ioZcwAgo;CC-*{ZG!%ZSa+&B;Z!geDddWn)7ihH5a8$M0u@xi!7R09{ z8%FX!Vlj*HP9$HKxnrpVJ^4b#xpFE5%bamEZPy7OjoqVoxsTs{P-NvYM;>xG4LS#E ztNi!=_U|7doBXbR?eyiZPFM5%2?aMEIu9rv>5%mwD)sl77`vl)7x~m@+Wb9uQ&SEo zHk;kVo9wD&V}VxX%hb!+SpM@#{=1(t+0Ag0 z)cAV3X3<$A)l_ci?3tn^RLD+Q=&}@??=f-3a%!kV!s;gBkFS!4EBYnAlUpVX@CoE#0&fw3z(E0rm`L5yO`WQUd1c@QB?$O> z&*h~JX50ukUMYQF*-x`(mQqrB6r6)ey);Yt9t3%f*)GhJW>MR*5j*{E=MyI90T#67 z9W7r8Lqe&?Pvqa{C^($+=n?3`%e(oHR)x+A&TaHPzVw|S*Ac=}D*Q6dQqKOk}hn}#&0%4JwuTWu0chjEb$ z{4t7PJN}r6ITM7e8y+Kq0u36D-d!lKOg=nXJZ=y9J{Rk@5@fDLAn3ERwRg+TTIfX~ zH)T%Ah&C1w5rxHjR z=Ouac^5ot}4oB|sOx-P%FL4wgF{W2o((d(o+pp#SuX?=$`TzeBW}WXYE_6o6iqA7T z&bMPg;@6K~KP23xx7bbFd&iJNp`{OgcEXt8;=5H=U^cfp0aDwc{he;-0^Z4#L7_?g zt9=7BX|IR2gvvOq?D2SVh!W8j&CZ~&rw68_`qTf30*TGSwHkh-qX{Gg={=ECf;on2 zd#Rymeu0=ziJBV?NeEsBztoJ1&J-l3m3*%j>Ws zpicJC|F%_FC6)|2L5)ZmpnT|ob(6q`~%EhQ? zlsOq^nDE`5m*9o^F2)W>7F*H6zJJ|ej!uuo zs&%=`vH0$v%#cP^SLHI@Fe~Kkpz=`e8D>1`?`>*{D0lDtRZ$$NVLOBDBFmM*wP0URg7aYBU07CMAK`EMl`RB zP>5nAL?HQCOo2&US!N1d6ka!_PTV_^%JTP!#+@w!Aaz0kZ7iUT1+=k%HWttt85?P2 zG`BKrSfC9Hv<9Iy2(3YA!vbwspbZPOVS&#lEO5j8TyHAVew|^achi^gbZH7@zAp9J z%+sYwRrR4)TVcKEVRJKn}vUp|4Lq zI)~VOFVK~Eaz#1x#1qY$b?RED?m9blyPcC;M7T^e-8hIOwF*oWeP$^cxjd{-^Xd9_ ztlQ>!`ZTp{G4fIva$M<_N+FvDyFW|0w3=m|Ogg2Cn-TYOFHthk!^~kfIzxvqb*&d5vj-X3Vz zV`>K08|j#p+{LtZwnpKp`}j-dL2l}u(Ybr+y-x))2PsU>{5InkYUr6z`E z(9C0}D@>v_<0Iah+ACxPMee!hoE9%cpM+4g?FUo8k_kQZt!{Z#cbkr%~~eF8E7OONKG zTBoxu20qxE6gGxQ-q}-2~r!p67I2pe|+}y7llPFu#(VU&a;0Ez6C6A3)wjkZ^ z64uO`u2spv9mHJ5=p<}1PQefXhl=^k+q)B@c)V8U{QlJf z9??vXqo8eg^!kKHuPfNutxOvulLmQ+vE=|yOk-7`CvKr#;FIFq0Q@BQ7~ufDhQxh6 zqQMyP*D)X>fR08UCMt!pusJj?k|2rBIAF6OL;s%1sU1M)29vSHOcpa)%w#c>#Y`46 zSZ33FJC)6`wKSLNujBEP!A}h*&IP(BCyV`*QX5 z^8XIs9sTk3{QnN$U7q~k`Max+0Fhf9P$G9xZef7o&_jSBF7OtkQzUNK(D|9^h6p*M{e5>Za)*Oa{|y@S_8q6cyEE$V z^oGOU?(R-+u-!?grHcP*vU!u+t@)7*UFr9dp)2B7HX+Dn%DvN3cL)8>|XZuMBi1 zKbI&ckDP=^G&Qef^1KDBMNlwYCX!s;Rib-ReUi2%jFuf4Lr2;upwrGl9Zl2ia9X#< z7&28w{T=zL?t7hXM?uB#mn+>v;>TXyKwejSmf8*4%m!wv5nEkoXqkSEIgq1i;%SM8 zx~`){eB#IKqMj2El&7HTT+&+DJ~>HLx%|Tt1{}*}mV%CL0mjWifc;*-ogLxB064x%%BY!hW0^ixX zfOk=VPV#fc6c#9xxS*jfi7V9AC#hboT%F`b$jllzy!+R`*2fxHw6H6tS!pp7rAj>) zF)m$~k=h$VhTbD|jsgLXl;I>sY7E&|hTIFtG3^|D-|lY>B-?i|a0SY(sRJ|3m|g{t zR{(jPlVCHSm8x7{rUt`AYlVGJG}2Nh(!V$BEM>pojfj|Rk8rEHGWgg=3 zDXF|LFG0@KYbt5hm6ZveS8iu24y)ZMVG%Qb%8Jr}uj#biEjgbgJ|p6X(1WDm#Eoj3 zn3Kt*`Ni7-MzcF=bG7q3*|i7X9H@1Iw$2XpDsV%cZRZVi^;+SylyKTBIZvS1pa3<8 zbDfi?k${RRmqgl`@nm9V(Q`12s<;6&m-HNQx3i3 z{Byln6Q1oeJjFcuKp4$2oj9$ueuD0K0FM(cZ}AcD+ni;DlF-+_m;PVgDWP5POrBi{ zc}{#yv8conp6OZJj_6$0!%@#Cko>$R-iX8(TJ_FCJbw(G`)YET6jqXObsqgP1r>KL zvC>vOj??gX(Bti2M2q+_hg>iH)v@q4$-&zK2DE%MnW0Jj`j~^3)-sRDNfIACDj&v2 z8526xPLDZ`v;5?H#E-hszWcW&XYf*%bn{~Z zSsK+R^4jq*)H*}3q>mx$)q{8$9^A`k4R>p}Tf^NN?$&U(hPyS~t>JDBcWby?!`&M0 z)^LAx!+pOz#YSkJUd40ch|UOKK474jqGaO) zV2T)nW5mL{s~RK|uu%$4qZI6EjK>gU+r9D}CFN^qd5>fnO%q|JjJ>;W>L7<9d% zNGr&b@+d-Wo!6fgFOMQ#`sG<(J|KQX-KHVlqG~(w-3IAibbG7J_!4)?#&w&)j%OLy zZBuwWv;-TJr||fI_Xd8=)C=iwFlE9W$Wv0#nDC1p#sa!^AJU7mIvM0u#wPsv&^xkuwwD3*2GP14AV1aztLP1S5st&KiFU(^;2I z?R4#l9}h#jJSdEef}%o z2wWUmk^MasWAylO1BuU-yGBQhe$_kmWr{|3UG`hslC4%DZID9Rt;iIE_$RedaD?5% zd18-YiB0PYibm>7?^>H&p|`NX7S&gEw^p8_D>p0vFN z+;}{=&9lzH-C7^k`molAwLYx%VXY5qeOT+mS|3l-`snv6(_*Ax@e*-GIXbnXiIy@X zS`H;D>WK{?TEhUM1wcOk-XeL64g`BOn>ZK@YDVE-Ibz1W0QE0Jr1%7j#z<2;A+qC+FKWm`n5Oup$;C|U1> z3IMGk$D)Q-N=~Dh;c_&E)VV6sx7dRb0#mWGH*>Bwmfqzy8R1y(vH&yaoawOcQ$D8 z5+KGQpT#a*AwmM^@X)xa$(b{o&OFHRE&7nT{wI4K5E_k;qYIt~*onQ(1=kXZM{?4@ zW^B2sONPRn6K$<%p;2z*1?ACkdghf*$rUYu2bk$G7>a(@xy9(IdabjI<1w9m1xwB7 zN~ip~tLxKS3xB+MkCpIPn8n06`_F^-_Ngux_dzZWi^Z+cMnEX5qg+Jc9gYi<5k2}= zUrt#(Dsv5X8h#b+nB+g^LtT^>Jo*(wA@nl4r)h1rmY(M9GvDXhwB4sSl9|a6E z>1NkCLOBJ5ay*)Yy9pvf!lOGNfgylFfNv42mqB#VqDW*mw&{;I!$ZDTo;dL{x?5_A zmafhP*?gO=+=p7UQLoC~;+1Q52pMt#B{tiy&Gy?0{I=PC+lWcAs%_&`+uQP7m!Hwy zIU+75gIc}axaRF^jyVEAN0yI;ano(UckGAq;4|V z^HfX%np6(u^eQk2^vpMAxC~?fRn0|E*s}+XaC)*Ca2GB1!oW!z+w~L$%y#)<_siK( z#uhia-8iaTCQklllmx!Bbph|r<-*E{6HP!ixezi(tr^ObH1XP!CDFHXffDn?DRA*< zgaUz#)pbyk6EI_#jKLimGV0tQ&aR1kdnI3D1}H&*24G491nB7Cnt;~=Lw`ijWd}KA zExi;WuHKS`{T!MvsAq=A!E1SkRa9NnOk8cnCy=ZAtpEg0fH?{9a8EoPz9L=iWPzy?Rru_&w07*kIJ&>GU(j>ruIJ4M+~bM6Dh}` zezmOMl6w|EA>d+y}@`7{^n{(R+lBpkI6S=O~m038?w3uO*a;5yD)`17$63 zU19$c@juY~C3vBpEDmJLwO?T%CTZ3(35ztCI2=jilUu$n$yJRJHi z8s7#3yyH-Y?)YTR#&7O#?)`s{NdIo+{Iff~?N6rkhTjd{`x|(_!#cle1}ePQXE5rW z+(`7hK~+6|Cb7230j=9oIQAy(d^S%36n@8_ohfp$oMJ;vU@$)+4s|gZ%a6#=?oJ{G zAP!x)qV;?7XOrYN-FULEFjl!LeaC9|NA_DtY@WZEE+d)^??i4TFF-dZ0Q>=)@POs?2P|@GZ?r7x-;PaCVjt;{rme#aO+HNQD^b>%&kSCBo$1_K-P*h zepYeDgWZyF`h*^hWaSbtC8SXUsN~_v!VTeq28)qNuOSdgbfY>!QxPX=AR@i9!+FXn z42cU=`wU>dbxlq=7(whYfJadw^?*}=?vXR&sKu~Hi)Ad9u~=q}v5dt9=D46ZbY@-A z;F`jNy^>={Y5f)ol;r?|rcwqGX7MdhI<9>yPWU*8{2Dv$_%&jFR_xnIbv)_c5PdNL z7a^N5yttb{E-{85Uarhz0;&lMqgD3MTLtfe9W@fQN68hbNS}fQ|qr zjyIEGb(ny^h}sDk5B~zlr_QA2>8L8`FgMBGasIVBGKY)vCo7cHr!Ft|bdo$DS#4~kD-*OJK+C^KU6KDuJRUCM_BUg+HZRi;apg9-;-czZ$} z`=y|Ri%pjtPtbK47|n<)x9a33pDY5P!)ef(iL%ZfsHg5PTN{^25jKeLz_52?tj*mR zYpM)(dL<|OmDKux_yuApxJC6Zw8>F0R0lOSWpYidVne2=ALXIxd6veAGb!caR9+ZH zN1^baKn`GlfHMmMM7TExL0D--164u5r>#c5kMQ@j6FiXWdcLitIt`5>FU?NaILg*GP)!{rE7x_e%-rNOi5QMS@i?c|q ze4csvb13>@0t7`Hm7e#+B|*O=)j)o_HkJf2iN`Ybl02-$+{<**)Zk0;rG-T(J7k;% za1r#Lshn76ZmqRvt-VdP_68-X29(J9hWW$|;9Wy)5LSOIO%S%f5-pJEoT&zg__@=6 zFfbz?l~Y;kfq+h}191JhwJO1?giTcmZ%VRIe8L0;M*)HysWjKMl|qI=wmieGy=z=m$M#+qqv(53Whj zM!e)|^fX?O4SO3e?`9p2mu|C9m00aIB*=yYH4F(#R8NW1hmsjeY&T)pM2KjBQFkCC z7*e-lj1nGB5*3X@LKm4#@w~2TCX!MF3|3Y`|FzcjcH(?1LRLdqUly~PcyEG%KO*R= zIhsSm=9tq%GF9(+bLe?Oc!29+&u^G4gKpYK`w_`+2#+URL(`A?hlXjY#3hFuUFdsd zTd_1WVXc)fkb|(VL`Xa2lW?IOiic;H@5bW*jfKHxh@dkdSI+fIJT|TVo(4Bk&3JNU z3leJB4k1I~u?4}J$5NI}OS9t=IsQ%igzMt;WamncKs*)yRHe%;r|z=~I+lKQ1~4;m z*B`6or0i3-&XNoNDGYy3Lp~)-F(WlipjD{!Ov)yOQN7i?6ugc^ezWQYinbo}1wfz) zfp5`BH?}dJwFY>)CetRHOG&pt8ZAGPjsdjct(l|@O{sBoDeM&~O+1^=#K&_C9 zA>KNgKun|yxGWpQCrmIIhx8Zju_btEZ;vhA!Np+}R}&N<88J^N2Xn*$By-@<=~ONm z6*G?+m`YFP*7FRbNPYd4rSy^B0Gr?Tu}^`gS8+iOgzS6cZRK-%C%tLCPPg+J@jDva zBp+QOhtoinzeKW^+Ha-asQDxPXX=6Yl&!g5M2pBR+>UHUQu^a)aDx<|u@6x(e~JG= zorA&7;LZNt;O$^ny64bsY?R8rnfU#d@E4wVc#MZ0dQSuOS=C%=w9C0MhIGN8M7Obr zS4D)DmY%R78e6fKJJ~5ycX!O2soz^A;Fv}A7@Y+UYVqzWtI(}Nw+h`VbgR&< zJKVa%*8!Zp>6P7nAOOM91UYfAb|YMtB2fX!bdmFba;iSYi|;?a|Im*ml}ir!j4cFb zsTM17SrPgAAT8U&1^6t@o{s`Ci5c+d7(37dj(E)gB>-yNMxzVO+e@QcFyI!26{D~} zp@&_~z6vn3$jBn2wLnJ6shJP+TsaUa5}yToa6#vw*X?}y zBkb!*5JVqe-I&?wc0OWtx)KhZ&cSwnAgrO(qHnbPbyw=eSSpr{(iR0lViv>{!p``R z3$1mY;%Vzu`J`0?REBO7(@>0Nv74ufiTQQ#%^Zl|*Wg^jYfqV}- zs0A^fp=26NwxpcTwE9qTKHpgrIiF>=!m7@R_&dxeAW#IRh;SQFW&_HsG5kb~VQbo2 z%wsXn!(g64+4Wgc4SNXYH+jrJj;LCOYQ&gVU5*zKSo%`DBrA(BhiuRh|7ImNqrAmL zlx+=8h>;+7R123|nmP=5~S=%ri&`YKno6hwDNcwB2mRAkOgj8R$g+;kC> zSn%@z(*X1NJJ$^|{+3Jp50Y5$BOXtr@=QECqj&m|wnYx-?-9Cy98>XpYtZeS2Qz|> zDD_-=M>+?)z3879W`4Ov0b(3aq3VdJSu@1EjMUEpY?$t>X{v&pmP`kV=Xz?Q;tNKt zfZ@z1FiMS(`a;d1V^s92)gaXSUw4_vYH4v-lNB>$nsIop}8)|OPjwJxj z+p08Z%`>1?B|j@U9cFqqY(dVm#%ICIlAX!cA2P#PV=Zfy>_cBLX*H|WtX8u&)~xpW zaeMvv%JI&ARd%wa6O$R_Bs0rM*38wjC>2?gt*Y9|#*$np&n)!3Ie<)nCFwa7;=3!c z6YI)J9N{Sqq^?N{Nlj%^AF+Zc@#bJAR@dDG5fEv%-(%GSMi_Z612913Hy-ea(q7ByMaw9Lk%&4{)E8PSY<+Sb;#wzkz8R%=*WdyP%F-Ck9?vlcR)86`Pu z!HI2>+iWRsc8#QFX@1rqlbKb;Rux-SY*n#U#n$a@-QG)MrtPXMWS7VjQ?U_PQgscZ z7^Sy+B(s{Slj)rLDP6=8+iFFz_AUyv^d$~WE*%{fXMn)iOepSI|F-J zaRxROgb*L!TyzHfvicBgZDbWQxWF?NH_Q-c@wsn(*cEV^I~2=izVBgWH`F~3YqA}0 z553w$uMczR)n*Gg>+cTAa)B{Ce&@RHd_SPK4Fa}O)eXo*0@ zc6I8F7r8{yl?HH%>2{*Lvf~h1yP{vBL!twM;SwR8<_N0)3Jcf|&@HAj=FNc+CX^u; zymMV?wghpg*C_`a-XJB~N7VD^ov@dcL_Pr5vtDoDNS_eH<0wa@c#69EtvV_kz7tlr zpru&>Q#MW)kGKiD3DVE+CWudvI>)S5zF;L>c)AJ$Y(i(A z3x)__;sgjXS4l251pg2CQ-Yo>r z&rOuSguw1=T7S*s`D^OmJn)ne{+qIVUZ0I(76Ydc(_Fjk=g?NtRQ zypDZ|A#@9!io-eJ0VE7MVzj~OaVr=wYA-`u77B5qf}pAT&lIyg1z+A1z-|^eS>R-W zlLbzj2%PrIk{HLj|LUH6giW#;=SZ{zqe^#@RgC!|9-k5}!$k9i_F}qk!S^4-IY&#N zGTp7V!C5?7W$~n(*PcpDeA19uO210k7kP?WafT>)A z$`N=?R7=p?0#}KPXy`~Y2Ia;%7$Q}RQ-BDY1qjUPOl2xo=jvhQ6gbfHLN9E# z3mN|9V2C>MWUY&;t63y%k@SkZpzF+Seh)vXY|L2gJwkx(I*;kzlU!wQ3r>{_7-2TF zIcutEwhU{NTAS3`q}C?gK$~>0SC(j=;qejy&Gn<1+jZr)9Iad!s$6amR>UWl+kw_; zZ%vISYHC=3WC4-|NERS%B0$@)89;>->ajlCt@^Qj)R47kjk z^G^Bc4{<{~B|2;upTARvL&n-rfiCi7p}r&`Q(#6s>f8W#7RaQUA>>yt zF~J-|4-BCv><^=y8LEFdLuCvZ@B{3$ZB#r3xRW<7a;w8EgL;H2%~N~lgj&-~#+6n_ zYFV%BV{G@fd)q5Xeqjxf_6?D>8B+`MEzGwt-@^P&g!zNAME(qqKOp|@7Ge($J#?rL zTqDe1K&Q^022WoF^b)*CL;h;yUeI{O7S_Cz4*!6ODIyg1F^ICNGi71i zs#2IFHyz|J2L&8r0(=x;>b7(0mvInZK}=EeKfKXv-~A>ot;yAY;BZ9 zV<#uJZQHhO+qP}nwr$(aiFsn%>3rS)pzms5)qeIx)w|~!bF9r8PjKyFg6H)6suCIz zs|5|n4sk(JQde8-r5owiFIkmx;Zrj;)6Eh90ZX}0ep_8PELY$J-iuD21%rpWIug;{>}Vl50(E*kag#aGzxfnc%qBsl*7M3z=DvM|D_{Sy zV#T%T)*xp|AggEZMZ|hF1258MGj;ru4oHCRfEpuZeIdE`=cmQ2MgFo%YXlWMP^awU zC)7`({(BVN0_XIDAc+h>$<9gU?4t+Sx=4U?D4;pH%FLycV=V=M#1 zBXG&M6}N`Om;izu#RQ)CLCBof&19e0K%b8Xo{JS$&>%z80LRE`0t`>(2p zg6AgZ+At?H`fdK(K+k0`e`!Ek;r|NiLkF-S0KHH#9z*-LNTWL!ep3pPY6|w+jPaIv z+2C>|9Faif=)29ofCgS!RgVv%@3DIgPSV@)rmq`rzz#QGOkW}OH=^QbI-4&Ph=gT@ z!-12Wjq(xshGK{nOF-2a{{zx~MeK$@)BxR1M2>XG!W_gLrx{XakgftWjcg8toAQcQ z?{Ue|=OT%qmfPi=R{fvOra#X|iz<_tUO-oE0gdOk^DnvHWK(-ax5Nl^gV5 zNRVL>Cl7ZV4lI7$U$8_$$Su7Sh9NJe(WcpWiA$&2ad23so6&zi#o^!_^6Sj-fza!} z5@H@0M)8AA4wi>cL+tyD!jlKfGfkTJH{AuU^&`mkc;r7h#?!f48_~nv81wR!6SB5J z9)T|y#_si#@P3Uz+v$~;bbi>IHp-g{lI$-Es?Zd@kmo_IG2v3{jUX-+=LAa|CAI?r zfaX1I3cen$ijzG7H)x#NC7{2f5(@;^{L#Tsr^}(BRwa21k?L~sozB~=RRMVG-(8fzhm2c3y zr;8(lPcSaErq>OiG@`XGM1CEr6S`QZ`I>S+yV7V#DlfZsh3)KYI#n@uV#!t1-<0{> zg{#0gIDp)7Q>yJH<6?OEI$$PA3okTaqfimQzm;VN{~#sIo?6|Kyjk^-$HXkvct@7Q zfrPA$e?*vkD(aIi&Ybs@?R0imrPYo3 zy-z$D#Zw=VA>Z~TI=fjI(dvEhudEvLMJh1?h85RX&QPVK2m*xqhv5}G` z^VHI%by7y9Le6Sw0|)>bfEu74U@rsUmtB(hCajo>D9tQ8*ONu%dv?E-#nPH#q zQ1`}>*m^~?12cbg!8@{J%DSVvr zY*jKwtQoZTAa^px5bv?LZPs&C*OVOlQ%=DAQ=dsU6_a^}2g<|&Z z8S)l1)3($J@HTMn$3kQY8$^hgsf6_3qPf+e7Vu!g>J$OlitwF+Q|zD>t}BX5zU=I! z@H|zB2nc&Po%Wh02Uf=YmUy~{Gt4Ma_Wo;rc}U6Hclz$oHHu$we<`C_j|miL-@?Y( zgP>+hx4ct`9~GF&FA$XY(73+{Z{!k?&t(S_MhIonPVQV0fX2bxjJ_qjOy%vW;ir$Z zm2^2WiQ~Qs{v6I*PZ*G?)_YN#y{5c%nT*|^ICTlr6snq5uHnsj{1MkFC^BCOPs$Pa zG!k*_Nw8?1AR`X>$9$HPYZTBCdF858R3g#PW)G)rbNbVF68hU_rNPgpvBwEZ zlw|Db!rfQzt?)Xvn}2YHxcS44{X`rr(Zn!iDZmuESY%oS^j(}qUdz9j(-zgFwF0PQ zkxl!t;({Z!I%=$cL`f=DlP~J2Nu6)1>7l8)D}ofcCF6QxqH2^>MaBDQL)Zaz{{qIz zYVysK@UK9fT1t+PQDhOMqb;qEur|B(IRq8)3Tv&3A11LTtyx7$^HhpYYy7I9CbR`j zam)XGzyn|8g%W$d2O*N~)JdTyg{(X(A(=WU6qiGztj9mu`sGrgNHD&cxA&e>$G< zBs*08x&L4plf7lLBYWOIF8_o@0w}wD>lRr|2f#9+QDhR8f{(4Zy8yBPyhlJ~l!t~e z>%?Cip8ikz_ji%I-#Sb^tu%_lDZO>1k;|O5GfU#Hn`u{fb$jaVSWhk$jHf|nil%*Jx-ci?h!l~<3|w&;ho(rUiuLOae9o>-3pXyB z?uOgZ!7MUBJ8Ssu^T1Q!QY zIH8lxud$(*w6D0!VBhx6KfF2H-*uN3weSbjMMYSJm4qx^-IV`19S6CRcQ zt5uoe=SiKzC8jl|FO$Chmpp=Ej@ajFJVQ#>5QcpGuDJOWxh(pNTgBy|sdG=+R*@Q6 zTjbC^>j!_b>PqKDl!8Bp@p~qcY#jmBYPf>J3A!S>)DjuxpjQ5ay@P)O&h^j|EA;p< z?|uPkapfAf1o6^s6dj_(8=WVM7;3dh!lW1Px2A$H9Q&Z-g%}IvZ2;EMws8NY!_&8L zFn@xvwCBNjBLK?8%M9JZlnjc}kN%n?&DlhZcVO0iz;%qR%NTGbMEsY$o&}zDjGr%4 zdV6qZv;H5McVE1ZmzSiy)r_se*ex@kbR1W&6A3BA2O9}j{+>||*x2%@--^=(8RT>l zc}kX$G<;vtz)Y$r#BYs;;<1m4=5t8Dk8D>xq<%WdmXK}HzH6pg!B8klT_58 zepa+m4P%{Rge}%>)gleG&#aL@7x3s{^@zFlVF>g0rJ<`Tjb(y9s#!}1h+E7eaJB_N z3`%B5<9Nn6u#xN=2G__ry7;v|WkK;-5w)R((30sWY;G|iCqD@o1Y*`!D~tCO9eaY4nakJYp? z`JtWY3fN1%0%MAiPwCF7w3V1gkaVOj={$`@UUwe-Z>k4vJ=ES$g(N;2ZljZAg{Tzz zn`jn?hZ%FE@TDmK!~o)f0iDt-SU_vb%(Fm78G=Fl%Z!93_n4{p(WC;`2?vx;UPFPR zf5uF*Dm1riDP>&T-F$?wZ=Y*gQu~lA*u|G-h@T3ocX+>n`Z6}+V;)jZ!x3O1aK>U@+!5_pM-3Ax+eNJ-24s}Ao4cCYmO zG?;*Qa)kRpbY3_sP`B9;Z`qa}@F(8K4y!p`b71)sYx+N@A*zT-RTNy=CG{aYg)0aFG>rikIu0Px|Xbm9J+d&hE)+mdU&DgZ}c;k<~f> zM1*lsmX&KASHCeKi9wEWw#PDYmUvtUOE@D{?$}$B``9V6gTTe`Y8pVe6jK`kW@^QYpdh6x#2CnE zaKNT&vn#r&$s2dBd?Z>(Rk=1LD5$oXCY-6IiJAki)}+y+VO`f1ujQf~sm8aFj<-0~ z98UFFOA$u72_?~F zj?j~hul@0uc%C;tWF9eO+zXMDM_+SeD}brUktuZ(AArB(3SLen=_~S_Q%OxQm|r_O zpSnu}w&(bd;_(i|*t;d&q6cL&p9LU|COZB0tGTk@fan~H&ac{7Z`3U{!G`Ws&IuY^69|3si#f_)Z){pXYIAw?AO?uMl(w z8KeWop98(M)k&fPG}|zB?haCo9fM4fW->YlzaOPk;nAslNPuY3UEh4coFkUkdom z1HsphSlEl^W!BWVodIEk(Nk`+HSmYbaqd)pC5mW!3CPU`Gy;^xIN*DhQ%YmYrke3Q zWxkKB2o+v30Pe85@RSu3aE4&$V!cpgxP=I?@a;L3y^{%R2Hl(h=pk8sbSN|}7}YZ- z^bccz&IzX=#7->Hf~M_Ea;LB?`QkIWm=IqArnzL~fb@^$PDB3ccjG8fl-ISE=j6>x zIsWHD?uAu>g9np0A((-)!YME;YTAOy9%LwnjDi|TD%@n zxfpwZMH+oXYhlm{4iua7VRne=- zZ@=j#4)hMZAUVii=Zz@;X#!m1?@RlUFwkTNBPU9`95NV8Ua<%#VwbHM@4HXs`cWEC zUJp2rvZwcJ(a>4IP?~1Dw9yOw%WuXA$kyz`N{~lHf_*MxU_Nf?#KPE597Ps|Ks&K)cI$1(ntS~-`^p;=i4xzPXo|5QAkIx zS0j-yKFNWM-8`c6 zTs*04cqc{)(oP~}7}_GGr(5vpI)U25IXl>9_}=tTr^=z{PW)p2iEEU@V12u0=9d-^Fp?)m5CkR2>nD z+ZpA;`!uc!_QE{BYA61i_}TEy+gme~k;>Bpr_;`Hp0RO(v{$?oA~*30HAGeF%!x$3 z-yazFs`+~nn-#S;Xs}Uw`i@5E2_-Zo=_ALCL9abw&=JmKX8%KSXSQ}yIAQ=MRw2iA zNB5$lOi)7rn4coXkDWq(&;^EHSOakUK%HaN_EgK1wwnIiW?oO?H7mVc6jNGW&L01q zK-~IucIbSm5HuHSK2cBMKf4IA2?d&mF%a(kZHj+ngu2Demvm_XbJQ{tZ=56Zow9i| zg>ErSJUQ?*kigi%-pe2R(kO!YUqr|)sdUBG5x(X6P9dD93WZh(_N?0KH%TX(*?`X?N%44-k4#^CDT^~2g2 z@XTUYh)k>5JTa$1d>4%+-uZyaw^P{Svv$~I-&~BQ~ zQ}=xxxkWGtcQnKew)GT|*?y_R>j%2y-(1tQ&1Ue;9)Z5i4#5HCYo3Wm!gsdrIN!Xj z4|eY85<8*VlKmmy43MDEo@%TdOeb?>J?xko2@4igQj($sCfaBiRI0S3=1t-vfN`N$S#+G?(TX5v!4h;n1ahLV^K-$Aa0M2po%HB&)a-X}Q%d zcF*@b)y$dI0YluZnTw3j`xj?jiT(rJzFh>3^SLr1YIG!Ri0N4>c@68L%QI6SRljHtL95fx!Fv17H?WTHnmq3?IKX#R z|9QXpznZyJtTT$iG$}(pmez+VnMfn+Rti=<+ox_@vZNjhDZ$=!K+}aNK~smoFczEZa8=52*q)-jg1FAND-T!$o5ekfeQuCq)(5&Lni$Kh)2QE({W(x zq|#l8h>9m{Tz}>fa%36!GWq9(jH8LS$A#VHg0kw)S-aSON`37)O4v?|y8CG;>-2EI zAik9Dubrij+)?{@hKOXviVo6l(1n%?*ywz{0z{dPQ2M$8eIdF0rb~Zv1#~~}x%=Tb zhob!oc&CsRd_DozQL^9DqYsZBEilFAhu~-m;($U8Cgi;#@iEfueU1h+QVZ&<2BK4( zPnck@=i8eHsx;`S4IU4-!~(GPHW__MmkV%@Nb35eX(1n@c6D~9gA&=0(6^HBm}X&S z>M}*GT@fhU+N|HD=UY*&X$?ZL?#R?6Ai(m&uUO7?sDFd1 zwO+MlA_2$|ybqbeZK|u;YBnODSjqLWzK(~voe$ND9b~es#02T895iH?_YBU$9?b9r zhb-rYyDo3>7JEj6n`3;TGwN33ub9BA@@amVKNYRSsq&dV9=fU=G&4;r6V``fGSupo z0zX(@e#B`XO#sQDwkc-#F$uNyzDqut3Yhx@mMQCp%Zg0^-~c*D1$M~ZN2^?$k)F4f zW>*7LCK)r}i6wQ#lnWHgU|S|3iac?)7%-a2r))}AW9LjeK~^9sk|%N1IS0taOIhbc z*(AAhx&1x)__IW{k|?blSu(0tY0_zd{*-$#RrDAd@S7PJyL*vW8tG$V}93mKyO@P zF21{2us+Lf)_0YF(by?+gJzYhr={qmr+Po=Bjvve_QFoy=P=>0N$cGxmt-YEfg&|W z$K;>aZHUU(RPTs}dm8BzndhSZg-}v}`n4O}d)L5FiP7Gk;Y3PCF88`^Andqsn!zP@a4&7E)Yi3=E|Ho@(y^inM%04$d5$@l#_F z)%EzA!!)b2wU5qp@JZHgrs^u-w`wHA3sY}Eac0r!u+A{==|xT%gpDEtR-`7Z{bE2( zGv|n_AIyaQaP5K3M3I;aHpZF*K#2-C)btFpdhm-)%1EzKg{qoma-}Go~F|ZAA&gm zdy;rFm?(2t-bo7$-7z;N)7~ZRMb;zbsCd!B=gvcNe5@K73QTKxoy(7HlcE}h7+u;( z22t~#T-JlyR3KTG)qW3-RuDNzAk#WoN~eBmzDIaXXgm5nPy1UU{@r^y~SYE;EFf2-2`3HkJ(m}HPqnGk}z*LG1_F9W2(|0#j- zys?SGadPt5(g7wHr%wYtkwM);5UDX%jgd@CA>3e$c@Q6%nc0VPuTW(K3tasXJv)rZ z^36AE+7_Xh!9Y~pn}Te3ySu8(z&x?vUZP` zS&SPbkmuls^X&6&Njo5VW5F^3tMH)GvF$%s4DZXD=wRUiKW9zMUSmPZ9DZoC1v|{7 zMxCDMWKMioJVn;uN37Vi^b`>zLkUavgh)IXidhJ(WDt9hn&uvpzDkg&)=aw3An8$d zO^*Tf{ZM%`OorkL0~~{UCb00tC6+5gfU!0lCBtGF3aUwe%IL)e973*=2(xIhsk<%2 zQ){hvz%ejt+1FO6Cv~P~Dcc-kiZiyftAyD(Q_0a(TN0@IcdWMdZ=AWWzV;WAH*e`_ z))m2FbS)s|pllmna_fPP+R`O3L*eh~UO<@*e8&a4Ky~+SSoJlUI2;rD*3w+t|85E1-p4q|JN#kc^K!O6#`nj0LLZ==!GYNxxR)O%IMK#m@`JQlgl|U44@kU|N=hZa1CDFp{*s{X zUhwUnF}D~}epNag5W*rR2H7O<^L}bp&3L7M_qH%NeqXSXBxFFqjxTpkGcl=Mu&U7` zWF?AEJ2L%6kAPe{NWiWzGcZO|N!lpzX6h0mXxX}V?@@oG#;a}CAS-ZvS2@!{ZdGi1 zFZ?vv!~Dxy+<;x{!!qn0oN!``WB9H6X%KEUbgcDQWZGo{qe7%xXbp*fnTm}W9x)xf z=YiQ`=`quf48}GN8XtldOoX-vKiZo0Hgd2kGg9-$lKfJSio$@tuoJ0BU0rdyRWT`8 zwCd>&e&>krB~qMd%hf)(IY~^^624noVxR>>kyE0Io!=@r3c(lkX zI{!p(k-17GW2EuNN_lscnZYEtqaG^njIp-)U7a-J%s zW<~qF0_JQ3(3tr_$^t~L(kPwT5QQm>65)2z_7&dtEQ9HHG;|ByHjbFHsQZb2+3pso zn)HJC3-eTw3#YO0m#xY>3PtM9P{ta&H7jX-cD&uGjl7H+#5?wO=soXwQAPb)HVQkg zb9d_W9J_!%G1P34PSdi2I@L?f7F)tc)E5lwHjLl_AC+;pT1vSH?d712n3DlTC0zz3 zKCuxgp~yrfGN3_5XrRK&m@>7bEmR=bVnDU(wMK`T^KzfF0O@Y}aE)&V(b?;~9do+` z-&^$c{hyJ0*zyGz~u&dSe)Ukpf6%qEuzIlJ?BRm%Ts=5pq0EUU!OAayhT8X6&W zGkZo7M|-gZ2*cPd14a(#3TF5G0%ix^Wv7Iq-~Vq7ny6+`jX}!X=|CVaq7F$HD;fgR z0K6(7c9iVy6$+Gb{)*2mSqKO3HidxgjSKAVla^8Z$zb(Ihg<_+)gk zU&E@iN0bWdl0{R6UA|i*+=~rrZjFQ764;ckt^!|7`~%}P^{|EDL$i=7^b!g9(86O4 z={TymC3sVGX8D?7jBqq0$(+Od6}I9u!T^sI`V>1vJ=QZAGJ5SsoPR_#1v$B(NeNon z)R%6swLFq8Gt<=L1J-I$Nd>$4x%`cNSsAa2vMnG|NcBnMF8d?4-TqU@RY{b;b$6L{ z#O16j0^X~2j=WE4C>5(AaK_`6i7zQ@Xlm5hND{k2JBzyR%Z3&y1>WZxt+mZq6H9%Y z7L_a~oyjV`Td&IWYnpv^$6R>3)yeP)R((8<|2Hsqezgt&I>SlH6i8__6Qg5q;hI%Y zrh7kBZNG56%%|et={FQtpRj2Y9R3tc7X%N}DLAC?|E70S(SzF@)LYaH!aFcLJ0$)c zZRTBbk`pS`hAmbhc$x*`5xsU>N>7u8`%sSB8ktP`zlO6xl73z`i>AIkctI`8Bv06z zKhlWvSy6N!g`N}DslTq%f<;|6ROqBf5|94V7YjjX;k%|88n8fngY`V<&5;xKq@>Iy zymXUwdL@lqoN9LskMFE>xjTb}Iz@zp)AM$+7^%-RdmC4Ma-K>jHKu_5ync8__t``x z9pVCVZYI zX5$NP9fh<5UWaZ(q}C@z1)mT9&p1hN&zrO@Vk;Z`QQ7NR>`_L=qaHSkX;0GT+$r5I zp+wv6($%^d?D$y8a^29qZ_7KZ(^8A3-lf<&3WSPY4`-j+$;x~7~*I^mzi_HOYI7HNdpHJB9uEQJyfE2YB$<_*ur1n zalj%ckof!pMeYC#;(efz^iUxniF70@>BBE{5k(9Ge$oTC5brbqXpf62}|u z;Jzs0ScH9%UGoMv6QJ40buq+3u76>lV?ZW|>mtG$siBvKP(=_3R16u)VtT~cv14aV zc8e^su8AQWQuDjbOWEv#=Rw{@$i0pYRURG^XVxG=8n_W{ywpOZZwb#^V><-87 zG#VKelO4v=f-2-6M*KgBFj+1?z(9shMlLDV)G%z|qoWlpb$?>7NK$#(pZ6zDqhd7L zooA=v7SU1h-{6(m2f1yQ2%wnctlMa!hTO*uR zId4tpZnEH9NTl=gGGyJ((;M15M2eLRM-CM~Dm?iVq-m)R6My!L#8ul}T~0wCThF*% zR??r1-c;ErN=}uI5i20(R;t{{r6c`LCBY|M!Y#X}mg3rh=>vL2tp` zm1d_UafJo|rSP3@??gTVd({og#QI_r4516=uU_-4(JsEsCi%Z)%7Xw_JjAD%_pDIy zc*9mwKq$a6-A0ELW<^|EivdbLhxqJ&yc=`XN&3(8V5h4+6cuBy9wgeW!j4E~oKENjL3Z;0A{3aaw zj+QS|?o+y-yFM6faeAz6wmq{SPcQ2!@+M#d3n)c)B9TjG+MHc{i=>htW~4c<8o7Q< zy^!HnV_|~4cbJj>z>etq8dg^C)KZptYM$-~W!wBTCeppkj)WROjZ&lxgTg9=RYF9J zUG()VfnjBP+m(U&%t_^mHkC59u+DM)eYq^BU$br5T9PEz>FHJxiM1asU zjgYqpUu|!E;0s7>844I=^)I+GL=V^w6yr@|Xh|GFGb+U#674{HOr4(Z3&#|{&^c5v zo*Mbw-CAC<3lM4i*{C_(L7!itk?wAe7pXihKGz93(8oW*pIC~Du{g(kWL_SkI>y<4 zgcMCZPDgqk`(B@t4=s+wX=Mm$4hUU@9E?hw9XK0ESRL^KG4>P=j9c@f_FED@2~xKD z7xqFX#tyOESlc_FI??)9ScM?#O7Q?jx!tlRPXxZ=Hsyenah(k;Y^Cd)vv zhldx@<>&(xBImJdM-uVTfyYCGNd)}SvB(sfWf5e^JONadu%%6i8VvCVnLzL%EEpr_ zdA0BnCwtyXJud{TN?w(jhYuMdL0NiVUsb8UFy|Rw0Wj1D$pxgZLkT8$jobzE;eY)a z$@Z|MkpTackgHq-wNxT@32Gk zo5A3VJ>ejN*%AEnRs`q~yS6qYh8^&CuIcpg%QMbIq*v)OiKm9&l*UWJ-=vJ#rgl{k zR4EiSoy)0}j`cWAHWP}gxdiSbWkBeiveIl>+m>lP?s!Wdv>{Lr*8g>qz>8{(;<oR@k+ln&da2}+$-{&bo-S?Z6>L1PmGC&Cz3^ zt~rc%r@15I@Pb5(3&G?v$oT*epAEZG6()@epT$5=^$$X`p`M@R#m~0a;B;CHsOD!_ zEk~qU3V1#vu_C1z#ys|GcR56x>2%PH&m#91VMWp;7N`f!2uP-GRkAdti$s)WytR)< zk41ZVFh>6=_eEMhH3-3h%z$X2G9zJcx)Eo3c(E}h3U!J^z}93Xqy-Fh{%dA;G%fX(llOFa(3<#^nd;hnR6N!> zs5>}6xv4L|_V2x_zBqWMu=Nt$LAs}f^oZ(?<^eX>2bi15^x8`9d}9i9phqFDND*MO z*%>UQ0^Z((z#H#J%CNEmKrPc3wjhSatDhh#X)gWrMIsCGEEmw zo<&C=&<9Hd-9r`*%&!CqvA7~I8Tk!em_F)L%HW;A43Y7>O}%M_w$kR7=>F6~v1&~HWg|wz+Xdnc z5zca;2`bG^$OFRuE}nJ*hCYqS1%_0;-=@oy{SO-aOvA zPhQq^`d1FlKh`+q@C7c4ppyX+^`MarLb@VnovXXU`ij2u?tyO)-2`{Zc)a4r$ zRFbSH+}!M>i0YpG?}tv(Mhqj@;X< z$6_*v-pGpP{wz&ht_S%`JnG%r_-uT<%RhU98Mf1VT}{juBgYg(+2hy>$77+|5VwCd z)k;?OaPdy6ANTiyHr{}Fl-SrpVAPLh z5pB^ws}J_lIpj>Yd_vKM>H4h5*NT!& zQHQ&ihpiECyUmvJYFbYsWvIysOeGzJk2GayT2-sW4*N+}D3P+(o_L!FVnsvsmc6Vm zv68C6g~VMY%~HH}Bv%@#;b=-@W?$2?ZgEnriXxU8nU69h{qzlBi!zLld<>9-U)@v8 zBnCE0r5{7R06oBe7ENB8AFP7R5H}2^y1D|C9*`L>=B62(i#DS1xaX3lW0qR2REo&;uA2k3x!aHWCqF&mr^!#WBFd!z&gf3Ib!grU$m6nQ#5p zlvpcn_vrlg3G2JZ7Su4V3V&Y@v2_d#f4Jog2b=QJnA6wmYGRwh*uo3kBX$f~B@L5$ zCzGbkbUqe82~}w}vJ_g)E6eIcrtYg-01Q=~+G4QkGS5rUwdO^F5%v!h78}P6P>N}q z+NP{3Tg?|yBH5aHp|CrZ&{v}82`=nNbXz;ggRuhvObe1DH8MOVt-_K8$yYtR013Hu zv*0I?;lqj`FzkgA1vVr?#OCyQn88Mj)K=k@z4zZAjmZaNF%LwK zU0_K*jcx@#qWXI%-%>0ZiE(P3)>j1oE;vO^i`rnY?NndhvrN*9$?1?wC+%;3iwH

tF#jj(7HkY`vS*RWis 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 diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 4389ca2300369ab73deaf2704bd8feceebe6325f..86efad79f48c24d208e7fda9ed1a76a9d924e17e 100644 GIT binary patch delta 1948 zcmV;N2V?lBLZw2Get#rAI(wbBj@DHk+R7Z_nWekR=O3Fcnc56FO;h0MK^89?Sa z#K(rE-F=3x3#QOj+KLWc%|SLM@c#MdpQ-iDoGeVO^~!C%IR_Xn!TJU}3k|<+WdeC+ zcUqcdVz|P4C*=R_mfdY>NZ&g_`s>!KH?j8Z7IYlTdENT;&42uc(WK?>U6>d;CNQ#R z*?RxJWg>&L|Arli7mn#YX}8WC=hDJA3){9F40W%;gZCfWrVR2cyW>su^*8h3oB7W_ z|0r$6UCigeSt}#ub_N~T0uF4M7H+K}ZUJ-M(yaL$n%HekET@HM$Ze5b-&5L(4ID5h zd$n-9-5;;t+JBad{LQ7WV_(ParoI5(wb)F&AKDDg0gDv=R-3qWp+gg+34%@v)(O&E z4zwNU`ZESC7aEhdq|F$aQ}WqN+yc7pK-YzO3x&}3S{Jy5{B_Qu-Wso4p!Fv~ymkw; zPAna2tyjw#(q=7W>PQ0^dSlEN21c6q_N@)HJE(`F;D5CZU$=m%w?ON&*J=jbnYV9n z1?IK^$=1B{_6fXV*{li-QYcJN;-2O41PvCl@_9sYP ztOtt)?Dy{b%ER}z;ti&Z{#IP&j>X3>SL+ z9Oy0#?0;=E{YGz!DJJzg=d;Ducx<>~5AXM%0YUeBZROTdM#`kq?WujGt$c8-Is5z4 zGBrpV{t1kQH^Yw7R?dO@3C$5!Mu+~74-lRJJ9>HLz&TpX>4VQc$||F7Te+f0sr=70 zI)B|9&ouKtGx*2*_extixj6Nv9{(cav8}`Dy^}o@Cx7s^_6BP9U2NU-hd0Oz*n+ll zgQg}Ryy2H}>tkrIt(*c3vPOTX{R^BRy+$JQAOc$k5CjuSx)91&tnm-1VQ&)|T&U2M;#9tH9$y7)ws$0kuzAcWddugOtlsE`Jxw z@9n_n_P3C)gKoN*`>&d(Zo{F9JSL2wVvw77O`f*wQu{oz>l$hh*?2?Q6+q#UU2%n* z_T-mj!BB;gEOU$vPFuP5@i$vqoPPuN zi|bAKu&tckdmr}NvT$AUvby|;&qa*4M~mmQ{>TpSG!C}1l3n%!#7cj^OswEpbzy>M zc_M`MA^!%~?Uvn3J|p7gBLw=%44Ay;5uO!`k_cW!0phR8TZ1>}CW(&3_VIF_TGZ^6 z`f9803_E6Dy&F!|h3P>3=Wwzz`;!V47k~K7XA4IF(Wdp}rfnt)BkIW#fU&n+`*_PT z+}6EsYWXG?wG&DYjj9W*@O(BYjp*niUbPn>DE0@%f+FXzkW*BU-kids%AqZ3S?i%y zIOnF>5R#_}A1BG9?(K1o!H|b@98EBE=niefL>NGM`~-{<8U4(*v{{bsS&_vs!+&pq z+r$^wL@hMFx8;6}&~%G~x%3~mklO;Sun9wF-A=dDWkf7(BQ-+FJ)al%93Jp+&*OC+ ztTTY}7<@ArdkajHS(fCOl4DAa`Mf#i!C?W%{0Q9N$3H5uNz%3aOl)jfMk(JTz_OVg z*-BA%7f!Ef=BPZqdfK+48%LDUW>)ifE% z?gt+x=VPgdft7jx<-$nwe)^D+$f1p37*8Dk)uNc+YY6nJ1VH=p#7K?TxPScgn!+nQ zz4ic!A6rK=Z5mlf)v#fzAwjW>vt9bQoN=XNma5LLsT`%B6N!0>T+O=Az|0bE67a?jUiaM; in$YpE_%8rD-}ZX9owF|p@E8b84l0pR)Bym8Gx(1H delta 1984 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 F0RZn;ASnO< delta 5144 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 GE&%{eHyCyR diff --git a/build/params_calibnet.go b/build/params_calibnet.go index 0661bb839..32923f7a8 100644 --- a/build/params_calibnet.go +++ b/build/params_calibnet.go @@ -4,7 +4,6 @@ package build import ( - "math" "os" "strconv" @@ -71,7 +70,8 @@ const UpgradeSkyrHeight = 510 const UpgradeSharkHeight = 16800 // 6 days after genesis -const UpgradeHyggeHeight = math.MaxInt64 +// 2023-02-21T16:30:00Z +const UpgradeHyggeHeight = 322354 var SupportedProofTypes = []abi.RegisteredSealProof{ abi.RegisteredSealProof_StackedDrg32GiBV1, diff --git a/build/version.go b/build/version.go index 70e27ad50..7ae30bba8 100644 --- a/build/version.go +++ b/build/version.go @@ -37,7 +37,7 @@ func BuildTypeString() string { } // BuildVersion is the local build version -const BuildVersion = "1.19.1-dev" +const BuildVersion = "1.20.0-rc1" func UserVersion() string { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 4b705adad..41ea959bc 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,7 +7,7 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.19.1-dev + 1.20.0-rc1 COMMANDS: init Initialize a lotus miner repo diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index 74b7a19b8..f5cf91192 100644 --- a/documentation/en/cli-lotus-worker.md +++ b/documentation/en/cli-lotus-worker.md @@ -7,7 +7,7 @@ USAGE: lotus-worker [global options] command [command options] [arguments...] VERSION: - 1.19.1-dev + 1.20.0-rc1 COMMANDS: run Start lotus worker diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 04d6611bf..b3348a61e 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -7,7 +7,7 @@ USAGE: lotus [global options] command [command options] [arguments...] VERSION: - 1.19.1-dev + 1.20.0-rc1 COMMANDS: daemon Start a lotus daemon process From 45cbbe6c7abc43a79a47461f2016e3cdfd82049f Mon Sep 17 00:00:00 2001 From: jennijuju Date: Tue, 14 Feb 2023 18:24:43 -0500 Subject: [PATCH 16/49] update to gst 10-rc3 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 909fbed57..f74149438 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-paramfetch v0.0.4 - github.com/filecoin-project/go-state-types v0.10.0-rc2 + github.com/filecoin-project/go-state-types v0.10.0-rc3 github.com/filecoin-project/go-statemachine v1.0.2 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 diff --git a/go.sum b/go.sum index bf91929a1..4d8dc0630 100644 --- a/go.sum +++ b/go.sum @@ -356,8 +356,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.10.0-rc2 h1:nl92h86XridAoy0fjvW+8/8/eI0caVSm0fhAnIvtR64= -github.com/filecoin-project/go-state-types v0.10.0-rc2/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024= +github.com/filecoin-project/go-state-types v0.10.0-rc3 h1:qExCc2swTe5ndsiu9dEoMqIwppjuTNRbsAFgpzHnHbc= +github.com/filecoin-project/go-state-types v0.10.0-rc3/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= From 3f063f7cd7d3e30e1110b5606d44381a8e3c2a99 Mon Sep 17 00:00:00 2001 From: Aayush Date: Tue, 14 Feb 2023 19:04:43 -0500 Subject: [PATCH 17/49] fix: StorageKey is now fixed-size array --- node/impl/full/eth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 775550be2..d41a15c88 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -526,7 +526,7 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd } params, err := actors.SerializeParams(&evm.GetStorageAtParams{ - StorageKey: position, + StorageKey: *(*[32]byte)(position), }) if err != nil { return nil, fmt.Errorf("failed to serialize parameters: %w", err) From 39c709f7b36b89cba6b3bb05936ef854a19ad8a8 Mon Sep 17 00:00:00 2001 From: jennijuju Date: Tue, 14 Feb 2023 19:24:35 -0500 Subject: [PATCH 18/49] update butterfly artifects --- build/bootstrap/butterflynet.pi | 4 ++-- build/genesis/butterflynet.car | Bin 8383896 -> 8383893 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/bootstrap/butterflynet.pi b/build/bootstrap/butterflynet.pi index 1def01c7c..5b10e2bc4 100644 --- a/build/bootstrap/butterflynet.pi +++ b/build/bootstrap/butterflynet.pi @@ -1,2 +1,2 @@ -/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWHkVVMJ1rfVLM5poNrgwTJiaDkpDLkPqQ9zVuNPQ7AJ6p -/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWRyzqeQd51HCvVK3nvegmnBsYYPLSZbxR3Q9XAoUrUZ18 +/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWCa1wgMMBB9JjA2kYqaN1v5uh7xvcsc2gQJBHzPp7G57H +/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWD6fCvo1dyci6wsjTLyv7eJK73pCVz6RCQjbtPvbc8LYw diff --git a/build/genesis/butterflynet.car b/build/genesis/butterflynet.car index cb0c4162b4e0ffdacfe124005725f8435381b7ab..589e5ab7574a37bf39581d4acbf393ee942c476d 100644 GIT binary patch delta 2546 zcmb8wdpJ~S7y$4&GsqZ;n#_z;M=s+MDWZ}o_e>>1CP}3sYE+uh=)y3QM!Lz-Qgqoi zMRXZq%EQtX871XjZDcpsq9j_EeW&_kpJ(^k+5Y&Qf6n*5?|07oUD8^{2`51kS>TkM zE7-8B(%-_)#lb$CmHD)_jS^F56TNClUX+$Jvwq9&;9cCX9orEJ9*H>Ljz<**Bst=6 zaV*p_3}0^X>L7w?wDP0kjOs4g4L_`_tf#mfD4smNJTy^=TN)?Cu})xX(L(Rn6**19 z7M?>*!GV-Q;e_bL1EU5-71Q{oS5|P78dAf11!nRG33EjB2|Wf%H$xFWWTm1wky4{6 zi;nv??S_QwQ%w?2)>x11J?5CvcHy4v?b`9=Tlc&id}d~|H>+Xl1S?eGpbdmvR5UQo z-gl(L578_tEQmgP%Gf-o^Mmxwb3MK8{@+(Smtkf~60~OaIU<73B}e9tcleH9)HT05 zN^0J!-CClnyjvyPG7uY4%0izT2i|5MGVF{tJ?>TZC3S*jct#C3!2g};>6hfA>)Ek4 z?n^ZCKYbyK>9{bP|XoFW}pX~WHK;v@w1rB&hb+UJU?Ui0&=xdk|#Ebo&H_q5_{ z@eP=?hMtV+klfLfgJVb5w|Zq+4OaIhjHxWU>ekskl&IWwfYQ;^y_`N76Tu*hBi5Op zOgiqjumtoi+8tQ`@D;lkbrJb0o_B*rv(h!N9ufnsZti;@p-mHhY)mSRzkY0z>a%Q- zt9vZVKot;y8Xy7r_=!LROahuf3rq%602xdL z+JFM6fF@jd`tDC%1rYc6aGmpj^pR&)BMGukyrsLdtH5%I}`3)xnlO_Cwy7R}#2 z|GGlGRLwb=xMo`|mQELs4C{btKvz04JpJ-sTSc9Z^F?fTus?8!TEnDKJ9q4CI{D}_ zH+yk2Zw8nNP@o590exTq45iIHqvLyh6fGI~M@W9T%^2`py{N4{qq{n9=binJnVQ)T ztEn87+L?kwbRB+BPzbjF+VifW42P1Gbcwj+y%C@TV_*VIff<+$%z*`%11!N@Fb`M( zYcLy9as$P0Yh5yeo0WHkD|3KpZ>x41lw?zzFGDWjaHI?j6K?!H#Qib zc}mvxO+S7*=ccp!wI>-~Iq#PLQDrZCwP^?^=2k2P4!{vO0cYR>T!9-{2HXJ?EC(yV zO5g!j0Z-rsRs(O~1AM_6;0IV>E$|2HKmb?|0>K8b5o`iMU^8HYU=RYffKU(ywt{Vd z1H!>}umkJ_5nvbK0-lsx5g9@fDB9Jcza4N18E$1=`zC6={1g|(Z+l$Zy`)%Dpg(wy z`Or`$VBhR68sQx$D3Zqu-W9^xvptwssr2n&{Es-n*Fd2&Ap@747$@|_yP0M^OBwRe zh|fPyHu2tlcSbHTheqg;zhdM+A(+_OaE%Ul8#WhR)ZtiDC^SO15MHrm?>t3k%TKD! z$r>(uRYlUbxll$U^a>UBTJXB=TE>Q<;#a4xLz@TsnLw6UO#Pqt>%M>@}^ z5xV51juRK8n$*%4ZnVpP>eIYpf0Kckp?CH9mN#Y{Mh1qI>@~S&Y3fA?=>{TsgLGa> zpoYqSVTYO8BW6#?(C6#Q@yM#hvrxfmzfCkk$Jg2a=%%Iye+~Q51C1K?H7sd}Ke}^l zHuD4VlmDJxl&{PUO)xmh7>K9536_*MWT|M%h|E=o(FY5no1uMF+BODu&yCw#wA9Ep&FN&S|b`}s+nxLjTUVe zC9%(zXxgS{SD8voTZ=X!WeK&)Jyz>Uk9|jd=)*oc>%;HUIq&z1>o^!V}#oJF8uIDI#${J)M=5!bH`hQE3%JXriKk zLU$#lTnceoC0yil?MQS-0nYAB)yAwyTgf67doQo&6M5MZ4AV_8mR;&H#

qt+sWW5Z$wDjXG{D1@)v zZB8*&`nY1AU3+(t5Ya*T+fcHBtYGxF%Ys_tzLmt#aC9AZsWI4K6XL~PyP z%u~rabs~U$<5w+;p>Z!yGtOqfD$wEpM)>nna-zsWxt>UhEq@`aeCu$#14)sP2b|RW zDi8+srolq&{b}XC%1xqqw;k#Gt3&9#YN5Y-vN+p;=89nmP(nP@{gDVw@(m(kpR3+qt*veGUs zQ_J*dP6Tb}&OzhA4l3UlC-B9g02&}b8K?kNuna5*7@!8QKt5j`XaG&11y%rUuoCEi zRp1Mt3-Ev-@x`s)ITos@Zn+dP^1~k*(af5fk#*F}&W0*ZN&IP5sUfdPL;7e#L*>r- zTeWj)qBk~s2VCCO_s+-?rv&qJtAQTSm(0%@RA<^Ls(fx3N{gC9wM3W=1nhCK>PEI- zrh0F=poeV;)&L?f0>)r1SO-ibJ?!-bnW2hWW^oe7kBo<=l{^_($RE_Kohnfh z_8FUPaZ7jn@E-RetySH1)-1!GvOd^l&1u2SiS@t~Yyf7!99V#j;7dRPmS7Vg11n$+ zY`|t<3+%uaU=JL?SHKZC0cXk0375F;P({5gUq0`ij-OGrj+fhresPq0QjaN#Uu7{j zTzO19u9KDvhVY}>tRd!bDX6LM!Z8-v#%oVr+cd!+B08iirz6RdF2lxU%;12@8 zHV_DcKrq-2LO>`813N%Cpa3d}0FfXHM1!3m2E+myhy%MoJfMRFkO&wc2_%EvU=P>} zm>>nDf;5m0Sb!~I$@V2+xr%Nz|FZ|~?FLS3j}&50oY&lYi=!PLd%woWHic_y^18Ru!*{;AWTN8z?N|2? zJifZ?arO+J@o@u7d`s|2i(z&7GxZOt&(>s%ZMmhk<8ChFPF|so-6eF_^{p{hBh#5z z^7B*D8N07;INZ0u?e3n&$IFj$sL|nAl10^Qqi~9TzTsfi0;BDB0x~Q=e}{`<&(p3= z33bjEWeBBPpEL$MwZJFKgD@&;S?>qe)eADnDn64%hX$pg5Hz~D4!)_AWxTx)NtjSu zJ3U#v8QtOCJvd`@S76e1-97(uQIYu@Z=0Y~sa4O#=N~#LF$VAnf}GBMU_bZ Date: Tue, 14 Feb 2023 20:52:32 -0500 Subject: [PATCH 19/49] chore: add v1.20.0-rc1 changelog (#10273) * add v1.20.0-rc1 changelog Co-authored-by: Aayush Rajasekaran --- CHANGELOG.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd450afd2..b77b86ee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,55 @@ # Lotus changelog +# 1.20.0-rc1 / 2023-02-14 + +This is the first release candidate for the upcoming MANDATORY 1.20.0 release of Lotus. This release will deliver the Hygge network upgrade, introducing Filecoin network version 18. The centerpiece of the upgrade is the introduction of the [Filecoin Virtual Machine (FVM)’s Milestone 2.1](https://fvm.filecoin.io/), which will allow for EVM-compatible contracts to be deployed on the Filecoin network. This upgrade delivers user-programmablity to the Filecoin network for the first time! + +Note that this release candidate does NOT set the epoch at which mainnet will upgrade; that detail will be finalized in the 1.20.0 release. + +The Hygge upgrade introduces the following Filecoin Improvement Proposals (FIPs), delivered in FVM3 (see FVM [v3.0.0-rc.1](https://github.com/filecoin-project/ref-fvm/pull/1664)) and builtin-actors v10 (see actors [v1.10.0-rc.1](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0-rc.1)): + +- [FIP-0048](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0048.md): f4 Address Class +- [FIP-0049](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md): Actor events +- [FIP-0050](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0050.md): API between user-programmed actors and built-in actors +- [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md): Filecoin EVM runtime (FEVM) +- [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md): Supporting Ethereum Accounts, Addresses, and Transactions +- [FIP-0057](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0057.md): Update gas charging schedule and system limits for FEVM + +## Filecoin Ethereum Virtual Machine (FEVM) + +The Filecoin Ethereum Virtual Machine (FEVM) is built on top of the WASM-based execution environment introduced in the Skyr v16 upgrade. The chief feature introduced is the ability for anyone participating in the Filecoin network to deploy their own EVM-compatible contracts onto the blockchain, and invoke them as appropriate. + +## New Built-in Actors + +The FEVM is principally delivered through the introduction of **the new [EVM actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/evm)**. This actor “represents” smart contracts on the Filecoin network, and includes an interpreter that implements all EVM opcodes as their Filecoin equivalents, and translates state I/O operations to be compatible with Filecoin’s IPLD-based data model. For more on the EVM actors, please see [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md). + +The creation of EVM actors is managed by **the new** [Ethereum Address Manager actor (EAM)](https://github.com/filecoin-project/builtin-actors/tree/master/actors/eam), a singleton that is invoked in order to deploy EVM actors. In order to make usage of the FEVM as seamless as possible for users familiar with the Ethereum ecosystem, this upgrades also introduces **a dedicated actor to serve as “[Ethereum Accounts](https://github.com/filecoin-project/builtin-actors/tree/master/actors/ethaccount)”**. This actor exists to allow for secp keys to be used in the Ethereum addressing scheme. **The last new built-in actor introduced is [the Placeholder actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/placeholder)**, a thin “shell” of an actor that can transform into either EVM or EthAccount actors. For more on the EAM, EthAccount, and Placeholder actors, please see [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md). + +## Calibration nv18 Hygge Upgrade + +This release candidate sets the calibration-net nv18 Hygge upgrade at epoch 322354, 22023-02-21T16:30:00Z. The bundle the network will be using is [v10.0.0 actors](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0-rc.1) +(located at `build/actors/v10.tar.zst`) upon/post migration, manifest CID `bafy2bzaced25ta3j6ygs34roprilbtb3f6mxifyfnm7z7ndquaruxzdq3y7lo`. + +## Node Operators + +FVM has been running in lotus since v1.16.0 and up, and the new FEVM does not increase any node hardware spec requirement. + +With FEVM on Filecoin, we aim to provide full compatibility with the existing EVM ecosystem and its tooling out of box and thus, lotus now provides a full set of [Ethereum-styled APIs](https://github.com/filecoin-project/lotus/blob/release/v1.20.0/node/impl/full/eth.go) for developers and token holders to interact with the Filecoin network as well. + +**Enable Ethereum JSON RPC API** + +Note that Ethereum APIs are only supported in the lotus v1 API, meaning that any node operator who wants to enable Eth API services must be using the v1 API, instead of the v0 API. To enable Eth RPC, simply set `EnableEthRPC` to `true` in your node config.toml file; or set env var `LOTUS_FEVM_ENABLEETHRPC` to `1` before starting your lotus node. + +**Eth tx hash and Filecoin message CID** + +Most of the Eth APIs take Eth accounts and tx has as an input, and they start with `0x` , and that is what Ethereum tooling support. However, in Filecoin, we have Filecoin account formats where things start with `f` (`f410` specifically for eth accounts on Filecoin) and the messages are in the format of CIDs. To enable a smooth developer experience, Lotus internally converts between Ethereum address and Filecoin account address as needed. In addition, lotus also keeps a Eth tx hash <> Filecoin message CID map and stores them in a SQLite database as node sees a FEVM messages. The database is initiated and the maps are populated automatically in `~//sqlite/txhash.db` for any node that as Eth RPC enabled. Node operators can configure how many historical mappings they wanna store by configuring `EthTxHashMappingLifetimeDays` . + +**Events*** + +[FIP-0049 introduces actor events](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md) that can be emitted and externally observable during message execution. An `events.db` is created automatically under `~//sqlite` to store these events if the node has Eth RPC enabled. Node operators can configure the events support base on their needs by configuration `Events` configurations. + +Note: All three features are new and we welcome user feedbacks, create an issue if you have any enhancements that you’d like to see! + # 1.19.0 / 2022-12-07 This is an optional feature release of Lotus. This feature release includes the SplitStore beta, the experimental Lotus node cluster feature, as well as numerous enhancments and bugfixes. From 4f259d8644b458793fda8c9dee8d3fa695d43b0a Mon Sep 17 00:00:00 2001 From: Aayush Date: Wed, 15 Feb 2023 11:09:24 -0500 Subject: [PATCH 20/49] Revert "Standardize path variable" This reverts commit a9c1caa1886fbb7c576c46d4ade90f5c1561f6a2. --- cmd/lotus-shed/balances.go | 10 ++++------ cmd/lotus-shed/datastore.go | 12 +----------- cmd/lotus-shed/deal-label.go | 5 ++--- cmd/lotus-shed/diff.go | 5 ++--- cmd/lotus-shed/export-car.go | 5 ++--- cmd/lotus-shed/export.go | 10 ++++------ cmd/lotus-shed/fip-0036.go | 11 ++++++++--- cmd/lotus-shed/gas-estimation.go | 10 ++++------ cmd/lotus-shed/import-car.go | 14 -------------- cmd/lotus-shed/invariants.go | 5 ++--- cmd/lotus-shed/keyinfo.go | 11 +++-------- cmd/lotus-shed/main.go | 14 ++++++++++++++ cmd/lotus-shed/market.go | 10 ++++------ cmd/lotus-shed/migrations.go | 5 ++--- cmd/lotus-shed/miner-peerid.go | 8 +++----- cmd/lotus-shed/miner-types.go | 8 +++----- cmd/lotus-shed/msig.go | 5 ++--- cmd/lotus-shed/nonce-fix.go | 6 ++++++ cmd/lotus-shed/pruning.go | 5 ++--- cmd/lotus-shed/splitstore.go | 10 ++++------ cmd/lotus-shed/terminations.go | 5 ++--- 21 files changed, 74 insertions(+), 100 deletions(-) diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index c647f3b8e..9ce4faf72 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -454,9 +454,8 @@ var chainBalanceStateCmd = &cli.Command{ Description: "Produces a csv file of all account balances from a given stateroot", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.BoolFlag{ Name: "miner-info", @@ -678,9 +677,8 @@ var chainPledgeCmd = &cli.Command{ Description: "Calculate sector pledge numbers", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, ArgsUsage: "[stateroot epoch]", diff --git a/cmd/lotus-shed/datastore.go b/cmd/lotus-shed/datastore.go index d6b932954..5614e34f6 100644 --- a/cmd/lotus-shed/datastore.go +++ b/cmd/lotus-shed/datastore.go @@ -41,11 +41,6 @@ var datastoreListCmd = &cli.Command{ Name: "list", Description: "list datastore keys", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, - }, &cli.StringFlag{ Name: "repo-type", Usage: "node type (FullNode, StorageMiner, Worker, Wallet)", @@ -115,11 +110,6 @@ var datastoreGetCmd = &cli.Command{ Name: "get", Description: "list datastore keys", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, - }, &cli.StringFlag{ Name: "repo-type", Usage: "node type (FullNode, StorageMiner, Worker, Wallet)", @@ -133,7 +123,7 @@ var datastoreGetCmd = &cli.Command{ }, ArgsUsage: "[namespace key]", Action: func(cctx *cli.Context) error { - _ = logging.SetLogLevel("badger", "ERROR") + logging.SetLogLevel("badger", "ERROR") // nolint:errcheck r, err := repo.NewFS(cctx.String("repo")) if err != nil { diff --git a/cmd/lotus-shed/deal-label.go b/cmd/lotus-shed/deal-label.go index 2baa751a9..417d13701 100644 --- a/cmd/lotus-shed/deal-label.go +++ b/cmd/lotus-shed/deal-label.go @@ -24,9 +24,8 @@ var dealLabelCmd = &cli.Command{ Usage: "Scrape state to report on how many deals have non UTF-8 labels", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/diff.go b/cmd/lotus-shed/diff.go index e29d9ca6d..981dc850c 100644 --- a/cmd/lotus-shed/diff.go +++ b/cmd/lotus-shed/diff.go @@ -33,9 +33,8 @@ var diffMinerStates = &cli.Command{ ArgsUsage: " ", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/export-car.go b/cmd/lotus-shed/export-car.go index e32dbb2cf..5cb4737ea 100644 --- a/cmd/lotus-shed/export-car.go +++ b/cmd/lotus-shed/export-car.go @@ -35,9 +35,8 @@ var exportCarCmd = &cli.Command{ Description: "Export a car from repo", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, ArgsUsage: "[outfile] [root cid]", diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go index ab6d88698..459de3383 100644 --- a/cmd/lotus-shed/export.go +++ b/cmd/lotus-shed/export.go @@ -42,9 +42,8 @@ var exportChainCmd = &cli.Command{ Description: "Export chain from repo (requires node to be offline)", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.StringFlag{ Name: "tipset", @@ -147,9 +146,8 @@ var exportRawCmd = &cli.Command{ Description: "Export raw blocks from repo (requires node to be offline)", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.StringFlag{ Name: "car-size", diff --git a/cmd/lotus-shed/fip-0036.go b/cmd/lotus-shed/fip-0036.go index 1929eb4dd..485302b9b 100644 --- a/cmd/lotus-shed/fip-0036.go +++ b/cmd/lotus-shed/fip-0036.go @@ -58,6 +58,12 @@ var fip36PollCmd = &cli.Command{ Name: "fip36poll", Usage: "Process the FIP0036 FilPoll result", ArgsUsage: "[state root, votes]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + }, Subcommands: []*cli.Command{ finalResultCmd, }, @@ -69,9 +75,8 @@ var finalResultCmd = &cli.Command{ ArgsUsage: "[state root] [height] [votes json]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, diff --git a/cmd/lotus-shed/gas-estimation.go b/cmd/lotus-shed/gas-estimation.go index 669c1c345..cf56ea03d 100644 --- a/cmd/lotus-shed/gas-estimation.go +++ b/cmd/lotus-shed/gas-estimation.go @@ -42,9 +42,8 @@ var gasTraceCmd = &cli.Command{ ArgsUsage: "[migratedStateRootCid networkVersion messageCid]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { @@ -147,9 +146,8 @@ var replayOfflineCmd = &cli.Command{ ArgsUsage: "[messageCid]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.Int64Flag{ Name: "lookback-limit", diff --git a/cmd/lotus-shed/import-car.go b/cmd/lotus-shed/import-car.go index 6bba1d980..973e7b31b 100644 --- a/cmd/lotus-shed/import-car.go +++ b/cmd/lotus-shed/import-car.go @@ -19,13 +19,6 @@ import ( var importCarCmd = &cli.Command{ Name: "import-car", Description: "Import a car file into node chain blockstore", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, - }, - }, Action: func(cctx *cli.Context) error { r, err := repo.NewFS(cctx.String("repo")) if err != nil { @@ -103,13 +96,6 @@ var importCarCmd = &cli.Command{ var importObjectCmd = &cli.Command{ Name: "import-obj", Usage: "import a raw ipld object into your datastore", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, - }, - }, Action: func(cctx *cli.Context) error { r, err := repo.NewFS(cctx.String("repo")) if err != nil { diff --git a/cmd/lotus-shed/invariants.go b/cmd/lotus-shed/invariants.go index 953674ed0..e48f301c4 100644 --- a/cmd/lotus-shed/invariants.go +++ b/cmd/lotus-shed/invariants.go @@ -35,9 +35,8 @@ var invariantsCmd = &cli.Command{ ArgsUsage: "[StateRootCid, height]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 1c322f7d6..38f5ee6fe 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -146,14 +146,9 @@ var keyinfoImportCmd = &cli.Command{ Examples env LOTUS_PATH=/var/lib/lotus lotus-shed keyinfo import libp2p-host.keyinfo`, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, - }, - }, Action: func(cctx *cli.Context) error { + flagRepo := cctx.String("repo") + var input io.Reader if cctx.NArg() == 0 { input = os.Stdin @@ -182,7 +177,7 @@ var keyinfoImportCmd = &cli.Command{ return err } - fsrepo, err := repo.NewFS(cctx.String("repo")) + fsrepo, err := repo.NewFS(flagRepo) if err != nil { return err } diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index c0d0043f1..28a59f14d 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" logging "github.com/ipfs/go-log/v2" @@ -88,6 +89,19 @@ func main() { Version: build.UserVersion(), Commands: local, Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + &cli.StringFlag{ + Name: "miner-repo", + Aliases: []string{"storagerepo"}, + EnvVars: []string{"LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH"}, + Value: "~/.lotusminer", // TODO: Consider XDG_DATA_HOME + Usage: fmt.Sprintf("Specify miner repo path. flag storagerepo and env LOTUS_STORAGE_PATH are DEPRECATION, will REMOVE SOON"), + }, &cli.StringFlag{ Name: "log-level", Value: "info", diff --git a/cmd/lotus-shed/market.go b/cmd/lotus-shed/market.go index 6d86c90b9..0c5e7c81d 100644 --- a/cmd/lotus-shed/market.go +++ b/cmd/lotus-shed/market.go @@ -124,9 +124,8 @@ var marketExportDatastoreCmd = &cli.Command{ Description: "export markets datastore key/values to a file", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Usage: "path to the repo", }, &cli.StringFlag{ Name: "backup-dir", @@ -242,9 +241,8 @@ var marketImportDatastoreCmd = &cli.Command{ Description: "import markets datastore key/values from a backup file", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Usage: "path to the repo", }, &cli.StringFlag{ Name: "backup-path", diff --git a/cmd/lotus-shed/migrations.go b/cmd/lotus-shed/migrations.go index e0336283a..a7e0ee34f 100644 --- a/cmd/lotus-shed/migrations.go +++ b/cmd/lotus-shed/migrations.go @@ -54,9 +54,8 @@ var migrationsCmd = &cli.Command{ ArgsUsage: "[new network version, block to look back from]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.BoolFlag{ Name: "skip-pre-migration", diff --git a/cmd/lotus-shed/miner-peerid.go b/cmd/lotus-shed/miner-peerid.go index fdf8dae8d..e43063797 100644 --- a/cmd/lotus-shed/miner-peerid.go +++ b/cmd/lotus-shed/miner-peerid.go @@ -26,12 +26,10 @@ import ( var minerPeeridCmd = &cli.Command{ Name: "miner-peerid", - Usage: "Scrape state to find a miner based on peerid", - Flags: []cli.Flag{ + Usage: "Scrape state to find a miner based on peerid", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/miner-types.go b/cmd/lotus-shed/miner-types.go index 15e5db265..822d037aa 100644 --- a/cmd/lotus-shed/miner-types.go +++ b/cmd/lotus-shed/miner-types.go @@ -28,12 +28,10 @@ import ( var minerTypesCmd = &cli.Command{ Name: "miner-types", - Usage: "Scrape state to report on how many miners of each WindowPoStProofType exist", - Flags: []cli.Flag{ + Usage: "Scrape state to report on how many miners of each WindowPoStProofType exist", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go index 96ba91219..ccc932c93 100644 --- a/cmd/lotus-shed/msig.go +++ b/cmd/lotus-shed/msig.go @@ -43,9 +43,8 @@ var multisigGetAllCmd = &cli.Command{ ArgsUsage: "[state root]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { diff --git a/cmd/lotus-shed/nonce-fix.go b/cmd/lotus-shed/nonce-fix.go index d68f22e0b..d69c8a48d 100644 --- a/cmd/lotus-shed/nonce-fix.go +++ b/cmd/lotus-shed/nonce-fix.go @@ -17,6 +17,12 @@ import ( var noncefix = &cli.Command{ Name: "noncefix", Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, &cli.Uint64Flag{ Name: "start", }, diff --git a/cmd/lotus-shed/pruning.go b/cmd/lotus-shed/pruning.go index 1b6553057..275f3bc0a 100644 --- a/cmd/lotus-shed/pruning.go +++ b/cmd/lotus-shed/pruning.go @@ -86,9 +86,8 @@ var stateTreePruneCmd = &cli.Command{ Description: "Deletes old state root data from local chainstore", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.Int64Flag{ Name: "keep-from-lookback", diff --git a/cmd/lotus-shed/splitstore.go b/cmd/lotus-shed/splitstore.go index 348f2e36d..e8c45a0c5 100644 --- a/cmd/lotus-shed/splitstore.go +++ b/cmd/lotus-shed/splitstore.go @@ -39,9 +39,8 @@ var splitstoreRollbackCmd = &cli.Command{ Description: "rollbacks a splitstore installation", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.BoolFlag{ Name: "gc-coldstore", @@ -130,9 +129,8 @@ var splitstoreClearCmd = &cli.Command{ Description: "clears a splitstore installation for restart from snapshot", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, &cli.BoolFlag{ Name: "keys-only", diff --git a/cmd/lotus-shed/terminations.go b/cmd/lotus-shed/terminations.go index c9e3d26bb..c5f35995a 100644 --- a/cmd/lotus-shed/terminations.go +++ b/cmd/lotus-shed/terminations.go @@ -33,9 +33,8 @@ var terminationsCmd = &cli.Command{ ArgsUsage: "[block to look back from] [lookback period (epochs)]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "repo", - Value: "~/.lotus", - EnvVars: []string{"LOTUS_PATH"}, + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { From 6028d7ba1882aa82dad6a61630f9fb7c91e0ff73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 15 Feb 2023 19:41:46 +0100 Subject: [PATCH 21/49] sectors list: Explain http mode --- cmd/lotus-miner/sectors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 2dad7fc0f..6ff84b3fa 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -317,6 +317,7 @@ var sectorsListCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + // http mode allows for parallel json decoding/encoding, which was a bottleneck here minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp) if err != nil { return err From 12656b05fe94361873f61bd9c7cbda143dfaf447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 2 Feb 2023 11:37:45 +0100 Subject: [PATCH 22/49] feat: shed: Add a tool for removing sector data --- cmd/lotus-shed/sectors.go | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/cmd/lotus-shed/sectors.go b/cmd/lotus-shed/sectors.go index ee2f58c6b..465b0e772 100644 --- a/cmd/lotus-shed/sectors.go +++ b/cmd/lotus-shed/sectors.go @@ -49,6 +49,7 @@ var sectorsCmd = &cli.Command{ visAllocatedSectorsCmd, dumpRLESectorCmd, sectorReadCmd, + sectorDeleteCmd, }, } @@ -682,6 +683,90 @@ fr32 padding is removed from the output.`, }, } +var sectorDeleteCmd = &cli.Command{ + Name: "delete", + Usage: "delete a sector file from sector storage", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + }, + }, + ArgsUsage: "[sector num] [file type]", + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 2 { + return xerrors.Errorf("must pass sectornum/filetype") + } + + sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("parsing sector number: %w", err) + } + + var ft storiface.SectorFileType + switch cctx.Args().Get(1) { + case "cache": + ft = storiface.FTCache + case "sealed": + ft = storiface.FTSealed + case "unsealed": + ft = storiface.FTUnsealed + case "update-cache": + ft = storiface.FTUpdateCache + case "update": + ft = storiface.FTUpdate + default: + return xerrors.Errorf("invalid file type") + } + + ctx := lcli.ReqContext(cctx) + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + maddr, err := api.ActorAddress(ctx) + if err != nil { + return xerrors.Errorf("getting miner actor address: %w", err) + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return xerrors.Errorf("getting miner id: %w", err) + } + + sid := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(sectorNum), + } + + // get remote store + sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner) + if err != nil { + return xerrors.Errorf("could not get api info: %w", err) + } + + localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{}) + if err != nil { + return err + } + + if !cctx.Bool("really-do-it") { + return xerrors.Errorf("pass --really-do-it to actually perform the deletion") + } + + remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10, + &paths.DefaultPartialFileHandler{}) + + err = remote.Remove(ctx, sid, ft, true, nil) + if err != nil { + return xerrors.Errorf("removing sector: %w", err) + } + + return nil + }, +} + type emptyLocalStorage struct { } @@ -694,7 +779,6 @@ func (e *emptyLocalStorage) SetStorage(f func(*storiface.StorageConfig)) error { } func (e *emptyLocalStorage) Stat(path string) (fsutil.FsStat, error) { - //TODO implement me panic("don't call") } From 1d0a524b885c285c7c243e2963d890feeeeeecef Mon Sep 17 00:00:00 2001 From: Aayush Date: Wed, 15 Feb 2023 14:17:00 -0500 Subject: [PATCH 23/49] feat: EthAPI: Add EthAddressToFilecoinAddress --- .circleci/config.yml | 5 +++ api/api_full.go | 2 + api/mocks/mock_full.go | 15 +++++++ api/proxy_gen.go | 13 ++++++ build/openrpc/full.json.gz | Bin 33131 -> 33201 bytes build/openrpc/gateway.json.gz | Bin 8485 -> 8483 bytes build/openrpc/miner.json.gz | Bin 16043 -> 16046 bytes build/openrpc/worker.json.gz | Bin 5224 -> 5223 bytes documentation/en/api-v1-unstable-methods.md | 16 +++++++ gateway/node.go | 1 + itests/eth_api_test.go | 47 ++++++++++++++++++++ node/impl/full/dummy.go | 5 +++ node/impl/full/eth.go | 4 ++ 13 files changed, 108 insertions(+) create mode 100644 itests/eth_api_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 2230bfb00..2391a4e92 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -618,6 +618,11 @@ workflows: suite: itest-eth_account_abstraction target: "./itests/eth_account_abstraction_test.go" + - test: + name: test-itest-eth_api + suite: itest-eth_api + target: "./itests/eth_api_test.go" + - test: name: test-itest-eth_balance suite: itest-eth_balance diff --git a/api/api_full.go b/api/api_full.go index 3bd875dc7..c81bb2d6b 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -769,6 +769,8 @@ type FullNode interface { // // EthAccounts will always return [] since we don't expect Lotus to manage private keys EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read + // EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) //perm:read // EthBlockNumber returns the height of the latest (heaviest) TipSet EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read // EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 6e4873715..a5c65f07a 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -953,6 +953,21 @@ func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0) } +// EthAddressToFilecoinAddress mocks base method. +func (m *MockFullNode) EthAddressToFilecoinAddress(arg0 context.Context, arg1 ethtypes.EthAddress) (address.Address, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthAddressToFilecoinAddress", arg0, arg1) + ret0, _ := ret[0].(address.Address) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthAddressToFilecoinAddress indicates an expected call of EthAddressToFilecoinAddress. +func (mr *MockFullNodeMockRecorder) EthAddressToFilecoinAddress(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAddressToFilecoinAddress", reflect.TypeOf((*MockFullNode)(nil).EthAddressToFilecoinAddress), arg0, arg1) +} + // EthBlockNumber mocks base method. func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 2cfaa099a..f04bea2a9 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -244,6 +244,8 @@ type FullNodeMethods struct { EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `perm:"read"` + EthAddressToFilecoinAddress func(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) `perm:"read"` + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"` @@ -2007,6 +2009,17 @@ func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, e return *new([]ethtypes.EthAddress), ErrNotSupported } +func (s *FullNodeStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + if s.Internal.EthAddressToFilecoinAddress == nil { + return *new(address.Address), ErrNotSupported + } + return s.Internal.EthAddressToFilecoinAddress(p0, p1) +} + +func (s *FullNodeStub) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + return *new(address.Address), ErrNotSupported +} + func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { if s.Internal.EthBlockNumber == nil { return *new(ethtypes.EthUint64), ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index dabb581c2497e0d343d2e6e60a77f16f33a092da..06e43869da8a7952e093c3dccc9c1bdc726af3e1 100644 GIT binary patch literal 33201 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 literal 33131 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

tF#jj(7HkY`vS*RWis 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

h-{i7Th)aBuxC+j*` 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 C&Dd7} diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 545fe83cbc154490e171f37c40506cb431851e83..906c69d7a9d619d4dc889a9f7a8d7a70ca4349a5 100644 GIT binary patch delta 13501 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 delta 13519 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 JH=Fev0|3FwRu=#O diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index e5db590da6187c9a79b127d23aea535a8fc93df9..1b44c69bdec0a76c795eda80e5c2e3cb41e7d992 100644 GIT binary patch delta 4083 zcmVL|$7QdJrbvQ_CHh#GTFMe_6TvgbU+_8Il=Ajsb|1Z-O)e1D4! zQuu!1`-ShX;`@inINSGsK?J#wh7Rvve`xg&*IrcEmCr4QcX`pkX7>!6oam5SeN#YD z)ZXGiEP)%Z6*meO4@14)zgFlQ38CQJM1}|(^#yv8(wXn{545inZlxuv{WtebA+~SmhIlE)YFHbX6%v^uI7M z?Z*rIidKa3T>(WA)0b$5nT*I}e<^)G>*F|k_mOD>18zqHH<5^*3)`cCs+`TCWg#*P zwh1v|<@Wu&th7r=OnX6)=f&v2POwYgsLK$8U7k{mAX!BvZV>Ch&CC7Wn=;e^6GIb|RkM z=<1y;g?j}-NPGNqG7e84DYkBuN+Z#>&&mKxtPcyBSSrjeJ|1N%+jM3+x-JW&4*$|F zz1xZjZO)ohtp;Q2XL^D-D3seC{`C0agVdT2Ad8u35_SqWX-3jA>~xC*zUl2yfq54H zuTLw=l1l$WEaiW%KFtmCf8TTT?++h*RlmoM!`gC_OK$Ht8EaggDjCb!T(oUZ(gK;- z@0$rG&|UpX4BKSp%zUSZ271J!6h+N$`=eUm?z7E)1LL3ah+6?8X?f9}3s>X>rd8Ah2- zQOXRtxM5`*IU0?tLFHP?hjcZY51o^#%}Ib*mh8_=lE(?KltpZWy)U=&wk?i}frOGa z@)b&!a78n-XreN6vVYnh-B!ia6g>E!?#a^mjMy%^M4r8Ljm?n)vJ`pnBz;4Ri}}jK z{s()yDzgXI9#hHif5+7$bYeetZ_h5Sz2L7e{$Dq70qzo2Ikrbn9+Z6kGUb@EzxA&rfp!U51ht_7)kBzFb^Or;03nf*#7M z;mjt+(sdD`(y6kRrCvgmkv19)l(;n8XEh2GttTmynvkide+;#u-W#cUOsw9Zrwn@P zP#e@L*{(JvQ#vgnou;ZiRqg9TRf&tIXv%P`_WC_VFC}0nTf#v~LQU8DjsY6XJht9#Pmk10+k-w$J

R2BShU$0_6E6Dr`GiaQ{!xE4 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 delta 4085 zcmV4A z9|<#OlaQdtI5@{nl!M7dmfeRSbrj@ksVWV$Y*qRPqQ;z4k^DTo>^TpyeMY@|c>(D> zd>q||`DpkZ|IIcLCz1ArZHhZ@dP3~O2+CYybtta+&8>6Qu*j9B-Dw*wrFBxslBI}H ze<1o@kWfNg7p?{ASo z3g0h$zwrH)eE)cm?fbtVf?P;LhxaeEfBJ`OFDmTH=a$2}yl7yvdxlL;bjYo~DWE87 zZ*d@&z>U|68-*q8%MOw5|df9hB) zEs72Hw&OtK9+}%(SZBQlkeC31Z!Faudh>34Df3A>VR{ayD|PY{8VG8So;e?^G^h>e zMDy;^!ui|&@gHZovKP+Zlf@LRrkXy*+Hy5mE|IQ2=+auO@(Dy2i0&i0uN_5*{ud^u z{di$t(TY&ME1)Q1`V!4BlM$ILf2HqdeH>@+J~C}!!0l+@CKAzeVS6-Cm9sgtEJS9( zHX$ag+`gZem39ez4PqUb+*xD|ZImG73{GR4 zRij2CvLkBLU^uy=G_upSN9W6Zz{L>7_oDVxIvs6%>=sUB|1~nt0^eT;f6B_zPQ=q2 zUA>c~aIYW;X^($S#^LEB#nz2dX(ZbASs7r7^STo6bx}*JWYU;a}RN zcUv)`%~_MG)nH8hOivI8g>u`&pB_JakXrKrWHA#>!cGAv%}82?oo;c!H@zJyFwf%u z^=U;}Qt5w)rTp*Jr@2A?e|wJp{o#YJ>i5`jSX*v#$?Y8{V~xvGC1W|8i?;1aS|Ahq zeKWxXx~pG_VVlgHneX(_K#zEoqNv$ze^d+HeYV+e+&R8BBHSD8CBg)g*8NK7rW15m&|N`y1>Mb}f4i@jI;PxqhEb+d zlrlpuZdlnyjz;5ZP`Q@!A$6S1htA2=<|IHYOZI0b$>RiA$|5$x-j`c>+ZM;gKtf3y z`3faVxT2X^G*Ov3**|TMZmVKy3LgAV_hjjOMr;>dBF|pB#^y)?S&BS(lD?tE#eC&q z|AReUmDz)9kEvw%f8**AIS|m=cl=VE<;HRdy9-mUoNhtQ$?0OK@Vls zaAp%@>AHwe=~P+EQZFIONE?j?N?e-lvl<18){~S;O~}+!e}>vn?~PPFCRT6IQwBYC zs10hBY*(9-DV>&(PE*yMs`mAvs>H=pG-Wted;OlGmlCj(E#V*~p{8s7@lYFSgY5p( z6A}(|UDf-_Sl1I0s-uxUR(hk+NU2xC!D!eU>%)ORHW?E3+hYKO78<~?)dnzXy#b6{ zZUAdJiVOskf0=-WYS7Sp_wd3&o~=e69}^3nSv&y*wF1HM)jjF_Tc++w&)+I_U(5a{ zq0H?=({%i^fUCQFrEM<%0DDiAfO?obH zOli^!LC2IPz4CKBX(Ha)aZxkN{cmEwcck<+e`Tyr!_jC^zW_G`INhF zlg?-Q|3g;$GsMhUemWuml$NOB_5MRd3{JnqJe4z2N4Yi9i4k!K+rraL&of0&8Yq@snX8rN|{0v7YPxvgZ}YC?s^NnfFvr+W(S$E)__m0TvGE7^xyhH=O5MleyMf_g+8d8X zlMb3{N=G+`s58-!(HX;mI-Keg*oPxYmi|I`HmAYO4qt5pT7E^T>m|-0x$@WD0&QkL zsqG$q@6o2%tZCS;lB~DkjYP?LQ=|r~7jTcm4_1n_;>^v!Fw!sG(8M3+ljZlD91nenz^ji(QAioS|;k|Zd zn9y2*$2lTlx?AD|^#PAUmwLD4Ku@x5bZU5_Z%SNTRf;V%a&>>;YW{ zo7%y}XX%;CURz6+z&md=f3Vp-!=``P#kBHeO)Ep4 z-am`XyxuTg))_W|%c}Pfq0H5J$eMP7G!sUgjIa!7nlAD@WCFY`tqaa6bC6TpT_6)o zRse!OksAOB1ZTF14Djx8j*U6M#Kf$Ltd7OfqS#<>I}SANk-4pffBH*3keC31Z!Fau zdh>34l3ULem=O*X(yAJ+0~I6Fj*&^1Ek)8o+tkuv#-4 zmVwic`Ye<`VJyu@Fyf5HA=GW#F*v)TV8vJmvpwIAG%Oit#X$j!_8qr0t_ zkj!|4rV`aRMc~t|6v0z1GuJi{_LMf4jT-oUI`t4`Bc*f^irHfsT#`kv)0e_L8sM)-&SFf!NOhJIMq3pcLb zFweLmtE${K7Rk%cT$yrSU}T_kGPSvRYozMtSZlm}g0r^6{#(XbV|rYcv2Hl3rpl6^ z`7G$YCm?tSjSf1{*h-0sWNG#rc%)ma{=H{Mmw zH=@yQ;K^C%qKhEsf}Fo(a;}Z{k#pX-&q&Vdr)GqF_4g&M%%>ZR+>AF+ETFZ_LfgQh zvlRIy@=Aet0`XoO;`MXRiDGX3!bR0rq;{EWT9i6$J1H(wlVBKYcyxV9U}8&bxDA;2 z2G*6te@ctkHxoof5S4m}${^?9uNdT3nVs)4SD&EoFu&RyeJ8`SFcUFTZ=u1qftBQF z^h=~B0s{pGzBUXT=A4OF?J&Hl`yU{4;gu5$5e240@xiXb z1$6H{K<8*<70?4Hcz3d~jxPAkrhv{N`v-f#LzH4NyCn;_0uF}$kkEZFLe9Wsh@!a{-a~G3Yks`&*Iar@kV&!|@+UC*zYGNry z5jz{Z&cof_oL2X8K35DC;4`Aon19UZlu~NF&Ccl+6S-^B=BPA{oG$<7v`5YP9xvA6 z2e`#Z0f&0VNKv(_lkktPTEn%xPgw#TI6$}af3*5Nc(;Jg&2E|Q{PSHfZiUMfkwOdB zDsoEZTe*nK--sv8ku%lP`RU56X_mU7<5W5^A%!Onq;r4avfz@un!=9TY7BZ_=xCr3 zm&inh1>HleB3?$G)Bhzp=Kem_zU7Fl(rdzjl*rGr?G)>Ra;VVL#$yN-y`v7)en;0Q zf4$BGntEqqD#J;CJW*9cuZ$LjdoE&G_< zznb9M!(3a8ly|5F#zkwMf~A^Sl8%K}ryKrmT|H>P#^wB9oXDU48f-LV7Xag%5h zcz-6sIaHLK7^2XYImu?2D|@20br1PeFHBNE^THHd>~1GjBRf5LUA24O5RPiSk*-um z(v~V@FDFRpFNo>Cml#n_mE7jz3*gvhJ9GssT7S0s?W&qswsG%)C85{?bdFpEpo;(r nf;BzhE(!5NJVlfTpHis Date: Thu, 16 Feb 2023 10:33:47 -0700 Subject: [PATCH 24/49] support network name overrides in pack to build releases --- Makefile | 2 +- build/actors/pack.sh | 2 +- gen/bundle/bundle.go | 32 +++++++++++++++++++++++++------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 023ca61f5..385ea3482 100644 --- a/Makefile +++ b/Makefile @@ -298,7 +298,7 @@ actors-gen: actors-code-gen fiximports .PHONY: actors-gen bundle-gen: - $(GOCC) run ./gen/bundle $(RELEASE) + $(GOCC) run ./gen/bundle $(RELEASE) $(RELEASE_OVERRIDES) $(GOCC) fmt ./build/... .PHONY: bundle-gen diff --git a/build/actors/pack.sh b/build/actors/pack.sh index 863a3c5c7..b8d2bdb3d 100755 --- a/build/actors/pack.sh +++ b/build/actors/pack.sh @@ -52,4 +52,4 @@ popd echo "Generating metadata..." -make -C ../../ RELEASE="$RELEASE" bundle-gen +make -C ../../ RELEASE="$RELEASE" RELEASE_OVERRIDES="${RELEASE_OVERRIDES[*]}" bundle-gen diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index d953b99c9..da38f192f 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -2,6 +2,7 @@ package main import ( "os" + "strings" "text/template" "github.com/filecoin-project/lotus/build" @@ -32,19 +33,36 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet } `)) +func splitOverride(override string) (string, string) { + x := strings.Split(override, "=") + return x[0], x[1] +} + func main() { metadata, err := build.ReadEmbeddedBuiltinActorsMetadata() if err != nil { panic(err) } - // TODO: Re-enable this when we can set the tag for ONLY the appropriate version - // https://github.com/filecoin-project/lotus/issues/10185#issuecomment-1422864836 - //if len(os.Args) > 1 { - // for _, m := range metadata { - // m.BundleGitTag = os.Args[1] - // } - //} + // see ./build/actors/pack.sh + // expected args are git bundle tag then number of per network overrides + // overrides are in the format network_name=override + overrides := map[string]string{} + for _, override := range os.Args[2:] { + network, version := splitOverride(override) + overrides[network] = version + } + + if len(os.Args) > 1 { + for _, m := range metadata { + override, ok := overrides[m.Network] + if ok { + m.BundleGitTag = override + } else { + m.BundleGitTag = os.Args[1] + } + } + } fi, err := os.Create("./build/builtin_actors_gen.go") if err != nil { From 16b7d4525fe7cd7ba938658bb70746b365c89f0d Mon Sep 17 00:00:00 2001 From: mike seiler Date: Thu, 16 Feb 2023 10:40:16 -0700 Subject: [PATCH 25/49] lintfix --- gen/bundle/bundle.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index da38f192f..e369fd3dc 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -44,9 +44,9 @@ func main() { panic(err) } - // see ./build/actors/pack.sh - // expected args are git bundle tag then number of per network overrides - // overrides are in the format network_name=override + // see ./build/actors/pack.sh + // expected args are git bundle tag then number of per network overrides + // overrides are in the format network_name=override overrides := map[string]string{} for _, override := range os.Args[2:] { network, version := splitOverride(override) From ea03e1b6e70969e3c4bc7194bdf12b4b2aac7a45 Mon Sep 17 00:00:00 2001 From: mike seiler Date: Thu, 16 Feb 2023 13:10:25 -0700 Subject: [PATCH 26/49] only override the correct version for bundle gen --- gen/bundle/bundle.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index e369fd3dc..908ef57e8 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" "strings" "text/template" @@ -56,7 +57,7 @@ func main() { if len(os.Args) > 1 { for _, m := range metadata { override, ok := overrides[m.Network] - if ok { + if ok && strings.HasPrefix(override, fmt.Sprintf("v%d", m.Version)) { m.BundleGitTag = override } else { m.BundleGitTag = os.Args[1] From 0f6cbf1be25aa2d255051fcdc0b2e1d280910174 Mon Sep 17 00:00:00 2001 From: mike seiler Date: Thu, 16 Feb 2023 14:01:45 -0700 Subject: [PATCH 27/49] include the version that pack is running on for filtering the build gen metadata --- Makefile | 2 +- build/actors/pack.sh | 2 +- gen/bundle/bundle.go | 30 ++++++++++++++++++++---------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 385ea3482..d1e7d159a 100644 --- a/Makefile +++ b/Makefile @@ -298,7 +298,7 @@ actors-gen: actors-code-gen fiximports .PHONY: actors-gen bundle-gen: - $(GOCC) run ./gen/bundle $(RELEASE) $(RELEASE_OVERRIDES) + $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) $(GOCC) fmt ./build/... .PHONY: bundle-gen diff --git a/build/actors/pack.sh b/build/actors/pack.sh index b8d2bdb3d..e594bb2da 100755 --- a/build/actors/pack.sh +++ b/build/actors/pack.sh @@ -52,4 +52,4 @@ popd echo "Generating metadata..." -make -C ../../ RELEASE="$RELEASE" RELEASE_OVERRIDES="${RELEASE_OVERRIDES[*]}" bundle-gen +make -C ../../ VERSION="$VERSION" RELEASE="$RELEASE" RELEASE_OVERRIDES="${RELEASE_OVERRIDES[*]}" bundle-gen diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index 908ef57e8..a1eab4e04 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -45,24 +45,34 @@ func main() { panic(err) } + var metadataSpecificVersion []*build.BuiltinActorsMetadata + // see ./build/actors/pack.sh // expected args are git bundle tag then number of per network overrides // overrides are in the format network_name=override - overrides := map[string]string{} - for _, override := range os.Args[2:] { - network, version := splitOverride(override) - overrides[network] = version - } if len(os.Args) > 1 { + version := os.Args[1] + overrides := map[string]string{} + for _, override := range os.Args[3:] { + k, v := splitOverride(override) + overrides[k] = v + } for _, m := range metadata { - override, ok := overrides[m.Network] - if ok && strings.HasPrefix(override, fmt.Sprintf("v%d", m.Version)) { - m.BundleGitTag = override - } else { - m.BundleGitTag = os.Args[1] + if strings.HasPrefix(version, fmt.Sprintf("v%d", m.Version)) { + // correct version + override, ok := overrides[m.Network] + if ok { + m.BundleGitTag = override + } else { + m.BundleGitTag = os.Args[2] + } + fmt.Println("hi") + metadataSpecificVersion = append(metadataSpecificVersion, m) } } + metadata = metadataSpecificVersion + } fi, err := os.Create("./build/builtin_actors_gen.go") From 5854d72784eeb4eba464d7d650e00236228d12da Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 16 Feb 2023 16:36:52 -0800 Subject: [PATCH 28/49] fix: eth: correctly decode EthGetStorageAt output (#10284) * fix: eth: correctly decode EthGetStorageAt output We cbor-encode it. Also: 1. Actually use the passed block param. 2. Check if the target actor is an EVM actor to avoid nonsense outputs. fixes https://github.com/filecoin-project/ref-fvm/issues/1621 --- itests/fevm_test.go | 14 ++++++++++++++ node/impl/full/eth.go | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 3018bf63d..cf70faba2 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -265,6 +265,20 @@ func TestFEVMDelegateCall(t *testing.T) { expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) require.Equal(t, result, expectedResultActor) + + // The implementation's storage should not have been updated. + actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr) + require.NoError(t, err) + value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value) + + // The storage actor's storage _should_ have been updated + storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr) + require.NoError(t, err) + value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthBytes(expectedResult), value) } // TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert. diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index e30fe4da1..3fc6c6940 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -510,13 +510,18 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, } func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return nil, xerrors.Errorf("cannot parse block param: %s", blkParam) + } + l := len(position) if l > 32 { return nil, fmt.Errorf("supplied storage key is too long") } // pad with zero bytes if smaller than 32 bytes - position = append(make([]byte, 32-l, 32-l), position...) + position = append(make([]byte, 32-l, 32), position...) to, err := ethAddr.ToFilecoinAddress() if err != nil { @@ -529,6 +534,18 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd return nil, fmt.Errorf("failed to construct system sender address: %w", err) } + actor, err := a.StateManager.LoadActor(ctx, to, ts) + if err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return ethtypes.EthBytes(make([]byte, 32)), nil + } + return nil, xerrors.Errorf("failed to lookup contract %s: %w", ethAddr, err) + } + + if !builtinactors.IsEvmActor(actor.Code) { + return ethtypes.EthBytes(make([]byte, 32)), nil + } + params, err := actors.SerializeParams(&evm.GetStorageAtParams{ StorageKey: *(*[32]byte)(position), }) @@ -547,8 +564,6 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd GasPremium: big.Zero(), } - ts := a.Chain.GetHeaviestTipSet() - // Try calling until we find a height with no migration. var res *api.InvocResult for { @@ -567,10 +582,22 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd } if res.MsgRct == nil { - return nil, fmt.Errorf("no message receipt") + return nil, xerrors.Errorf("no message receipt") } - return res.MsgRct.Return, nil + if res.MsgRct.ExitCode.IsError() { + return nil, xerrors.Errorf("failed to lookup storage slot: %s", res.Error) + } + + var ret abi.CborBytes + if err := ret.UnmarshalCBOR(bytes.NewReader(res.MsgRct.Return)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal storage slot: %w", err) + } + + // pad with zero bytes if smaller than 32 bytes + ret = append(make([]byte, 32-len(ret), 32), ret...) + + return ethtypes.EthBytes(ret), nil } func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { From b2610bed52ce8e1b809cc34daaf112ddbd673fac Mon Sep 17 00:00:00 2001 From: mike seiler Date: Thu, 16 Feb 2023 17:55:04 -0700 Subject: [PATCH 29/49] change rpc types from uint to hash to match fevm implementation --- itests/specs/eth_openrpc.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/itests/specs/eth_openrpc.json b/itests/specs/eth_openrpc.json index 1947bbd32..0f354b5c7 100644 --- a/itests/specs/eth_openrpc.json +++ b/itests/specs/eth_openrpc.json @@ -1794,9 +1794,9 @@ "result": { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } }, @@ -1807,9 +1807,9 @@ "result": { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } }, @@ -1820,9 +1820,9 @@ "result": { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } }, @@ -1833,9 +1833,9 @@ { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } ], @@ -1853,9 +1853,9 @@ { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } ], @@ -1954,9 +1954,9 @@ { "name": "Filter Identifier", "schema": { - "title": "hex encoded unsigned integer", + "title": "32 byte hex value", "type": "string", - "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + "pattern": "^0x[0-9a-f]{64}$" } } ], From 00b6d060411c9230265206cfac1a6e557dce7f95 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 16 Feb 2023 17:18:03 -0800 Subject: [PATCH 30/49] feat: eth: parse revert data (#10295) We don't really want to do this in the FVM because it's Ethereum specific, but this makes sense to do in the Ethereum API. See: See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require --- chain/types/ethtypes/eth_types.go | 33 +++++++++--- itests/contracts/Errors.hex | 1 + itests/contracts/Errors.sol | 24 +++++++++ itests/fevm_test.go | 30 +++++++++++ node/impl/full/eth.go | 84 ++++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 itests/contracts/Errors.hex create mode 100644 itests/contracts/Errors.sol diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 1539a638b..006ffffdc 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -66,6 +66,18 @@ func EthUint64FromHex(s string) (EthUint64, error) { return EthUint64(parsedInt), nil } +// Parse a uint64 from big-endian encoded bytes. +func EthUint64FromBytes(b []byte) (EthUint64, error) { + if len(b) != 32 { + return 0, xerrors.Errorf("eth int must be 32 bytes long") + } + var zeros [32 - 8]byte + if !bytes.Equal(b[:len(zeros)], zeros[:]) { + return 0, xerrors.Errorf("eth int overflows 64 bits") + } + return EthUint64(binary.BigEndian.Uint64(b[len(zeros):])), nil +} + func (e EthUint64) Hex() string { if e == 0 { return "0x0" @@ -78,11 +90,15 @@ type EthBigInt big.Int var EthBigIntZero = EthBigInt{Int: big.Zero().Int} -func (e EthBigInt) MarshalJSON() ([]byte, error) { +func (e EthBigInt) String() string { if e.Int == nil || e.Int.BitLen() == 0 { - return json.Marshal("0x0") + return "0x0" } - return json.Marshal(fmt.Sprintf("0x%x", e.Int)) + return fmt.Sprintf("0x%x", e.Int) +} + +func (e EthBigInt) MarshalJSON() ([]byte, error) { + return json.Marshal(e.String()) } func (e *EthBigInt) UnmarshalJSON(b []byte) error { @@ -106,12 +122,15 @@ func (e *EthBigInt) UnmarshalJSON(b []byte) error { // EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x". type EthBytes []byte -func (e EthBytes) MarshalJSON() ([]byte, error) { +func (e EthBytes) String() string { if len(e) == 0 { - return json.Marshal("0x") + return "0x" } - s := hex.EncodeToString(e) - return json.Marshal("0x" + s) + return "0x" + hex.EncodeToString(e) +} + +func (e EthBytes) MarshalJSON() ([]byte, error) { + return json.Marshal(e.String()) } func (e *EthBytes) UnmarshalJSON(b []byte) error { diff --git a/itests/contracts/Errors.hex b/itests/contracts/Errors.hex new file mode 100644 index 000000000..64e4ea6df --- /dev/null +++ b/itests/contracts/Errors.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506102de806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630abe88b61461005c57806358d4cbce1461006657806359be8c55146100705780638791bd331461007a578063c6dbcf2e14610084575b600080fd5b61006461008e565b005b61006e61009f565b005b6100786100a4565b005b6100826100df565b005b61008c610111565b005b600061009d5761009c61012a565b5b565b600080fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100d6906101b6565b60405180910390fd5b6040517f09caebf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001905060008082610125919061023e565b505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082825260208201905092915050565b7f6d7920726561736f6e0000000000000000000000000000000000000000000000600082015250565b60006101a0600983610159565b91506101ab8261016a565b602082019050919050565b600060208201905081810360008301526101cf81610193565b9050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610249826101d6565b9150610254836101d6565b925082610264576102636101e0565b5b600160000383147f80000000000000000000000000000000000000000000000000000000000000008314161561029d5761029c61020f565b5b82820590509291505056fea26469706673582212207815355e9e7ced2b8168a953c364e82871c0fe326602bbb9106e6551aea673ed64736f6c63430008120033 \ No newline at end of file diff --git a/itests/contracts/Errors.sol b/itests/contracts/Errors.sol new file mode 100644 index 000000000..f9bcfbce2 --- /dev/null +++ b/itests/contracts/Errors.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract Errors { + error CustomError(); + + function failRevertEmpty() public { + revert(); + } + function failRevertReason() public { + revert("my reason"); + } + function failAssert() public { + assert(false); + } + function failDivZero() public { + int a = 1; + int b = 0; + a / b; + } + function failCustom() public { + revert CustomError(); + } +} diff --git a/itests/fevm_test.go b/itests/fevm_test.go index cf70faba2..d9c0019de 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -882,3 +882,33 @@ func TestFEVMGetBlockDifficulty(t *testing.T) { require.NoError(t, err) require.Equal(t, len(ret), 32) } + +func TestFEVMErrorParsing(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + e := client.EVM() + + _, contractAddr := e.DeployContractFromFilename(ctx, "contracts/Errors.hex") + contractAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr) + require.NoError(t, err) + customError := ethtypes.EthBytes(kit.CalcFuncSignature("CustomError()")).String() + for sig, expected := range map[string]string{ + "failRevertEmpty()": "none", + "failRevertReason()": "Error(my reason)", + "failAssert()": "Assert()", + "failDivZero()": "DivideByZero()", + "failCustom()": customError, + } { + sig := sig + expected := expected + t.Run(sig, func(t *testing.T) { + entryPoint := kit.CalcFuncSignature(sig) + _, err := e.EthCall(ctx, ethtypes.EthCall{ + To: &contractAddrEth, + Data: entryPoint, + }, "latest") + require.ErrorContains(t, err, fmt.Sprintf("exit 33, revert reason: %s, vm error", expected)) + }) + } +} diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 3fc6c6940..454b3eca5 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -871,7 +871,8 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk ty return nil, xerrors.Errorf("CallWithGas failed: %w", err) } if res.MsgRct.ExitCode.IsError() { - return nil, xerrors.Errorf("message execution failed: exit %s, msg receipt: %s, reason: %s", res.MsgRct.ExitCode, res.MsgRct.Return, res.Error) + reason := parseEthRevert(res.MsgRct.Return) + return nil, xerrors.Errorf("message execution failed: exit %s, revert reason: %s, vm error: %s", res.MsgRct.ExitCode, reason, res.Error) } return res, nil } @@ -1032,7 +1033,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s invokeResult, err := a.applyMessage(ctx, msg, ts.Key()) if err != nil { - return nil, xerrors.Errorf("failed to apply message: %w", err) + return nil, err } if msg.To == builtintypes.EthereumAddressManagerActorAddr { @@ -2211,6 +2212,85 @@ func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) { return keys, nil } +const errorFunctionSelector = "\x08\xc3\x79\xa0" // Error(string) +const panicFunctionSelector = "\x4e\x48\x7b\x71" // Panic(uint256) +// Eth ABI (solidity) panic codes. +var panicErrorCodes map[uint64]string = map[uint64]string{ + 0x00: "Panic()", + 0x01: "Assert()", + 0x11: "ArithmeticOverflow()", + 0x12: "DivideByZero()", + 0x21: "InvalidEnumVariant()", + 0x22: "InvalidStorageArray()", + 0x31: "PopEmptyArray()", + 0x32: "ArrayIndexOutOfBounds()", + 0x41: "OutOfMemory()", + 0x51: "CalledUninitializedFunction()", +} + +// Parse an ABI encoded revert reason. This reason should be encoded as if it were the parameters to +// an `Error(string)` function call. +// +// See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require +func parseEthRevert(ret []byte) string { + if len(ret) == 0 { + return "none" + } + var cbytes abi.CborBytes + if err := cbytes.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { + return "ERROR: revert reason is not cbor encoded bytes" + } + if len(cbytes) == 0 { + return "none" + } + // If it's not long enough to contain an ABI encoded response, return immediately. + if len(cbytes) < 4+32 { + return ethtypes.EthBytes(cbytes).String() + } + switch string(cbytes[:4]) { + case panicFunctionSelector: + cbytes := cbytes[4 : 4+32] + // Read the and check the code. + code, err := ethtypes.EthUint64FromBytes(cbytes) + if err != nil { + // If it's too big, just return the raw value. + codeInt := big.PositiveFromUnsignedBytes(cbytes) + return fmt.Sprintf("Panic(%s)", ethtypes.EthBigInt(codeInt).String()) + } + if s, ok := panicErrorCodes[uint64(code)]; ok { + return s + } + return fmt.Sprintf("Panic(0x%x)", code) + case errorFunctionSelector: + cbytes := cbytes[4:] + cbytesLen := ethtypes.EthUint64(len(cbytes)) + // Read the and check the offset. + offset, err := ethtypes.EthUint64FromBytes(cbytes[:32]) + if err != nil { + break + } + if cbytesLen < offset { + break + } + + // Read and check the length. + if cbytesLen-offset < 32 { + break + } + start := offset + 32 + length, err := ethtypes.EthUint64FromBytes(cbytes[offset : offset+32]) + if err != nil { + break + } + if cbytesLen-start < length { + break + } + // Slice the error message. + return fmt.Sprintf("Error(%s)", cbytes[start:start+length]) + } + return ethtypes.EthBytes(cbytes).String() +} + func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) { var totalGasUsed uint64 for _, tx := range txGasRewards { From ccdb4470853a99f57cbaacff2675168ba2c0f3a8 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 16 Feb 2023 23:58:16 -0500 Subject: [PATCH 31/49] avoid actor not found --- cli/evm.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cli/evm.go b/cli/evm.go index 2169a3486..7aee5d838 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -8,6 +8,8 @@ import ( "fmt" "os" + "github.com/filecoin-project/specs-actors/v8/actors/builtin" + "github.com/urfave/cli/v2" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -75,13 +77,18 @@ var EvmGetInfoCmd = &cli.Command{ } actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK) - if err != nil { - return err - } - fmt.Println("Filecoin address: ", faddr) fmt.Println("Eth address: ", eaddr) - fmt.Println("Code cid: ", actor.Code.String()) + if err != nil { + fmt.Printf("Actor lookup failed for faddr %s with error: %s\n", faddr, err) + } else { + idAddr, err := api.StateLookupID(ctx, faddr, types.EmptyTSK) + if err == nil { + fmt.Println("ID address: ", idAddr) + fmt.Println("Code cid: ", actor.Code.String()) + fmt.Println("Actor Type: ", builtin.ActorNameByCode(actor.Code)) + } + } return nil }, From f2648adee8bd3a5de63bb04ad8a610cffdbf51a9 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Fri, 17 Feb 2023 00:11:07 -0500 Subject: [PATCH 32/49] fix import --- cli/evm.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/evm.go b/cli/evm.go index 7aee5d838..e1c4d7b93 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -8,8 +8,7 @@ import ( "fmt" "os" - "github.com/filecoin-project/specs-actors/v8/actors/builtin" - + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/urfave/cli/v2" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" From 59db4eeacd9931a8956c00308a87112ffb4b0cc6 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Fri, 17 Feb 2023 00:21:29 -0500 Subject: [PATCH 33/49] fix gen --- cli/evm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/evm.go b/cli/evm.go index e1c4d7b93..d153e7212 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -8,7 +8,6 @@ import ( "fmt" "os" - "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/urfave/cli/v2" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -22,6 +21,7 @@ import ( "github.com/filecoin-project/lotus/api/v0api" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" ) From d589443a5e0ab3bfc40a569146329369f2631e14 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 17 Feb 2023 12:16:09 -0500 Subject: [PATCH 34/49] feat: EthApiTest: Confirm EthAddressToFilecoinAddress works without EthRPC (#10302) --- itests/eth_api_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/itests/eth_api_test.go b/itests/eth_api_test.go index 39026637f..63c6aa5a2 100644 --- a/itests/eth_api_test.go +++ b/itests/eth_api_test.go @@ -16,7 +16,8 @@ import ( ) func TestEthAddressToFilecoinAddress(t *testing.T) { - client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + // Disable EthRPC to confirm that this method does NOT need the EthEnableRPC config set to true + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC()) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() From 2d3065ae8eb904ad89c7df5b5b96f757735a870f Mon Sep 17 00:00:00 2001 From: Jorropo Date: Thu, 26 Jan 2023 16:41:28 +0100 Subject: [PATCH 35/49] chore: all: bump go-libipfs to replace go-block-format Includes changes from: - https://github.com/ipfs/go-block-format/pull/37 - https://github.com/ipfs/go-libipfs/pull/58 (cherry picked from commit f572852d06aa73e54193d053601ab879642638f7) --- api/api_full.go | 2 +- api/api_gateway.go | 2 +- api/docgen/docgen.go | 2 +- api/mocks/mock_full.go | 2 +- api/proxy_gen.go | 2 +- api/v0api/full.go | 2 +- api/v0api/gateway.go | 2 +- api/v0api/proxy_gen.go | 2 +- api/v0api/v0mocks/mock_full.go | 2 +- blockstore/api.go | 2 +- blockstore/autobatch.go | 2 +- blockstore/badger/blockstore.go | 2 +- blockstore/badger/blockstore_test.go | 2 +- blockstore/badger/blockstore_test_suite.go | 2 +- blockstore/buffered.go | 2 +- blockstore/discard.go | 2 +- blockstore/fallback.go | 2 +- blockstore/idstore.go | 2 +- blockstore/ipfs.go | 2 +- blockstore/mem.go | 2 +- blockstore/mem_test.go | 2 +- blockstore/net.go | 2 +- blockstore/net_serve.go | 2 +- blockstore/net_test.go | 2 +- blockstore/splitstore/debug.go | 2 +- blockstore/splitstore/splitstore.go | 2 +- blockstore/splitstore/splitstore_compact.go | 2 +- blockstore/splitstore/splitstore_expose.go | 2 +- blockstore/splitstore/splitstore_reify.go | 2 +- blockstore/splitstore/splitstore_test.go | 2 +- blockstore/splitstore/splitstore_warmup.go | 2 +- blockstore/sync.go | 2 +- blockstore/timed.go | 2 +- blockstore/timed_test.go | 2 +- blockstore/union.go | 2 +- blockstore/union_test.go | 2 +- chain/events/state/mock/api.go | 2 +- chain/gen/genesis/genblock.go | 2 +- chain/store/messages.go | 2 +- chain/store/snapshot.go | 2 +- chain/store/store.go | 2 +- chain/sub/incoming.go | 2 +- chain/sub/incoming_test.go | 2 +- chain/sync.go | 2 +- chain/types/blockheader.go | 2 +- chain/types/message.go | 2 +- chain/types/signedmessage.go | 2 +- chain/types/tipset_key.go | 2 +- chain/vm/vm.go | 2 +- cmd/lotus-shed/datastore-vlog.go | 2 +- cmd/lotus-shed/export.go | 2 +- cmd/lotus-shed/import-car.go | 2 +- cmd/tvx/stores.go | 2 +- conformance/runner.go | 2 +- gateway/node.go | 2 +- gateway/proxy_fil.go | 2 +- go.mod | 9 +++++---- go.sum | 19 ++++++++++++------- .../deals_partial_retrieval_dm-level_test.go | 2 +- itests/deals_partial_retrieval_test.go | 2 +- markets/dagstore/blockstore.go | 2 +- markets/storageadapter/api.go | 2 +- .../ondealsectorcommitted_test.go | 2 +- node/impl/full/chain.go | 2 +- 64 files changed, 79 insertions(+), 73 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index c81bb2d6b..e7a2d289e 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -7,8 +7,8 @@ import ( "time" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/peer" "github.com/filecoin-project/go-address" diff --git a/api/api_gateway.go b/api/api_gateway.go index aea6fc3d1..2e877fb1a 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -3,8 +3,8 @@ package api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 606ae9d8e..65d71d208 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -14,9 +14,9 @@ import ( "unicode" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-graphsync" + blocks "github.com/ipfs/go-libipfs/blocks" textselector "github.com/ipld/go-ipld-selector-text-lite" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/metrics" diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index a5c65f07a..f49e912a2 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -12,8 +12,8 @@ import ( gomock "github.com/golang/mock/gomock" uuid "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" metrics "github.com/libp2p/go-libp2p/core/metrics" network0 "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" diff --git a/api/proxy_gen.go b/api/proxy_gen.go index f04bea2a9..baf433735 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -8,8 +8,8 @@ import ( "time" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/metrics" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" diff --git a/api/v0api/full.go b/api/v0api/full.go index 87d5cba4e..490cd73c8 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -3,8 +3,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" textselector "github.com/ipld/go-ipld-selector-text-lite" "github.com/libp2p/go-libp2p/core/peer" diff --git a/api/v0api/gateway.go b/api/v0api/gateway.go index bd55917c7..674371c14 100644 --- a/api/v0api/gateway.go +++ b/api/v0api/gateway.go @@ -3,8 +3,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index 4acf2e111..5fa0d949c 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -5,8 +5,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/peer" "golang.org/x/xerrors" diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 3aff979ff..619f19d35 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -11,8 +11,8 @@ import ( gomock "github.com/golang/mock/gomock" uuid "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" metrics "github.com/libp2p/go-libp2p/core/metrics" network0 "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" diff --git a/blockstore/api.go b/blockstore/api.go index 090f53e5a..251deb13a 100644 --- a/blockstore/api.go +++ b/blockstore/api.go @@ -3,8 +3,8 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/autobatch.go b/blockstore/autobatch.go index d41d521ef..3cb8eafa6 100644 --- a/blockstore/autobatch.go +++ b/blockstore/autobatch.go @@ -5,9 +5,9 @@ import ( "sync" "time" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/badger/blockstore.go b/blockstore/badger/blockstore.go index 050ed6d3b..da4f9f67d 100644 --- a/blockstore/badger/blockstore.go +++ b/blockstore/badger/blockstore.go @@ -13,9 +13,9 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/dgraph-io/badger/v2/options" "github.com/dgraph-io/badger/v2/pb" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logger "github.com/ipfs/go-log/v2" pool "github.com/libp2p/go-buffer-pool" "github.com/multiformats/go-base32" diff --git a/blockstore/badger/blockstore_test.go b/blockstore/badger/blockstore_test.go index a14515796..fc81be43e 100644 --- a/blockstore/badger/blockstore_test.go +++ b/blockstore/badger/blockstore_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" diff --git a/blockstore/badger/blockstore_test_suite.go b/blockstore/badger/blockstore_test_suite.go index 7db155901..877eb6e6b 100644 --- a/blockstore/badger/blockstore_test_suite.go +++ b/blockstore/badger/blockstore_test_suite.go @@ -9,10 +9,10 @@ import ( "strings" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" u "github.com/ipfs/go-ipfs-util" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/blockstore" diff --git a/blockstore/buffered.go b/blockstore/buffered.go index dbee095a2..e089ed561 100644 --- a/blockstore/buffered.go +++ b/blockstore/buffered.go @@ -4,9 +4,9 @@ import ( "context" "os" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" ) // buflog is a logger for the buffered blockstore. It is subscoped from the diff --git a/blockstore/discard.go b/blockstore/discard.go index a8e6cfec7..7f1a76a22 100644 --- a/blockstore/discard.go +++ b/blockstore/discard.go @@ -4,8 +4,8 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" ) var _ Blockstore = (*discardstore)(nil) diff --git a/blockstore/fallback.go b/blockstore/fallback.go index de948b346..9fab960f5 100644 --- a/blockstore/fallback.go +++ b/blockstore/fallback.go @@ -5,9 +5,9 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/idstore.go b/blockstore/idstore.go index 23b85146a..a0ecec5f0 100644 --- a/blockstore/idstore.go +++ b/blockstore/idstore.go @@ -4,8 +4,8 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" mh "github.com/multiformats/go-multihash" "golang.org/x/xerrors" ) diff --git a/blockstore/ipfs.go b/blockstore/ipfs.go index 41c2b8710..756314f2d 100644 --- a/blockstore/ipfs.go +++ b/blockstore/ipfs.go @@ -5,9 +5,9 @@ import ( "context" "io/ioutil" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" httpapi "github.com/ipfs/go-ipfs-http-client" + blocks "github.com/ipfs/go-libipfs/blocks" iface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" diff --git a/blockstore/mem.go b/blockstore/mem.go index 7cfefafd7..05da287c5 100644 --- a/blockstore/mem.go +++ b/blockstore/mem.go @@ -3,9 +3,9 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" ) // NewMemory returns a temporary memory-backed blockstore. diff --git a/blockstore/mem_test.go b/blockstore/mem_test.go index 4d4a77624..6a5e0d2d1 100644 --- a/blockstore/mem_test.go +++ b/blockstore/mem_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" ) diff --git a/blockstore/net.go b/blockstore/net.go index 77da764a5..a6b008af2 100644 --- a/blockstore/net.go +++ b/blockstore/net.go @@ -8,9 +8,9 @@ import ( "sync" "sync/atomic" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/blockstore/net_serve.go b/blockstore/net_serve.go index 2540c845e..b58d2a5fd 100644 --- a/blockstore/net_serve.go +++ b/blockstore/net_serve.go @@ -5,9 +5,9 @@ import ( "context" "encoding/binary" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/blockstore/net_test.go b/blockstore/net_test.go index d8c33818e..6c3060a98 100644 --- a/blockstore/net_test.go +++ b/blockstore/net_test.go @@ -6,8 +6,8 @@ import ( "io" "testing" - block "github.com/ipfs/go-block-format" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" "github.com/stretchr/testify/require" ) diff --git a/blockstore/splitstore/debug.go b/blockstore/splitstore/debug.go index f059ae4ce..c870a44e1 100644 --- a/blockstore/splitstore/debug.go +++ b/blockstore/splitstore/debug.go @@ -12,8 +12,8 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "go.uber.org/multierr" "golang.org/x/xerrors" ) diff --git a/blockstore/splitstore/splitstore.go b/blockstore/splitstore/splitstore.go index dee6e784c..0afb15c11 100644 --- a/blockstore/splitstore/splitstore.go +++ b/blockstore/splitstore/splitstore.go @@ -8,10 +8,10 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" dstore "github.com/ipfs/go-datastore" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/stats" "go.uber.org/multierr" diff --git a/blockstore/splitstore/splitstore_compact.go b/blockstore/splitstore/splitstore_compact.go index 6ffb35726..0422736f0 100644 --- a/blockstore/splitstore/splitstore_compact.go +++ b/blockstore/splitstore/splitstore_compact.go @@ -10,9 +10,9 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/stats" "golang.org/x/sync/errgroup" diff --git a/blockstore/splitstore/splitstore_expose.go b/blockstore/splitstore/splitstore_expose.go index ff9bf1f71..d092fbb9b 100644 --- a/blockstore/splitstore/splitstore_expose.go +++ b/blockstore/splitstore/splitstore_expose.go @@ -4,9 +4,9 @@ import ( "context" "errors" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" bstore "github.com/filecoin-project/lotus/blockstore" ) diff --git a/blockstore/splitstore/splitstore_reify.go b/blockstore/splitstore/splitstore_reify.go index 9db480b8c..aa14f090a 100644 --- a/blockstore/splitstore/splitstore_reify.go +++ b/blockstore/splitstore/splitstore_reify.go @@ -5,8 +5,8 @@ import ( "runtime" "sync/atomic" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/splitstore/splitstore_test.go b/blockstore/splitstore/splitstore_test.go index 750a2efed..c97a9d01c 100644 --- a/blockstore/splitstore/splitstore_test.go +++ b/blockstore/splitstore/splitstore_test.go @@ -11,11 +11,11 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-datastore/sync" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" diff --git a/blockstore/splitstore/splitstore_warmup.go b/blockstore/splitstore/splitstore_warmup.go index e387263da..23bbad7ca 100644 --- a/blockstore/splitstore/splitstore_warmup.go +++ b/blockstore/splitstore/splitstore_warmup.go @@ -5,9 +5,9 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" diff --git a/blockstore/sync.go b/blockstore/sync.go index 1b4ad8297..4f97027ae 100644 --- a/blockstore/sync.go +++ b/blockstore/sync.go @@ -4,8 +4,8 @@ import ( "context" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" ) // NewMemorySync returns a thread-safe in-memory blockstore. diff --git a/blockstore/timed.go b/blockstore/timed.go index 38f4e51f3..dda2e1958 100644 --- a/blockstore/timed.go +++ b/blockstore/timed.go @@ -6,9 +6,9 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/raulk/clock" "go.uber.org/multierr" ) diff --git a/blockstore/timed_test.go b/blockstore/timed_test.go index 931f14507..fb3aa00c9 100644 --- a/blockstore/timed_test.go +++ b/blockstore/timed_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/raulk/clock" "github.com/stretchr/testify/require" ) diff --git a/blockstore/union.go b/blockstore/union.go index 71e785f1a..3372cd20c 100644 --- a/blockstore/union.go +++ b/blockstore/union.go @@ -3,9 +3,9 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" ) type unionBlockstore []Blockstore diff --git a/blockstore/union_test.go b/blockstore/union_test.go index 579489947..47aab852a 100644 --- a/blockstore/union_test.go +++ b/blockstore/union_test.go @@ -5,7 +5,7 @@ import ( "context" "testing" - blocks "github.com/ipfs/go-block-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" ) diff --git a/chain/events/state/mock/api.go b/chain/events/state/mock/api.go index cdec42659..680e304f5 100644 --- a/chain/events/state/mock/api.go +++ b/chain/events/state/mock/api.go @@ -4,8 +4,8 @@ import ( "context" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/chain/gen/genesis/genblock.go b/chain/gen/genesis/genblock.go index f26659cdf..930b3ccff 100644 --- a/chain/gen/genesis/genblock.go +++ b/chain/gen/genesis/genblock.go @@ -3,8 +3,8 @@ package genesis import ( "encoding/hex" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/multiformats/go-multihash" ) diff --git a/chain/store/messages.go b/chain/store/messages.go index 1ee1f8ad4..5ac62d394 100644 --- a/chain/store/messages.go +++ b/chain/store/messages.go @@ -3,10 +3,10 @@ package store import ( "context" - 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" + block "github.com/ipfs/go-libipfs/blocks" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/chain/store/snapshot.go b/chain/store/snapshot.go index e90a60611..36435152e 100644 --- a/chain/store/snapshot.go +++ b/chain/store/snapshot.go @@ -5,8 +5,8 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" carutil "github.com/ipld/go-car/util" carv2 "github.com/ipld/go-car/v2" diff --git a/chain/store/store.go b/chain/store/store.go index 2773f1ad3..754e3a123 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -12,11 +12,11 @@ import ( "time" lru "github.com/hashicorp/golang-lru" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" dstore "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/query" cbor "github.com/ipfs/go-ipld-cbor" + block "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/stats" "go.opencensus.io/trace" diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index b8427e036..4c7d16a9a 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -8,9 +8,9 @@ import ( "time" lru "github.com/hashicorp/golang-lru" - blocks "github.com/ipfs/go-block-format" bserv "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/connmgr" diff --git a/chain/sub/incoming_test.go b/chain/sub/incoming_test.go index 8566391b9..d17b08825 100644 --- a/chain/sub/incoming_test.go +++ b/chain/sub/incoming_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/golang/mock/gomock" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" pubsub "github.com/libp2p/go-libp2p-pubsub" pb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/peer" diff --git a/chain/sync.go b/chain/sync.go index b0c8b50ff..db7b7fc04 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -11,10 +11,10 @@ import ( "github.com/Gurpartap/async" "github.com/hashicorp/go-multierror" - blocks "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" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/peer" diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index e0b9e6b30..559569ba0 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -4,8 +4,8 @@ import ( "bytes" "math/big" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/minio/blake2b-simd" "golang.org/x/xerrors" diff --git a/chain/types/message.go b/chain/types/message.go index 352548d0c..a25cd05b6 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/chain/types/signedmessage.go b/chain/types/signedmessage.go index 168531714..dc867c5e5 100644 --- a/chain/types/signedmessage.go +++ b/chain/types/signedmessage.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" diff --git a/chain/types/tipset_key.go b/chain/types/tipset_key.go index 15e655da7..50753ffd2 100644 --- a/chain/types/tipset_key.go +++ b/chain/types/tipset_key.go @@ -7,8 +7,8 @@ import ( "io" "strings" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" typegen "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-state-types/abi" diff --git a/chain/vm/vm.go b/chain/vm/vm.go index dcebe2b17..f09864c2d 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -7,9 +7,9 @@ import ( "sync/atomic" "time" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + block "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" cbg "github.com/whyrusleeping/cbor-gen" diff --git a/cmd/lotus-shed/datastore-vlog.go b/cmd/lotus-shed/datastore-vlog.go index 936d33849..af412df19 100644 --- a/cmd/lotus-shed/datastore-vlog.go +++ b/cmd/lotus-shed/datastore-vlog.go @@ -12,8 +12,8 @@ import ( "strings" "github.com/dgraph-io/badger/v2/y" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/mitchellh/go-homedir" "github.com/multiformats/go-base32" "github.com/urfave/cli/v2" diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go index 459de3383..d67fa4493 100644 --- a/cmd/lotus-shed/export.go +++ b/cmd/lotus-shed/export.go @@ -15,11 +15,11 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/dgraph-io/badger/v2/pb" "github.com/dustin/go-humanize" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" offline "github.com/ipfs/go-ipfs-exchange-offline" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "github.com/ipld/go-car" "github.com/multiformats/go-base32" diff --git a/cmd/lotus-shed/import-car.go b/cmd/lotus-shed/import-car.go index 973e7b31b..4c636a3af 100644 --- a/cmd/lotus-shed/import-car.go +++ b/cmd/lotus-shed/import-car.go @@ -7,8 +7,8 @@ import ( "io" "os" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" "github.com/urfave/cli/v2" "golang.org/x/xerrors" diff --git a/cmd/tvx/stores.go b/cmd/tvx/stores.go index 9035c482a..b863ffa74 100644 --- a/cmd/tvx/stores.go +++ b/cmd/tvx/stores.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/fatih/color" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -15,6 +14,7 @@ import ( offline "github.com/ipfs/go-ipfs-exchange-offline" cbor "github.com/ipfs/go-ipld-cbor" format "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "golang.org/x/xerrors" diff --git a/conformance/runner.go b/conformance/runner.go index b6bb5a164..ff738a4a5 100644 --- a/conformance/runner.go +++ b/conformance/runner.go @@ -14,12 +14,12 @@ import ( "github.com/fatih/color" "github.com/hashicorp/go-multierror" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" offline "github.com/ipfs/go-ipfs-exchange-offline" format "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "github.com/ipld/go-car" diff --git a/gateway/node.go b/gateway/node.go index 4f57d1d6a..00a83df96 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -5,8 +5,8 @@ import ( "fmt" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "go.opencensus.io/stats" "golang.org/x/time/rate" diff --git a/gateway/proxy_fil.go b/gateway/proxy_fil.go index 0e53130fb..1f6ee2ccc 100644 --- a/gateway/proxy_fil.go +++ b/gateway/proxy_fil.go @@ -3,8 +3,8 @@ package gateway import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/go.mod b/go.mod index f74149438..777eabd86 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,6 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab github.com/ipfs/bbloom v0.0.4 github.com/ipfs/go-bitswap v0.10.2 - github.com/ipfs/go-block-format v0.0.3 github.com/ipfs/go-blockservice v0.4.0 github.com/ipfs/go-cid v0.3.2 github.com/ipfs/go-cidutil v0.1.0 @@ -100,6 +99,7 @@ require ( github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.6 github.com/ipfs/go-ipld-format v0.4.0 + github.com/ipfs/go-libipfs v0.3.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.8.1 github.com/ipfs/go-metrics-interface v0.0.1 @@ -115,7 +115,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/koalacxr/quantile v0.0.1 github.com/libp2p/go-buffer-pool v0.1.0 - github.com/libp2p/go-libp2p v0.23.2 + github.com/libp2p/go-libp2p v0.23.4 github.com/libp2p/go-libp2p-consensus v0.0.1 github.com/libp2p/go-libp2p-gorpc v0.4.0 github.com/libp2p/go-libp2p-kad-dht v0.18.0 @@ -130,7 +130,7 @@ require ( github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.7.0 + github.com/multiformats/go-multiaddr v0.8.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.1.1 github.com/multiformats/go-multihash v0.2.1 @@ -140,7 +140,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/raulk/clock v1.1.0 github.com/raulk/go-watchdog v1.3.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/urfave/cli/v2 v2.16.3 github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba @@ -234,6 +234,7 @@ require ( github.com/huin/goupnp v1.0.3 // indirect github.com/iancoleman/orderedmap v0.1.0 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect + github.com/ipfs/go-block-format v0.1.1 // indirect github.com/ipfs/go-filestore v1.2.0 // indirect github.com/ipfs/go-ipfs-cmds v0.7.0 // indirect github.com/ipfs/go-ipfs-config v0.18.0 // indirect diff --git a/go.sum b/go.sum index 4d8dc0630..f7cf3a6b2 100644 --- a/go.sum +++ b/go.sum @@ -691,8 +691,9 @@ github.com/ipfs/go-bitswap v0.10.2 h1:B81RIwkTnIvSYT1ZCzxjYTeF0Ek88xa9r1AMpTfk+9 github.com/ipfs/go-bitswap v0.10.2/go.mod h1:+fZEvycxviZ7c+5KlKwTzLm0M28g2ukCPqiuLfJk4KA= 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/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= -github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= +github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI= +github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs= github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= @@ -820,6 +821,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= +github.com/ipfs/go-libipfs v0.3.0 h1:YvzFWGcl88eiz2tjOheNqaeQseH+dW3fUKrSaHOG/dU= +github.com/ipfs/go-libipfs v0.3.0/go.mod h1:pSUHZ5qPJTAidsxe9bAeHp3KIiw2ODEW2a2kM3v+iXI= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= @@ -1039,8 +1042,8 @@ github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2 github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.17.0/go.mod h1:Fkin50rsGdv5mm5BshBUtPRZknt9esfmYXBOYcwOTgw= github.com/libp2p/go-libp2p v0.19.4/go.mod h1:MIt8y481VDhUe4ErWi1a4bvt/CjjFfOq6kZTothWIXY= -github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE= -github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= +github.com/libp2p/go-libp2p v0.23.4 h1:hWi9XHSOVFR1oDWRk7rigfyA4XNMuYL20INNybP9LP8= +github.com/libp2p/go-libp2p v0.23.4/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= @@ -1496,8 +1499,8 @@ github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9x github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= -github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= -github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= +github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU= +github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1793,8 +1796,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1803,8 +1807,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= diff --git a/itests/deals_partial_retrieval_dm-level_test.go b/itests/deals_partial_retrieval_dm-level_test.go index f56d64026..246541229 100644 --- a/itests/deals_partial_retrieval_dm-level_test.go +++ b/itests/deals_partial_retrieval_dm-level_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" textselector "github.com/ipld/go-ipld-selector-text-lite" "github.com/stretchr/testify/require" diff --git a/itests/deals_partial_retrieval_test.go b/itests/deals_partial_retrieval_test.go index 0bbf23da0..e2dae9aff 100644 --- a/itests/deals_partial_retrieval_test.go +++ b/itests/deals_partial_retrieval_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" "github.com/stretchr/testify/require" "golang.org/x/xerrors" diff --git a/markets/dagstore/blockstore.go b/markets/dagstore/blockstore.go index 317cb08b9..593204ec8 100644 --- a/markets/dagstore/blockstore.go +++ b/markets/dagstore/blockstore.go @@ -4,9 +4,9 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" bstore "github.com/ipfs/go-ipfs-blockstore" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/dagstore" diff --git a/markets/storageadapter/api.go b/markets/storageadapter/api.go index b93ffdfbb..3105f2261 100644 --- a/markets/storageadapter/api.go +++ b/markets/storageadapter/api.go @@ -3,9 +3,9 @@ package storageadapter import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/markets/storageadapter/ondealsectorcommitted_test.go b/markets/storageadapter/ondealsectorcommitted_test.go index 1d7519ff9..592c22db7 100644 --- a/markets/storageadapter/ondealsectorcommitted_test.go +++ b/markets/storageadapter/ondealsectorcommitted_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "golang.org/x/xerrors" diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 8448a542e..17444ca58 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -11,12 +11,12 @@ import ( "strings" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" offline "github.com/ipfs/go-ipfs-exchange-offline" cbor "github.com/ipfs/go-ipld-cbor" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "github.com/ipfs/go-merkledag" mh "github.com/multiformats/go-multihash" From 7a4205ac36d4a4c963377f059f25b0dd8fa92402 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 27 Jan 2023 23:01:51 +0100 Subject: [PATCH 36/49] chore: node: migrate go-bitswap to go-libipfs/bitswap This was migrated in https://github.com/ipfs/go-libipfs/pull/63. (cherry picked from commit d060df2fb901faee701f711e02ea3a3ad6b8ef7f) --- go.mod | 5 ++--- go.sum | 8 ++++---- node/modules/chain.go | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 777eabd86..953f862df 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,6 @@ require ( github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94 github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab github.com/ipfs/bbloom v0.0.4 - github.com/ipfs/go-bitswap v0.10.2 github.com/ipfs/go-blockservice v0.4.0 github.com/ipfs/go-cid v0.3.2 github.com/ipfs/go-cidutil v0.1.0 @@ -95,11 +94,11 @@ require ( github.com/ipfs/go-ipfs-exchange-offline v0.3.0 github.com/ipfs/go-ipfs-files v0.1.1 github.com/ipfs/go-ipfs-http-client v0.4.0 - github.com/ipfs/go-ipfs-routing v0.2.1 + github.com/ipfs/go-ipfs-routing v0.3.0 github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.6 github.com/ipfs/go-ipld-format v0.4.0 - github.com/ipfs/go-libipfs v0.3.0 + github.com/ipfs/go-libipfs v0.4.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.8.1 github.com/ipfs/go-metrics-interface v0.0.1 diff --git a/go.sum b/go.sum index f7cf3a6b2..04250657b 100644 --- a/go.sum +++ b/go.sum @@ -688,7 +688,6 @@ github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiL github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= github.com/ipfs/go-bitswap v0.10.2 h1:B81RIwkTnIvSYT1ZCzxjYTeF0Ek88xa9r1AMpTfk+9Q= -github.com/ipfs/go-bitswap v0.10.2/go.mod h1:+fZEvycxviZ7c+5KlKwTzLm0M28g2ukCPqiuLfJk4KA= 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/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= @@ -798,8 +797,9 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY github.com/ipfs/go-ipfs-pq v0.0.2/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/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= -github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= +github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc= +github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= @@ -821,8 +821,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.3.0 h1:YvzFWGcl88eiz2tjOheNqaeQseH+dW3fUKrSaHOG/dU= -github.com/ipfs/go-libipfs v0.3.0/go.mod h1:pSUHZ5qPJTAidsxe9bAeHp3KIiw2ODEW2a2kM3v+iXI= +github.com/ipfs/go-libipfs v0.4.0 h1:TkUxJGjtPnSzAgkw7VjS0/DBay3MPjmTBa4dGdUQCDE= +github.com/ipfs/go-libipfs v0.4.0/go.mod h1:XsU2cP9jBhDrXoJDe0WxikB8XcVmD3k2MEZvB3dbYu8= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= diff --git a/node/modules/chain.go b/node/modules/chain.go index 6129f0345..f304ab135 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/ipfs/go-bitswap" - "github.com/ipfs/go-bitswap/network" "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-libipfs/bitswap" + "github.com/ipfs/go-libipfs/bitswap/network" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/routing" "go.uber.org/fx" From 198217d6bc96544e661440a9a5218e7f3ed2ab88 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 17 Feb 2023 18:46:58 +0100 Subject: [PATCH 37/49] chore: all: bump go-libipfs to v0.4.1 --- go.mod | 6 +++--- go.sum | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 953f862df..1d74e1a23 100644 --- a/go.mod +++ b/go.mod @@ -98,7 +98,7 @@ require ( github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.6 github.com/ipfs/go-ipld-format v0.4.0 - github.com/ipfs/go-libipfs v0.4.0 + github.com/ipfs/go-libipfs v0.4.1 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.8.1 github.com/ipfs/go-metrics-interface v0.0.1 @@ -239,12 +239,12 @@ require ( github.com/ipfs/go-ipfs-config v0.18.0 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect - github.com/ipfs/go-ipfs-pq v0.0.2 // indirect + github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipld-legacy v0.1.1 // indirect github.com/ipfs/go-ipns v0.3.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-path v0.3.0 // indirect - github.com/ipfs/go-peertaskqueue v0.8.0 // indirect + github.com/ipfs/go-peertaskqueue v0.8.1 // indirect github.com/ipfs/go-verifcid v0.0.2 // indirect github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 // indirect diff --git a/go.sum b/go.sum index 04250657b..948e87ebb 100644 --- a/go.sum +++ b/go.sum @@ -793,8 +793,9 @@ github.com/ipfs/go-ipfs-http-client v0.4.0/go.mod h1:NXzPUKt/QVCuR74a8angJCGOSLP github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= +github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= @@ -821,8 +822,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.4.0 h1:TkUxJGjtPnSzAgkw7VjS0/DBay3MPjmTBa4dGdUQCDE= -github.com/ipfs/go-libipfs v0.4.0/go.mod h1:XsU2cP9jBhDrXoJDe0WxikB8XcVmD3k2MEZvB3dbYu8= +github.com/ipfs/go-libipfs v0.4.1 h1:tyu3RRMKFQUyUQt5jyt5SmDnls93H4Tr3HifL50zihg= +github.com/ipfs/go-libipfs v0.4.1/go.mod h1:Ad8ybPqwCkl2cNiNUMvM/iaVc/5bwNpHu8RPZ5te1hw= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= @@ -863,8 +864,8 @@ github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU= -github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM= +github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= +github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU= github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= From dbcf30470f8ddb1e916ab230dee4bd7a97a9f39e Mon Sep 17 00:00:00 2001 From: mike seiler Date: Fri, 17 Feb 2023 11:16:40 -0700 Subject: [PATCH 38/49] clean up comment remove print --- gen/bundle/bundle.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index a1eab4e04..bc038569d 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -46,9 +46,9 @@ func main() { } var metadataSpecificVersion []*build.BuiltinActorsMetadata - // see ./build/actors/pack.sh - // expected args are git bundle tag then number of per network overrides + // expected args are: + // $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) // overrides are in the format network_name=override if len(os.Args) > 1 { @@ -67,7 +67,6 @@ func main() { } else { m.BundleGitTag = os.Args[2] } - fmt.Println("hi") metadataSpecificVersion = append(metadataSpecificVersion, m) } } From 30615a4ed6963bc83f6d3f1ad2180b707120ab94 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 10:36:30 -0800 Subject: [PATCH 39/49] feat: eth: return revert data on failed gas estimation (#10298) Unfortunately, we need to execute the message twice to get this (unless we want to change some APIs). But it's unlikely to be a performance issue and will definitely help people debug failures. --- itests/fevm_test.go | 21 +++++++++++++++------ node/impl/full/eth.go | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index d9c0019de..940d56ef1 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -901,14 +901,23 @@ func TestFEVMErrorParsing(t *testing.T) { "failCustom()": customError, } { sig := sig - expected := expected + expected := fmt.Sprintf("exit 33, revert reason: %s, vm error", expected) t.Run(sig, func(t *testing.T) { entryPoint := kit.CalcFuncSignature(sig) - _, err := e.EthCall(ctx, ethtypes.EthCall{ - To: &contractAddrEth, - Data: entryPoint, - }, "latest") - require.ErrorContains(t, err, fmt.Sprintf("exit 33, revert reason: %s, vm error", expected)) + t.Run("EthCall", func(t *testing.T) { + _, err := e.EthCall(ctx, ethtypes.EthCall{ + To: &contractAddrEth, + Data: entryPoint, + }, "latest") + require.ErrorContains(t, err, expected) + }) + t.Run("EthEstimateGas", func(t *testing.T) { + _, err := e.EthEstimateGas(ctx, ethtypes.EthCall{ + To: &contractAddrEth, + Data: entryPoint, + }) + require.ErrorContains(t, err, expected) + }) }) } } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 454b3eca5..2f50d873e 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -888,12 +888,22 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et msg.GasLimit = 0 ts := a.Chain.GetHeaviestTipSet() - msg, err = a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key()) + gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key()) if err != nil { + // On failure, GasEstimateMessageGas doesn't actually return the invocation result, + // it just returns an error. That means we can't get the revert reason. + // + // So we re-execute the message with EthCall (well, applyMessage which contains the + // guts of EthCall). This will give us an ethereum specific error with revert + // information. + msg.GasLimit = build.BlockGasLimit + if _, err2 := a.applyMessage(ctx, msg, ts.Key()); err2 != nil { + err = err2 + } return ethtypes.EthUint64(0), xerrors.Errorf("failed to estimate gas: %w", err) } - expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, msg, ts) + expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, gassedMsg, ts) if err != nil { log.Errorw("expected gas", "err", err) } From a3bc65ba052ab37a1f34653c3053894d147a4f31 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 16 Feb 2023 20:07:20 -0800 Subject: [PATCH 40/49] fix: eth: return the correct nonce from EthGetTransactionCount EVM contracts track this number internally. fixes https://github.com/filecoin-project/lotus/issues/10255 --- chain/actors/builtin/evm/actor.go.template | 1 + chain/actors/builtin/evm/evm.go | 1 + chain/actors/builtin/evm/state.go.template | 6 +++++ chain/actors/builtin/evm/v10.go | 4 ++++ itests/eth_bytecode_test.go | 27 +++++++++++++++++++--- node/impl/full/eth.go | 24 +++++++++++++++++++ 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/chain/actors/builtin/evm/actor.go.template b/chain/actors/builtin/evm/actor.go.template index aa23b5f11..62da06867 100644 --- a/chain/actors/builtin/evm/actor.go.template +++ b/chain/actors/builtin/evm/actor.go.template @@ -48,6 +48,7 @@ type State interface { cbor.Marshaler Nonce() (uint64, error) + IsAlive() (bool, error) GetState() interface{} GetBytecode() ([]byte, error) diff --git a/chain/actors/builtin/evm/evm.go b/chain/actors/builtin/evm/evm.go index f55a2177d..f214cdc13 100644 --- a/chain/actors/builtin/evm/evm.go +++ b/chain/actors/builtin/evm/evm.go @@ -48,6 +48,7 @@ type State interface { cbor.Marshaler Nonce() (uint64, error) + IsAlive() (bool, error) GetState() interface{} GetBytecode() ([]byte, error) diff --git a/chain/actors/builtin/evm/state.go.template b/chain/actors/builtin/evm/state.go.template index eb55a8463..f193733d1 100644 --- a/chain/actors/builtin/evm/state.go.template +++ b/chain/actors/builtin/evm/state.go.template @@ -4,6 +4,8 @@ import ( "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/go-state-types/abi" evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm" ) @@ -40,6 +42,10 @@ func (s *state{{.v}}) Nonce() (uint64, error) { return s.State.Nonce, nil } +func (s *state{{.v}}) IsAlive() (bool, error) { + return s.State.Tombstone == nil, nil +} + func (s *state{{.v}}) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/evm/v10.go b/chain/actors/builtin/evm/v10.go index 77a09037b..d467aa187 100644 --- a/chain/actors/builtin/evm/v10.go +++ b/chain/actors/builtin/evm/v10.go @@ -41,6 +41,10 @@ func (s *state10) Nonce() (uint64, error) { return s.State.Nonce, nil } +func (s *state10) IsAlive() (bool, error) { + return s.State.Tombstone == nil, nil +} + func (s *state10) GetState() interface{} { return &s.State } diff --git a/itests/eth_bytecode_test.go b/itests/eth_bytecode_test.go index 4d03a0f6d..a8a75e83f 100644 --- a/itests/eth_bytecode_test.go +++ b/itests/eth_bytecode_test.go @@ -10,15 +10,16 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/itests/kit" ) -// TestGetCode ensures that GetCode returns the correct results for: +// TestGetCodeAndNonce ensures that GetCode and GetTransactionCount return the correct results for: // 1. Placeholders. // 2. Non-existent actors. // 3. Normal EVM actors. // 4. Self-destructed EVM actors. -func TestGetCode(t *testing.T) { +func TestGetCodeAndNonce(t *testing.T) { kit.QuietMiningLogs() blockTime := 100 * time.Millisecond @@ -28,7 +29,7 @@ func TestGetCode(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - // Accounts should have empty code. + // Accounts should have empty code, empty nonce. { // A random eth address should have no code. _, ethAddr, filAddr := client.EVM().NewAccount() @@ -36,6 +37,11 @@ func TestGetCode(t *testing.T) { require.NoError(t, err) require.Empty(t, bytecode) + // Nonce should also be zero + nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) + // send some funds to the account. kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10)) @@ -43,6 +49,11 @@ func TestGetCode(t *testing.T) { bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest") require.NoError(t, err) require.Empty(t, bytecode) + + // Nonce should still be zero. + nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) } // Check contract code. @@ -61,6 +72,11 @@ func TestGetCode(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, bytecode) + // Nonce should be one. + nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthUint64(1), nonce) + // Destroy it. _, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil) require.NoError(t, err) @@ -69,6 +85,11 @@ func TestGetCode(t *testing.T) { bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest") require.NoError(t, err) require.Empty(t, bytecode) + + // Nonce should go back to zero + nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) } } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 454b3eca5..552223343 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -31,6 +31,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" + builtinevm "github.com/filecoin-project/lotus/chain/actors/builtin/evm" "github.com/filecoin-project/lotus/chain/ethhashlookup" "github.com/filecoin-project/lotus/chain/events/filter" "github.com/filecoin-project/lotus/chain/messagepool" @@ -367,6 +368,29 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes. return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam) } + // First, handle the case where the "sender" is an EVM actor. + actor, err := a.StateManager.LoadActor(ctx, addr, ts) + if err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return 0, nil + } + return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) + } + + if builtinactors.IsEvmActor(actor.Code) { + evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) + if err != nil { + return 0, xerrors.Errorf("failed to load evm state: %w", err) + } + if alive, err := evmState.IsAlive(); err != nil { + return 0, err + } else if !alive { + return 0, nil + } + nonce, err := evmState.Nonce() + return ethtypes.EthUint64(nonce), err + } + nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key()) if err != nil { return ethtypes.EthUint64(0), nil From 4dedced1752e7fefebb3196b98ed6619bb447c99 Mon Sep 17 00:00:00 2001 From: mike seiler Date: Fri, 17 Feb 2023 11:52:40 -0700 Subject: [PATCH 41/49] lintfix --- gen/bundle/bundle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index bc038569d..d3e5ebf6b 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -47,7 +47,7 @@ func main() { var metadataSpecificVersion []*build.BuiltinActorsMetadata // see ./build/actors/pack.sh - // expected args are: + // expected args are: // $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) // overrides are in the format network_name=override From f41435d2858a00bf465252aa7f003c74b731bd0e Mon Sep 17 00:00:00 2001 From: Aayush Date: Fri, 17 Feb 2023 14:17:30 -0500 Subject: [PATCH 42/49] feat: bundle: only write git tags for newly packed bundles --- gen/bundle/bundle.go | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index d3e5ebf6b..f57ced15b 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -1,8 +1,8 @@ package main import ( - "fmt" "os" + "strconv" "strings" "text/template" @@ -40,38 +40,42 @@ func splitOverride(override string) (string, string) { } func main() { + // read metadata from the embedded bundle, includes all info except git tags metadata, err := build.ReadEmbeddedBuiltinActorsMetadata() if err != nil { panic(err) } - var metadataSpecificVersion []*build.BuiltinActorsMetadata - // see ./build/actors/pack.sh - // expected args are: - // $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) - // overrides are in the format network_name=override - + // IF args have been provided, extract git tag info from them, otherwise + // rely on previously embedded metadata for git tags. if len(os.Args) > 1 { - version := os.Args[1] + // see ./build/actors/pack.sh + // (optional) expected args are: + // $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) + // overrides are in the format network_name=override + gitTag := os.Args[2] + packedActorsVersion, err := strconv.Atoi(os.Args[1][1:]) + if err != nil { + panic(err) + } + overrides := map[string]string{} for _, override := range os.Args[3:] { k, v := splitOverride(override) overrides[k] = v } for _, m := range metadata { - if strings.HasPrefix(version, fmt.Sprintf("v%d", m.Version)) { - // correct version + if int(m.Version) == packedActorsVersion { override, ok := overrides[m.Network] if ok { m.BundleGitTag = override } else { - m.BundleGitTag = os.Args[2] + m.BundleGitTag = gitTag } - metadataSpecificVersion = append(metadataSpecificVersion, m) + } else { + m.BundleGitTag = getOldGitTagFromEmbeddedMetadata(m) } } - metadata = metadataSpecificVersion - } fi, err := os.Create("./build/builtin_actors_gen.go") @@ -85,3 +89,14 @@ func main() { panic(err) } } + +func getOldGitTagFromEmbeddedMetadata(m *build.BuiltinActorsMetadata) string { + for _, v := range build.EmbeddedBuiltinActorsMetadata { + // if we agree on the manifestCid for the previously embedded metadata, use the previously set tag + if m.Version == v.Version && m.Network == v.Network && m.ManifestCid == v.ManifestCid { + return m.BundleGitTag + } + } + + return "" +} From 49cd428c437e753bed411a8d90e1a7a3c514ac0c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 11:17:35 -0800 Subject: [PATCH 43/49] nit: put evm case in a block --- node/impl/full/eth.go | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 552223343..f0df89bff 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -369,26 +369,28 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes. } // First, handle the case where the "sender" is an EVM actor. - actor, err := a.StateManager.LoadActor(ctx, addr, ts) - if err != nil { - if xerrors.Is(err, types.ErrActorNotFound) { - return 0, nil - } - return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) - } - - if builtinactors.IsEvmActor(actor.Code) { - evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) + { + actor, err := a.StateManager.LoadActor(ctx, addr, ts) if err != nil { - return 0, xerrors.Errorf("failed to load evm state: %w", err) + if xerrors.Is(err, types.ErrActorNotFound) { + return 0, nil + } + return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) } - if alive, err := evmState.IsAlive(); err != nil { - return 0, err - } else if !alive { - return 0, nil + + if builtinactors.IsEvmActor(actor.Code) { + evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) + if err != nil { + return 0, xerrors.Errorf("failed to load evm state: %w", err) + } + if alive, err := evmState.IsAlive(); err != nil { + return 0, err + } else if !alive { + return 0, nil + } + nonce, err := evmState.Nonce() + return ethtypes.EthUint64(nonce), err } - nonce, err := evmState.Nonce() - return ethtypes.EthUint64(nonce), err } nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key()) From 6c0f4cbd744205b7931f4ebd7ae706f061a92ca6 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 11:18:51 -0800 Subject: [PATCH 44/49] nit: actually, don't use blocks --- node/impl/full/eth.go | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index f0df89bff..0141f6a56 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -369,28 +369,23 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes. } // First, handle the case where the "sender" is an EVM actor. - { - actor, err := a.StateManager.LoadActor(ctx, addr, ts) + if actor, err := a.StateManager.LoadActor(ctx, addr, ts); err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return 0, nil + } + return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) + } else if builtinactors.IsEvmActor(actor.Code) { + evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) if err != nil { - if xerrors.Is(err, types.ErrActorNotFound) { - return 0, nil - } - return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) + return 0, xerrors.Errorf("failed to load evm state: %w", err) } - - if builtinactors.IsEvmActor(actor.Code) { - evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) - if err != nil { - return 0, xerrors.Errorf("failed to load evm state: %w", err) - } - if alive, err := evmState.IsAlive(); err != nil { - return 0, err - } else if !alive { - return 0, nil - } - nonce, err := evmState.Nonce() - return ethtypes.EthUint64(nonce), err + if alive, err := evmState.IsAlive(); err != nil { + return 0, err + } else if !alive { + return 0, nil } + nonce, err := evmState.Nonce() + return ethtypes.EthUint64(nonce), err } nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key()) From bad41c247a51916b096b93ade2bffe21e8a5255c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 12:02:00 -0800 Subject: [PATCH 45/49] fix: eth: cleanup error cases 1. Return an error on gas estimation failure instead of logging. 2. Return early when processing signed messages on failure instead of continuing. --- node/impl/full/eth.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 454b3eca5..5e18e7e77 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -895,7 +895,7 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, msg, ts) if err != nil { - log.Errorw("expected gas", "err", err) + return 0, xerrors.Errorf("gas search failed: %w", err) } return ethtypes.EthUint64(expectedGas), nil @@ -2157,11 +2157,13 @@ func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types. ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.StateAPI) if err != nil { log.Errorf("error converting filecoin message to eth tx: %s", err) + return } err = m.TransactionHashLookup.UpsertHash(ethTx.Hash, msg.Cid()) if err != nil { log.Errorf("error inserting tx mapping to db: %s", err) + return } } From 73102e9432f31cb68f2571d76cd59d9785470090 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 13:29:53 -0800 Subject: [PATCH 46/49] test: eth: make sure we can deploy a new placeholder on transfer (#10281) We have a test that triggers smart-contract logic on "transfers", but nothing that tries to create a new actor as a side-effect of a transfer. fixes https://github.com/filecoin-project/ref-fvm/issues/1670 --- itests/fevm_test.go | 33 +++++++++++++++++++++++++++++++++ itests/kit/evm.go | 6 +++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 3018bf63d..068df49ef 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -844,6 +844,39 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) { require.Len(t, receipt.Logs, 1) } +// This test ensures that we can deploy new contracts from a solidity call to `transfer` without +// exceeding the 10M gas limit. +func TestFEVMTestDeployOnTransfer(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + fromAddr := client.DefaultKey.Address + t.Log("from - ", fromAddr) + + //create contract A + filenameStorage := "contracts/ValueSender.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //send to some random address. + params := [32]byte{} + params[30] = 0xff + randomAddr, err := ethtypes.CastEthAddress(params[12:]) + value := big.NewInt(100) + entryPoint := kit.CalcFuncSignature("sendEthToB(address)") + require.NoError(t, err) + ret, err := client.EVM().InvokeSolidityWithValue(ctx, fromAddr, contractAddr, entryPoint, params[:], value) + require.NoError(t, err) + require.True(t, ret.Receipt.ExitCode.IsSuccess()) + + balance, err := client.EVM().EthGetBalance(ctx, randomAddr, "latest") + require.NoError(t, err) + require.Equal(t, value.Int, balance.Int) + + filAddr, err := randomAddr.ToFilecoinAddress() + require.NoError(t, err) + client.AssertActorType(ctx, filAddr, manifest.PlaceholderKey) +} + func TestFEVMProxyUpgradeable(t *testing.T) { ctx, cancel, client := kit.SetupFEVMTest(t) defer cancel() diff --git a/itests/kit/evm.go b/itests/kit/evm.go index 3cbfcd5f2..c98795f26 100644 --- a/itests/kit/evm.go +++ b/itests/kit/evm.go @@ -104,6 +104,10 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string } func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) { + return e.InvokeSolidityWithValue(ctx, sender, target, selector, inputData, big.Zero()) +} + +func (e *EVM) InvokeSolidityWithValue(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte, value big.Int) (*api.MsgLookup, error) { params := append(selector, inputData...) var buffer bytes.Buffer err := cbg.WriteByteArray(&buffer, params) @@ -115,7 +119,7 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target msg := &types.Message{ To: target, From: sender, - Value: big.Zero(), + Value: value, Method: builtintypes.MethodsEVM.InvokeContract, GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041 Params: params, From e51f3e9b159667b6a5cceeb1c7ffab60b7d010d6 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 17 Feb 2023 15:06:58 -0800 Subject: [PATCH 47/49] fix: eth: incorrect struct tags (#10309) --- api/proxy_gen.go | 2 +- gen/api/proxygen.go | 3 ++- itests/deals_partial_retrieval_dm-level_test.go | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 29a4e7131..5d56c177c 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -117,7 +117,7 @@ type EthSubscriberStruct struct { } type EthSubscriberMethods struct { - EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"` + EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true" rpc_method:"eth_subscription"` } type EthSubscriberStub struct { diff --git a/gen/api/proxygen.go b/gen/api/proxygen.go index 75fbc668c..fba276372 100644 --- a/gen/api/proxygen.go +++ b/gen/api/proxygen.go @@ -307,7 +307,8 @@ type {{.Num}}Struct struct { type {{.Num}}Methods struct { {{range .Methods}} - {{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+` + {{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{$first := true}}{{range .Tags}}{{if $first}}{{$first = false}}{{else}} {{end}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+` + {{end}} } diff --git a/itests/deals_partial_retrieval_dm-level_test.go b/itests/deals_partial_retrieval_dm-level_test.go index 246541229..156ed67fe 100644 --- a/itests/deals_partial_retrieval_dm-level_test.go +++ b/itests/deals_partial_retrieval_dm-level_test.go @@ -166,7 +166,7 @@ func testDMExportAsFile(ctx context.Context, client *kit.TestFullNode, expDirect func testV0RetrievalAsFile(ctx context.Context, client *kit.TestFullNode, retOrder api0.RetrievalOrder, tempDir string) error { out := tempDir + string(os.PathSeparator) + "exp-test" + retOrder.Root.String() - cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet + cv0 := &api0.WrapperV1Full{FullNode: client.FullNode} err := cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{ Path: out, }) @@ -220,7 +220,7 @@ func tesV0RetrievalAsCar(ctx context.Context, client *kit.TestFullNode, retOrder } defer out.Close() //nolint:errcheck - cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet + cv0 := &api0.WrapperV1Full{FullNode: client.FullNode} err = cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{ Path: out.Name(), IsCAR: true, From 2dcaddf61d3ec780089d4f315625bb3c02f993ee Mon Sep 17 00:00:00 2001 From: Travis Person Date: Wed, 15 Feb 2023 21:24:21 +0000 Subject: [PATCH 48/49] feat: stmgr: add env to disable premigrations Setting the environment variable `LOTUS_DISABLE_PRE_MIGRATIONS=1` will discard premigrations for all upgrade. --- chain/stmgr/forks.go | 10 ++++++ chain/stmgr/forks_test.go | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 514f78f76..5a38fbada 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -4,7 +4,9 @@ import ( "bytes" "context" "encoding/binary" + "os" "sort" + "strings" "sync" "time" @@ -26,6 +28,9 @@ import ( "github.com/filecoin-project/lotus/chain/vm" ) +// EnvDisablePreMigrations when set to '1' stops pre-migrations from running +const EnvDisablePreMigrations = "LOTUS_DISABLE_PRE_MIGRATIONS" + // MigrationCache can be used to cache information used by a migration. This is primarily useful to // "pre-compute" some migration state ahead of time, and make it accessible in the migration itself. type MigrationCache interface { @@ -218,6 +223,11 @@ func runPreMigration(ctx context.Context, sm *StateManager, fn PreMigrationFunc, height := ts.Height() parent := ts.ParentState() + if disabled := os.Getenv(EnvDisablePreMigrations); strings.TrimSpace(disabled) == "1" { + log.Warnw("SKIPPING pre-migration", "height", height) + return + } + startTime := time.Now() log.Warn("STARTING pre-migration") diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index f56fc5ed1..52cfe5fce 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "os" "sync" "testing" @@ -535,3 +536,70 @@ func TestForkPreMigration(t *testing.T) { // to this channel. require.Equal(t, 6, len(counter)) } + +func TestDisablePreMigration(t *testing.T) { + logging.SetAllLoggers(logging.LevelInfo) + + cg, err := gen.NewGenerator() + require.NoError(t, err) + + err = os.Setenv(EnvDisablePreMigrations, "1") + require.NoError(t, err) + + defer func() { + err := os.Unsetenv(EnvDisablePreMigrations) + require.NoError(t, err) + }() + + counter := make(chan struct{}, 10) + + sm, err := NewStateManager( + cg.ChainStore(), + consensus.NewTipSetExecutor(filcns.RewardFunc), + cg.StateManager().VMSys(), + UpgradeSchedule{{ + Network: network.Version1, + Height: testForkHeight, + Migration: func(_ context.Context, _ *StateManager, _ MigrationCache, _ ExecMonitor, + root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) { + + counter <- struct{}{} + + return root, nil + }, + PreMigrations: []PreMigration{{ + StartWithin: 20, + PreMigration: func(ctx context.Context, _ *StateManager, _ MigrationCache, + _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { + panic("should be skipped") + }, + }}}, + }, + cg.BeaconSchedule(), + ) + require.NoError(t, err) + require.NoError(t, sm.Start(context.Background())) + defer func() { + require.NoError(t, sm.Stop(context.Background())) + }() + + inv := consensus.NewActorRegistry() + registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}}) + inv.Register(actorstypes.Version0, nil, registry) + + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { + nvm, err := vm.NewLegacyVM(ctx, vmopt) + require.NoError(t, err) + nvm.SetInvoker(inv) + return nvm, nil + }) + + cg.SetStateManager(sm) + + for i := 0; i < 50; i++ { + _, err := cg.NextTipSet() + require.NoError(t, err) + } + + require.Equal(t, 1, len(counter)) +} From 51aecb6b172a43ee44321f20cc1b9aed11d2af4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 20 Feb 2023 17:38:18 +0100 Subject: [PATCH 49/49] fix: tests: Make TestWorkerKeyChange not flaky --- cmd/lotus-miner/actor_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cmd/lotus-miner/actor_test.go b/cmd/lotus-miner/actor_test.go index 791298ffa..dfb452213 100644 --- a/cmd/lotus-miner/actor_test.go +++ b/cmd/lotus-miner/actor_test.go @@ -34,8 +34,8 @@ func TestWorkerKeyChange(t *testing.T) { kit.QuietMiningLogs() - blocktime := 1 * time.Millisecond - client1, client2, miner, ens := kit.EnsembleTwoOne(t, kit.MockProofs()) + blocktime := 5 * time.Millisecond + client1, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) output := bytes.NewBuffer(nil) @@ -96,7 +96,4 @@ func TestWorkerKeyChange(t *testing.T) { // Wait for finality (worker key switch). targetHeight := head.Height() + policy.ChainFinality client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight)) - - // Make sure the other node can catch up. - client2.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight)) }