diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000..3833fc22 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,11 @@ +# File managed by web3-bot. DO NOT EDIT. +# See https://github.com/protocol/.github/ for details. + +name: Automerge +on: [ pull_request ] + +jobs: + automerge: + uses: protocol/.github/.github/workflows/automerge.yml@master + with: + job: 'automerge' diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml index 0dada63e..a787668c 100644 --- a/.github/workflows/release-check.yml +++ b/.github/workflows/release-check.yml @@ -16,4 +16,4 @@ concurrency: jobs: release-check: - uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0.22 diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 2ebdbed3..d2bc982b 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -14,4 +14,4 @@ concurrency: jobs: releaser: - uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 + uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0.22 diff --git a/.github/workflows/tagpush.yml b/.github/workflows/tagpush.yml index 72efb2d4..7dde18f8 100644 --- a/.github/workflows/tagpush.yml +++ b/.github/workflows/tagpush.yml @@ -15,4 +15,4 @@ concurrency: jobs: releaser: - uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0.22 diff --git a/api/api.go b/api/api.go index 41c63e33..d4a6f974 100644 --- a/api/api.go +++ b/api/api.go @@ -201,7 +201,7 @@ func (s *Server) toEchoHandler(handlerFunc any) echo.HandlerFunc { var j int // Get path parameters - for i := 0; i < handlerFuncType.NumIn(); i++ { + for i := range handlerFuncType.NumIn() { paramType := handlerFuncType.In(i) if paramType.String() == "context.Context" { inputParams = append(inputParams, reflect.ValueOf(c.Request().Context())) @@ -346,6 +346,7 @@ func (s *Server) setupRoutes(e *echo.Echo) { e.POST("/api/preparation/:id/piece", s.toEchoHandler(s.dataprepHandler.AddPieceHandler)) // Wallet + e.POST("/api/wallet/create", s.toEchoHandler(s.walletHandler.CreateHandler)) e.POST("/api/wallet", s.toEchoHandler(s.walletHandler.ImportHandler)) e.GET("/api/wallet", s.toEchoHandler(s.walletHandler.ListHandler)) e.DELETE("/api/wallet/:address", s.toEchoHandler(s.walletHandler.RemoveHandler)) diff --git a/api/api_test.go b/api/api_test.go index ac63411b..da4f2ab1 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -184,6 +184,8 @@ func setupMockWallet() wallet.Handler { m := new(wallet.MockWallet) m.On("AttachHandler", mock.Anything, mock.Anything, "id", "wallet"). Return(&model.Preparation{}, nil) + m.On("CreateHandler", mock.Anything, mock.Anything, mock.Anything). + Return(&model.Wallet{}, nil) m.On("DetachHandler", mock.Anything, mock.Anything, "id", "wallet"). Return(&model.Preparation{}, nil) m.On("ImportHandler", mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -301,6 +303,15 @@ func TestAllAPIs(t *testing.T) { }) t.Run("wallet", func(t *testing.T) { + t.Run("CreateWallet", func(t *testing.T) { + resp, err := client.Wallet.CreateWallet(&wallet2.CreateWalletParams{ + Request: &models.WalletCreateRequest{}, + Context: ctx, + }) + require.NoError(t, err) + require.True(t, resp.IsSuccess()) + require.NotNil(t, resp.Payload) + }) t.Run("ImportWallet", func(t *testing.T) { resp, err := client.Wallet.ImportWallet(&wallet2.ImportWalletParams{ Request: &models.WalletImportRequest{}, diff --git a/client/swagger/http/wallet/create_wallet_parameters.go b/client/swagger/http/wallet/create_wallet_parameters.go new file mode 100644 index 00000000..bb53489c --- /dev/null +++ b/client/swagger/http/wallet/create_wallet_parameters.go @@ -0,0 +1,153 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package wallet + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/data-preservation-programs/singularity/client/swagger/models" +) + +// NewCreateWalletParams creates a new CreateWalletParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewCreateWalletParams() *CreateWalletParams { + return &CreateWalletParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewCreateWalletParamsWithTimeout creates a new CreateWalletParams object +// with the ability to set a timeout on a request. +func NewCreateWalletParamsWithTimeout(timeout time.Duration) *CreateWalletParams { + return &CreateWalletParams{ + timeout: timeout, + } +} + +// NewCreateWalletParamsWithContext creates a new CreateWalletParams object +// with the ability to set a context for a request. +func NewCreateWalletParamsWithContext(ctx context.Context) *CreateWalletParams { + return &CreateWalletParams{ + Context: ctx, + } +} + +// NewCreateWalletParamsWithHTTPClient creates a new CreateWalletParams object +// with the ability to set a custom HTTPClient for a request. +func NewCreateWalletParamsWithHTTPClient(client *http.Client) *CreateWalletParams { + return &CreateWalletParams{ + HTTPClient: client, + } +} + +/* +CreateWalletParams contains all the parameters to send to the API endpoint + + for the create wallet operation. + + Typically these are written to a http.Request. +*/ +type CreateWalletParams struct { + + /* Request. + + Request body + */ + Request *models.WalletCreateRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the create wallet params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateWalletParams) WithDefaults() *CreateWalletParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the create wallet params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateWalletParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the create wallet params +func (o *CreateWalletParams) WithTimeout(timeout time.Duration) *CreateWalletParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the create wallet params +func (o *CreateWalletParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the create wallet params +func (o *CreateWalletParams) WithContext(ctx context.Context) *CreateWalletParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the create wallet params +func (o *CreateWalletParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the create wallet params +func (o *CreateWalletParams) WithHTTPClient(client *http.Client) *CreateWalletParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the create wallet params +func (o *CreateWalletParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithRequest adds the request to the create wallet params +func (o *CreateWalletParams) WithRequest(request *models.WalletCreateRequest) *CreateWalletParams { + o.SetRequest(request) + return o +} + +// SetRequest adds the request to the create wallet params +func (o *CreateWalletParams) SetRequest(request *models.WalletCreateRequest) { + o.Request = request +} + +// WriteToRequest writes these params to a swagger request +func (o *CreateWalletParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Request != nil { + if err := r.SetBodyParam(o.Request); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/swagger/http/wallet/create_wallet_responses.go b/client/swagger/http/wallet/create_wallet_responses.go new file mode 100644 index 00000000..14c6fef9 --- /dev/null +++ b/client/swagger/http/wallet/create_wallet_responses.go @@ -0,0 +1,258 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package wallet + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/data-preservation-programs/singularity/client/swagger/models" +) + +// CreateWalletReader is a Reader for the CreateWallet structure. +type CreateWalletReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CreateWalletReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewCreateWalletOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 400: + result := NewCreateWalletBadRequest() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 500: + result := NewCreateWalletInternalServerError() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + default: + return nil, runtime.NewAPIError("[POST /wallet/create] CreateWallet", response, response.Code()) + } +} + +// NewCreateWalletOK creates a CreateWalletOK with default headers values +func NewCreateWalletOK() *CreateWalletOK { + return &CreateWalletOK{} +} + +/* +CreateWalletOK describes a response with status code 200, with default header values. + +OK +*/ +type CreateWalletOK struct { + Payload *models.ModelWallet +} + +// IsSuccess returns true when this create wallet o k response has a 2xx status code +func (o *CreateWalletOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this create wallet o k response has a 3xx status code +func (o *CreateWalletOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create wallet o k response has a 4xx status code +func (o *CreateWalletOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this create wallet o k response has a 5xx status code +func (o *CreateWalletOK) IsServerError() bool { + return false +} + +// IsCode returns true when this create wallet o k response a status code equal to that given +func (o *CreateWalletOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the create wallet o k response +func (o *CreateWalletOK) Code() int { + return 200 +} + +func (o *CreateWalletOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletOK %s", 200, payload) +} + +func (o *CreateWalletOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletOK %s", 200, payload) +} + +func (o *CreateWalletOK) GetPayload() *models.ModelWallet { + return o.Payload +} + +func (o *CreateWalletOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.ModelWallet) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewCreateWalletBadRequest creates a CreateWalletBadRequest with default headers values +func NewCreateWalletBadRequest() *CreateWalletBadRequest { + return &CreateWalletBadRequest{} +} + +/* +CreateWalletBadRequest describes a response with status code 400, with default header values. + +Bad Request +*/ +type CreateWalletBadRequest struct { + Payload *models.APIHTTPError +} + +// IsSuccess returns true when this create wallet bad request response has a 2xx status code +func (o *CreateWalletBadRequest) IsSuccess() bool { + return false +} + +// IsRedirect returns true when this create wallet bad request response has a 3xx status code +func (o *CreateWalletBadRequest) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create wallet bad request response has a 4xx status code +func (o *CreateWalletBadRequest) IsClientError() bool { + return true +} + +// IsServerError returns true when this create wallet bad request response has a 5xx status code +func (o *CreateWalletBadRequest) IsServerError() bool { + return false +} + +// IsCode returns true when this create wallet bad request response a status code equal to that given +func (o *CreateWalletBadRequest) IsCode(code int) bool { + return code == 400 +} + +// Code gets the status code for the create wallet bad request response +func (o *CreateWalletBadRequest) Code() int { + return 400 +} + +func (o *CreateWalletBadRequest) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletBadRequest %s", 400, payload) +} + +func (o *CreateWalletBadRequest) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletBadRequest %s", 400, payload) +} + +func (o *CreateWalletBadRequest) GetPayload() *models.APIHTTPError { + return o.Payload +} + +func (o *CreateWalletBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.APIHTTPError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewCreateWalletInternalServerError creates a CreateWalletInternalServerError with default headers values +func NewCreateWalletInternalServerError() *CreateWalletInternalServerError { + return &CreateWalletInternalServerError{} +} + +/* +CreateWalletInternalServerError describes a response with status code 500, with default header values. + +Internal Server Error +*/ +type CreateWalletInternalServerError struct { + Payload *models.APIHTTPError +} + +// IsSuccess returns true when this create wallet internal server error response has a 2xx status code +func (o *CreateWalletInternalServerError) IsSuccess() bool { + return false +} + +// IsRedirect returns true when this create wallet internal server error response has a 3xx status code +func (o *CreateWalletInternalServerError) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create wallet internal server error response has a 4xx status code +func (o *CreateWalletInternalServerError) IsClientError() bool { + return false +} + +// IsServerError returns true when this create wallet internal server error response has a 5xx status code +func (o *CreateWalletInternalServerError) IsServerError() bool { + return true +} + +// IsCode returns true when this create wallet internal server error response a status code equal to that given +func (o *CreateWalletInternalServerError) IsCode(code int) bool { + return code == 500 +} + +// Code gets the status code for the create wallet internal server error response +func (o *CreateWalletInternalServerError) Code() int { + return 500 +} + +func (o *CreateWalletInternalServerError) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletInternalServerError %s", 500, payload) +} + +func (o *CreateWalletInternalServerError) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /wallet/create][%d] createWalletInternalServerError %s", 500, payload) +} + +func (o *CreateWalletInternalServerError) GetPayload() *models.APIHTTPError { + return o.Payload +} + +func (o *CreateWalletInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.APIHTTPError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/client/swagger/http/wallet/wallet_client.go b/client/swagger/http/wallet/wallet_client.go index 598b3d31..e3373fe6 100644 --- a/client/swagger/http/wallet/wallet_client.go +++ b/client/swagger/http/wallet/wallet_client.go @@ -56,6 +56,8 @@ type ClientOption func(*runtime.ClientOperation) // ClientService is the interface for Client methods type ClientService interface { + CreateWallet(params *CreateWalletParams, opts ...ClientOption) (*CreateWalletOK, error) + ImportWallet(params *ImportWalletParams, opts ...ClientOption) (*ImportWalletOK, error) ListWallets(params *ListWalletsParams, opts ...ClientOption) (*ListWalletsOK, error) @@ -65,6 +67,44 @@ type ClientService interface { SetTransport(transport runtime.ClientTransport) } +/* +CreateWallet creates new wallet +*/ +func (a *Client) CreateWallet(params *CreateWalletParams, opts ...ClientOption) (*CreateWalletOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewCreateWalletParams() + } + op := &runtime.ClientOperation{ + ID: "CreateWallet", + Method: "POST", + PathPattern: "/wallet/create", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &CreateWalletReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*CreateWalletOK) + if ok { + return success, nil + } + // unexpected success response + // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + msg := fmt.Sprintf("unexpected success response for CreateWallet: API contract not enforced by server. Client expected to get an error, but got: %T", result) + panic(msg) +} + /* ImportWallet imports a private key */ diff --git a/client/swagger/models/model_deal.go b/client/swagger/models/model_deal.go index eb73cbea..6d760f88 100644 --- a/client/swagger/models/model_deal.go +++ b/client/swagger/models/model_deal.go @@ -18,8 +18,11 @@ import ( // swagger:model model.Deal type ModelDeal struct { + // client actor Id + ClientActorID string `json:"clientActorId,omitempty"` + // client Id - ClientID string `json:"clientId,omitempty"` + ClientID int64 `json:"clientId,omitempty"` // created at CreatedAt string `json:"createdAt,omitempty"` diff --git a/client/swagger/models/model_wallet.go b/client/swagger/models/model_wallet.go index dc2ff9fe..c6196011 100644 --- a/client/swagger/models/model_wallet.go +++ b/client/swagger/models/model_wallet.go @@ -8,6 +8,7 @@ package models import ( "context" + "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" ) @@ -17,23 +18,100 @@ import ( // swagger:model model.Wallet type ModelWallet struct { + // ActorID is the short ID of the wallet + ActorID string `json:"actorId,omitempty"` + + // ActorName is readable label for the wallet + ActorName string `json:"actorName,omitempty"` + // Address is the Filecoin full address of the wallet Address string `json:"address,omitempty"` - // ID is the short ID of the wallet - ID string `json:"id,omitempty"` + // Balance is in Fil cached from chain + Balance float64 `json:"balance,omitempty"` + + // BalancePlus is in Fil+ cached from chain + BalancePlus float64 `json:"balancePlus,omitempty"` + + // BalanceUpdatedAt is a timestamp when balance info was last pulled from chain + BalanceUpdatedAt string `json:"balanceUpdatedAt,omitempty"` + + // ContactInfo is optional email for SP wallets + ContactInfo string `json:"contactInfo,omitempty"` + + // id + ID int64 `json:"id,omitempty"` + + // Location is optional region, country for SP wallets + Location string `json:"location,omitempty"` // PrivateKey is the private key of the wallet PrivateKey string `json:"privateKey,omitempty"` + + // wallet type + WalletType ModelWalletType `json:"walletType,omitempty"` } // Validate validates this model wallet func (m *ModelWallet) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateWalletType(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } return nil } -// ContextValidate validates this model wallet based on context it is used +func (m *ModelWallet) validateWalletType(formats strfmt.Registry) error { + if swag.IsZero(m.WalletType) { // not required + return nil + } + + if err := m.WalletType.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("walletType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("walletType") + } + return err + } + + return nil +} + +// ContextValidate validate this model wallet based on the context it is used func (m *ModelWallet) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateWalletType(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ModelWallet) contextValidateWalletType(ctx context.Context, formats strfmt.Registry) error { + + if swag.IsZero(m.WalletType) { // not required + return nil + } + + if err := m.WalletType.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("walletType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("walletType") + } + return err + } + return nil } diff --git a/client/swagger/models/model_wallet_type.go b/client/swagger/models/model_wallet_type.go new file mode 100644 index 00000000..9e33fae9 --- /dev/null +++ b/client/swagger/models/model_wallet_type.go @@ -0,0 +1,78 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// ModelWalletType model wallet type +// +// swagger:model model.WalletType +type ModelWalletType string + +func NewModelWalletType(value ModelWalletType) *ModelWalletType { + return &value +} + +// Pointer returns a pointer to a freshly-allocated ModelWalletType. +func (m ModelWalletType) Pointer() *ModelWalletType { + return &m +} + +const ( + + // ModelWalletTypeUserWallet captures enum value "UserWallet" + ModelWalletTypeUserWallet ModelWalletType = "UserWallet" + + // ModelWalletTypeSPWallet captures enum value "SPWallet" + ModelWalletTypeSPWallet ModelWalletType = "SPWallet" +) + +// for schema +var modelWalletTypeEnum []interface{} + +func init() { + var res []ModelWalletType + if err := json.Unmarshal([]byte(`["UserWallet","SPWallet"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + modelWalletTypeEnum = append(modelWalletTypeEnum, v) + } +} + +func (m ModelWalletType) validateModelWalletTypeEnum(path, location string, value ModelWalletType) error { + if err := validate.EnumCase(path, location, value, modelWalletTypeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this model wallet type +func (m ModelWalletType) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateModelWalletTypeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this model wallet type based on context it is used +func (m ModelWalletType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/client/swagger/models/wallet_create_request.go b/client/swagger/models/wallet_create_request.go new file mode 100644 index 00000000..a1411264 --- /dev/null +++ b/client/swagger/models/wallet_create_request.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WalletCreateRequest wallet create request +// +// swagger:model wallet.CreateRequest +type WalletCreateRequest struct { + + // This is either "secp256k1" or "bls" + KeyType string `json:"keyType,omitempty"` +} + +// Validate validates this wallet create request +func (m *WalletCreateRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this wallet create request based on context it is used +func (m *WalletCreateRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *WalletCreateRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WalletCreateRequest) UnmarshalBinary(b []byte) error { + var res WalletCreateRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/cmd/admin/init.go b/cmd/admin/init.go index 59cf0eaf..ad3a0213 100644 --- a/cmd/admin/init.go +++ b/cmd/admin/init.go @@ -16,7 +16,7 @@ var InitCmd = &cli.Command{ Usage: "Name of the user or service that is running the Singularity for tracking and logging purpose", }, }, - Description: "This commands need to be run before running any singularity daemon or after any version upgrade", + Description: "This command needs to be run before running any singularity daemon or after any version upgrade", Action: func(c *cli.Context) error { db, closer, err := database.OpenFromCLI(c) if err != nil { diff --git a/cmd/admin/migrate.go b/cmd/admin/migrate.go new file mode 100644 index 00000000..ede8bf97 --- /dev/null +++ b/cmd/admin/migrate.go @@ -0,0 +1,94 @@ +package admin + +import ( + "fmt" + + "github.com/cockroachdb/errors" + "github.com/data-preservation-programs/singularity/cmd/cliutil" + "github.com/data-preservation-programs/singularity/database" + "github.com/data-preservation-programs/singularity/model" + "github.com/urfave/cli/v2" +) + +var MigrateCmd = &cli.Command{ + Name: "migrate", + Usage: "Migrate database up, down, or to a certain version", + Subcommands: []*cli.Command{ + { + Name: "up", + Usage: "Execute any unrun migrations", + Action: func(c *cli.Context) error { + db, closer, err := database.OpenFromCLI(c) + if err != nil { + return errors.WithStack(err) + } + defer closer.Close() + return model.GetMigrator(db).Migrate() + }, + }, + { + Name: "down", + Usage: "Rollback to previous migration", + Action: func(c *cli.Context) error { + db, closer, err := database.OpenFromCLI(c) + if err != nil { + return errors.WithStack(err) + } + defer closer.Close() + return model.GetMigrator(db).RollbackLast() + }, + }, + { + Name: "to", + Usage: "Migrate to specified version", + ArgsUsage: "", + Before: cliutil.CheckNArgs, + Action: func(c *cli.Context) error { + db, closer, err := database.OpenFromCLI(c) + if err != nil { + return errors.WithStack(err) + } + defer closer.Close() + + id := c.Args().Get(0) + + migrator := model.GetMigrator(db) + last, err := migrator.GetLastMigration() + if err != nil { + return errors.WithStack(err) + } + if last == id { + fmt.Println("Already at requested migration") + return nil + } + + alreadyRan, err := migrator.HasRunMigration(id) + if err != nil { + return errors.WithStack(err) + } else if alreadyRan { + return migrator.RollbackTo(id) + } else { + return migrator.MigrateTo(id) + } + }, + }, + { + Name: "which", + Usage: "Print current migration ID", + Action: func(c *cli.Context) error { + db, closer, err := database.OpenFromCLI(c) + if err != nil { + return errors.WithStack(err) + } + defer closer.Close() + + last, err := model.GetMigrator(db).GetLastMigration() + if err != nil { + return errors.WithStack(err) + } + fmt.Printf("Current migration: " + last + "\n") + return nil + }, + }, + }, +} diff --git a/cmd/app.go b/cmd/app.go index 2d21eab7..d59a6319 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -120,6 +120,7 @@ Upgrading: Subcommands: []*cli.Command{ admin.InitCmd, admin.ResetCmd, + admin.MigrateCmd, admin.MigrateDatasetCmd, admin.MigrateScheduleCmd, }, @@ -165,6 +166,7 @@ Upgrading: Category: "Operations", Usage: "Wallet management", Subcommands: []*cli.Command{ + wallet.CreateCmd, wallet.ImportCmd, wallet.ListCmd, wallet.RemoveCmd, diff --git a/cmd/dataprep_test.go b/cmd/dataprep_test.go index 3bea7156..9c7b6664 100644 --- a/cmd/dataprep_test.go +++ b/cmd/dataprep_test.go @@ -24,7 +24,7 @@ var testPreparation = model.Preparation{ MaxSize: 100, PieceSize: 200, Wallets: []model.Wallet{{ - ID: "client_id", + ActorID: "client_id", Address: "client_address", PrivateKey: "private_key", }}, diff --git a/cmd/deal_test.go b/cmd/deal_test.go index 4430543b..fd418270 100644 --- a/cmd/deal_test.go +++ b/cmd/deal_test.go @@ -24,7 +24,7 @@ func swapDealHandler(mockHandler deal.Handler) func() { func TestSendDealHandler(t *testing.T) { testutil.One(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { - err := db.Create(&model.Wallet{ID: "client_id"}).Error + err := db.Create(&model.Wallet{ActorID: "client_id"}).Error require.NoError(t, err) runner := NewRunner() defer runner.Save(t) @@ -42,7 +42,8 @@ func TestSendDealHandler(t *testing.T) { SectorStartEpoch: 1500, Price: "0", Verified: true, - ClientID: "client_id", + ClientID: ptr.Of(model.WalletID(1)), + ClientActorID: "client_id", }, nil).Once() _, _, err = runner.Run(ctx, "singularity deal send-manual --client client --provider provider --piece-cid piece_cid --piece-size 1024 --save") require.NoError(t, err) @@ -58,7 +59,8 @@ func TestSendDealHandler(t *testing.T) { SectorStartEpoch: 1500, Price: "0", Verified: true, - ClientID: "client_id", + ClientID: ptr.Of(model.WalletID(1)), + ClientActorID: "client_id", }, nil).Once() _, _, err = runner.Run(ctx, "singularity --verbose deal send-manual --client client --provider provider --piece-cid piece_cid --piece-size 1024 --save") require.NoError(t, err) @@ -89,7 +91,8 @@ func TestListDealHandler(t *testing.T) { Price: "0", Verified: true, ScheduleID: ptr.Of(model.ScheduleID(5)), - ClientID: "client_id", + ClientID: ptr.Of(model.WalletID(1)), + ClientActorID: "client_id", }, { ID: 2, @@ -107,7 +110,8 @@ func TestListDealHandler(t *testing.T) { Price: "0", Verified: false, ScheduleID: ptr.Of(model.ScheduleID(5)), - ClientID: "client_id", + ClientID: ptr.Of(model.WalletID(1)), + ClientActorID: "client_id", }, }, nil) _, _, err := runner.Run(ctx, "singularity deal list --preparation 1 --source source --schedule 5 --provider f01 --state active") diff --git a/cmd/wallet/create.go b/cmd/wallet/create.go new file mode 100644 index 00000000..6c08f37c --- /dev/null +++ b/cmd/wallet/create.go @@ -0,0 +1,61 @@ +package wallet + +import ( + "github.com/cockroachdb/errors" + "github.com/data-preservation-programs/singularity/cmd/cliutil" + "github.com/data-preservation-programs/singularity/database" + "github.com/data-preservation-programs/singularity/handler/wallet" + "github.com/urfave/cli/v2" +) + +var CreateCmd = &cli.Command{ + Name: "create", + Usage: "Create a new wallet", + ArgsUsage: "[type]", + Description: `Create a new Filecoin wallet using offline keypair generation. + +The wallet will be stored locally in the Singularity database and can be used for making deals and other operations. The private key is generated securely and stored encrypted. + +SUPPORTED KEY TYPES: + secp256k1 ECDSA using the secp256k1 curve (default, most common) + bls BLS signature scheme (Boneh-Lynn-Shacham) + +EXAMPLES: + # Create a secp256k1 wallet (default) + singularity wallet create + + # Create a secp256k1 wallet explicitly + singularity wallet create secp256k1 + + # Create a BLS wallet + singularity wallet create bls + +The newly created wallet address and other details will be displayed upon successful creation.`, + Before: cliutil.CheckNArgs, + Action: func(c *cli.Context) error { + db, closer, err := database.OpenFromCLI(c) + if err != nil { + return errors.WithStack(err) + } + defer closer.Close() + + // Default to secp256k1 if no type is provided + keyType := c.Args().Get(0) + if keyType == "" { + keyType = wallet.KTSecp256k1.String() + } + + w, err := wallet.Default.CreateHandler( + c.Context, + db, + wallet.CreateRequest{ + KeyType: keyType, + }) + if err != nil { + return errors.WithStack(err) + } + + cliutil.Print(c, w) + return nil + }, +} diff --git a/cmd/wallet_test.go b/cmd/wallet_test.go index ff2892cd..f10061d0 100644 --- a/cmd/wallet_test.go +++ b/cmd/wallet_test.go @@ -23,6 +23,24 @@ func swapWalletHandler(mockHandler wallet.Handler) func() { } } +func TestWalletCreate(t *testing.T) { + testutil.OneWithoutReset(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { + runner := NewRunner() + defer runner.Save(t) + mockHandler := new(wallet.MockWallet) + defer swapWalletHandler(mockHandler)() + mockHandler.On("CreateHandler", mock.Anything, mock.Anything, mock.Anything).Return(&model.Wallet{ + ActorID: "id", + Address: "address", + PrivateKey: "private", + }, nil) + _, _, err := runner.Run(ctx, "singularity wallet create") + require.NoError(t, err) + _, _, err = runner.Run(ctx, "singularity --verbose wallet create") + require.NoError(t, err) + }) +} + func TestWalletImport(t *testing.T) { testutil.OneWithoutReset(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { tmp := t.TempDir() @@ -33,7 +51,7 @@ func TestWalletImport(t *testing.T) { mockHandler := new(wallet.MockWallet) defer swapWalletHandler(mockHandler)() mockHandler.On("ImportHandler", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&model.Wallet{ - ID: "id", + ActorID: "id", Address: "address", PrivateKey: "private", }, nil) @@ -51,11 +69,11 @@ func TestWalletList(t *testing.T) { mockHandler := new(wallet.MockWallet) defer swapWalletHandler(mockHandler)() mockHandler.On("ListHandler", mock.Anything, mock.Anything).Return([]model.Wallet{{ - ID: "id1", + ActorID: "id1", Address: "address1", PrivateKey: "private1", }, { - ID: "id2", + ActorID: "id2", Address: "address2", PrivateKey: "private2", }}, nil) diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md index f1b32fcc..c9d134c1 100644 --- a/docs/en/SUMMARY.md +++ b/docs/en/SUMMARY.md @@ -40,6 +40,11 @@ * [Admin](cli-reference/admin/README.md) * [Init](cli-reference/admin/init.md) * [Reset](cli-reference/admin/reset.md) + * [Migrate](cli-reference/admin/migrate/README.md) + * [Up](cli-reference/admin/migrate/up.md) + * [Down](cli-reference/admin/migrate/down.md) + * [To](cli-reference/admin/migrate/to.md) + * [Which](cli-reference/admin/migrate/which.md) * [Migrate Dataset](cli-reference/admin/migrate-dataset.md) * [Migrate Schedule](cli-reference/admin/migrate-schedule.md) * [Download](cli-reference/download.md) @@ -62,6 +67,7 @@ * [Deal Pusher](cli-reference/run/deal-pusher.md) * [Download Server](cli-reference/run/download-server.md) * [Wallet](cli-reference/wallet/README.md) + * [Create](cli-reference/wallet/create.md) * [Import](cli-reference/wallet/import.md) * [List](cli-reference/wallet/list.md) * [Remove](cli-reference/wallet/remove.md) diff --git a/docs/en/cli-reference/admin/README.md b/docs/en/cli-reference/admin/README.md index f7e036d6..a0a6900a 100644 --- a/docs/en/cli-reference/admin/README.md +++ b/docs/en/cli-reference/admin/README.md @@ -11,6 +11,7 @@ USAGE: COMMANDS: init Initialize or upgrade the database reset Reset the database + migrate Migrate database up, down, or to a certain version migrate-dataset Migrate dataset from old singularity mongodb migrate-schedule Migrate schedule from old singularity mongodb help, h Shows a list of commands or help for one command diff --git a/docs/en/cli-reference/admin/init.md b/docs/en/cli-reference/admin/init.md index cb59e97a..b321cbf2 100644 --- a/docs/en/cli-reference/admin/init.md +++ b/docs/en/cli-reference/admin/init.md @@ -9,7 +9,7 @@ USAGE: singularity admin init [command options] DESCRIPTION: - This commands need to be run before running any singularity daemon or after any version upgrade + This command needs to be run before running any singularity daemon or after any version upgrade OPTIONS: --identity value Name of the user or service that is running the Singularity for tracking and logging purpose diff --git a/docs/en/cli-reference/admin/migrate/README.md b/docs/en/cli-reference/admin/migrate/README.md new file mode 100644 index 00000000..e97e8385 --- /dev/null +++ b/docs/en/cli-reference/admin/migrate/README.md @@ -0,0 +1,21 @@ +# Migrate database up, down, or to a certain version + +{% code fullWidth="true" %} +``` +NAME: + singularity admin migrate - Migrate database up, down, or to a certain version + +USAGE: + singularity admin migrate command [command options] + +COMMANDS: + up Execute any unrun migrations + down Rollback to previous migration + to Migrate to specified version + which Print current migration ID + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/cli-reference/admin/migrate/down.md b/docs/en/cli-reference/admin/migrate/down.md new file mode 100644 index 00000000..bd8d6db8 --- /dev/null +++ b/docs/en/cli-reference/admin/migrate/down.md @@ -0,0 +1,14 @@ +# Rollback to previous migration + +{% code fullWidth="true" %} +``` +NAME: + singularity admin migrate down - Rollback to previous migration + +USAGE: + singularity admin migrate down [command options] + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/cli-reference/admin/migrate/to.md b/docs/en/cli-reference/admin/migrate/to.md new file mode 100644 index 00000000..3b1f802e --- /dev/null +++ b/docs/en/cli-reference/admin/migrate/to.md @@ -0,0 +1,14 @@ +# Migrate to specified version + +{% code fullWidth="true" %} +``` +NAME: + singularity admin migrate to - Migrate to specified version + +USAGE: + singularity admin migrate to [command options] + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/cli-reference/admin/migrate/up.md b/docs/en/cli-reference/admin/migrate/up.md new file mode 100644 index 00000000..1abb1970 --- /dev/null +++ b/docs/en/cli-reference/admin/migrate/up.md @@ -0,0 +1,14 @@ +# Execute any unrun migrations + +{% code fullWidth="true" %} +``` +NAME: + singularity admin migrate up - Execute any unrun migrations + +USAGE: + singularity admin migrate up [command options] + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/cli-reference/admin/migrate/which.md b/docs/en/cli-reference/admin/migrate/which.md new file mode 100644 index 00000000..f8c6131d --- /dev/null +++ b/docs/en/cli-reference/admin/migrate/which.md @@ -0,0 +1,14 @@ +# Print current migration ID + +{% code fullWidth="true" %} +``` +NAME: + singularity admin migrate which - Print current migration ID + +USAGE: + singularity admin migrate which [command options] + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/cli-reference/wallet/README.md b/docs/en/cli-reference/wallet/README.md index 7096416a..1710883b 100644 --- a/docs/en/cli-reference/wallet/README.md +++ b/docs/en/cli-reference/wallet/README.md @@ -9,6 +9,7 @@ USAGE: singularity wallet command [command options] COMMANDS: + create Create a new wallet import Import a wallet from exported private key list List all imported wallets remove Remove a wallet diff --git a/docs/en/cli-reference/wallet/create.md b/docs/en/cli-reference/wallet/create.md new file mode 100644 index 00000000..743ffadd --- /dev/null +++ b/docs/en/cli-reference/wallet/create.md @@ -0,0 +1,35 @@ +# Create a new wallet + +{% code fullWidth="true" %} +``` +NAME: + singularity wallet create - Create a new wallet + +USAGE: + singularity wallet create [command options] [type] + +DESCRIPTION: + Create a new Filecoin wallet using offline keypair generation. + + The wallet will be stored locally in the Singularity database and can be used for making deals and other operations. The private key is generated securely and stored encrypted. + + SUPPORTED KEY TYPES: + secp256k1 ECDSA using the secp256k1 curve (default, most common) + bls BLS signature scheme (Boneh-Lynn-Shacham) + + EXAMPLES: + # Create a secp256k1 wallet (default) + singularity wallet create + + # Create a secp256k1 wallet explicitly + singularity wallet create secp256k1 + + # Create a BLS wallet + singularity wallet create bls + + The newly created wallet address and other details will be displayed upon successful creation. + +OPTIONS: + --help, -h show help +``` +{% endcode %} diff --git a/docs/en/web-api-reference/wallet.md b/docs/en/web-api-reference/wallet.md index 0aa3ad4f..28a14954 100644 --- a/docs/en/web-api-reference/wallet.md +++ b/docs/en/web-api-reference/wallet.md @@ -8,6 +8,10 @@ [https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml](https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml) {% endswagger %} +{% swagger src="https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml" path="/wallet/create" method="post" %} +[https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml](https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml) +{% endswagger %} + {% swagger src="https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml" path="/wallet/{address}" method="delete" %} [https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml](https://raw.githubusercontent.com/data-preservation-programs/singularity/main/docs/swagger/swagger.yaml) {% endswagger %} diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 424f209f..f4db4ee4 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -5532,6 +5532,52 @@ const docTemplate = `{ } } }, + "/wallet/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Wallet" + ], + "summary": "Create new wallet", + "operationId": "CreateWallet", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/wallet.CreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Wallet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/api.HTTPError" + } + } + } + } + }, "/wallet/{address}": { "delete": { "tags": [ @@ -6078,9 +6124,12 @@ const docTemplate = `{ "model.Deal": { "type": "object", "properties": { - "clientId": { + "clientActorId": { "type": "string" }, + "clientId": { + "type": "integer" + }, "createdAt": { "type": "string" }, @@ -6501,20 +6550,61 @@ const docTemplate = `{ "model.Wallet": { "type": "object", "properties": { + "actorId": { + "description": "ActorID is the short ID of the wallet", + "type": "string" + }, + "actorName": { + "description": "ActorName is readable label for the wallet", + "type": "string" + }, "address": { "description": "Address is the Filecoin full address of the wallet", "type": "string" }, + "balance": { + "description": "Balance is in Fil cached from chain", + "type": "number" + }, + "balancePlus": { + "description": "BalancePlus is in Fil+ cached from chain", + "type": "number" + }, + "balanceUpdatedAt": { + "description": "BalanceUpdatedAt is a timestamp when balance info was last pulled from chain", + "type": "string" + }, + "contactInfo": { + "description": "ContactInfo is optional email for SP wallets", + "type": "string" + }, "id": { - "description": "ID is the short ID of the wallet", + "type": "integer" + }, + "location": { + "description": "Location is optional region, country for SP wallets", "type": "string" }, "privateKey": { "description": "PrivateKey is the private key of the wallet", "type": "string" + }, + "walletType": { + "$ref": "#/definitions/model.WalletType" } } }, + "model.WalletType": { + "type": "string", + "enum": [ + "UserWallet", + "SPWallet" + ], + "x-enum-varnames": [ + "UserWallet", + "SPWallet" + ] + }, "schedule.CreateRequest": { "type": "object", "properties": { @@ -16403,6 +16493,15 @@ const docTemplate = `{ "store.PieceReader": { "type": "object" }, + "wallet.CreateRequest": { + "type": "object", + "properties": { + "keyType": { + "description": "This is either \"secp256k1\" or \"bls\"", + "type": "string" + } + } + }, "wallet.ImportRequest": { "type": "object", "properties": { diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 2bf8a3a6..5244a1e3 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -5526,6 +5526,52 @@ } } }, + "/wallet/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Wallet" + ], + "summary": "Create new wallet", + "operationId": "CreateWallet", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/wallet.CreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Wallet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/api.HTTPError" + } + } + } + } + }, "/wallet/{address}": { "delete": { "tags": [ @@ -6072,9 +6118,12 @@ "model.Deal": { "type": "object", "properties": { - "clientId": { + "clientActorId": { "type": "string" }, + "clientId": { + "type": "integer" + }, "createdAt": { "type": "string" }, @@ -6495,20 +6544,61 @@ "model.Wallet": { "type": "object", "properties": { + "actorId": { + "description": "ActorID is the short ID of the wallet", + "type": "string" + }, + "actorName": { + "description": "ActorName is readable label for the wallet", + "type": "string" + }, "address": { "description": "Address is the Filecoin full address of the wallet", "type": "string" }, + "balance": { + "description": "Balance is in Fil cached from chain", + "type": "number" + }, + "balancePlus": { + "description": "BalancePlus is in Fil+ cached from chain", + "type": "number" + }, + "balanceUpdatedAt": { + "description": "BalanceUpdatedAt is a timestamp when balance info was last pulled from chain", + "type": "string" + }, + "contactInfo": { + "description": "ContactInfo is optional email for SP wallets", + "type": "string" + }, "id": { - "description": "ID is the short ID of the wallet", + "type": "integer" + }, + "location": { + "description": "Location is optional region, country for SP wallets", "type": "string" }, "privateKey": { "description": "PrivateKey is the private key of the wallet", "type": "string" + }, + "walletType": { + "$ref": "#/definitions/model.WalletType" } } }, + "model.WalletType": { + "type": "string", + "enum": [ + "UserWallet", + "SPWallet" + ], + "x-enum-varnames": [ + "UserWallet", + "SPWallet" + ] + }, "schedule.CreateRequest": { "type": "object", "properties": { @@ -16397,6 +16487,15 @@ "store.PieceReader": { "type": "object" }, + "wallet.CreateRequest": { + "type": "object", + "properties": { + "keyType": { + "description": "This is either \"secp256k1\" or \"bls\"", + "type": "string" + } + } + }, "wallet.ImportRequest": { "type": "object", "properties": { diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 490d4d59..de07188a 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -372,8 +372,10 @@ definitions: type: object model.Deal: properties: - clientId: + clientActorId: type: string + clientId: + type: integer createdAt: type: string dealId: @@ -670,16 +672,47 @@ definitions: type: object model.Wallet: properties: + actorId: + description: ActorID is the short ID of the wallet + type: string + actorName: + description: ActorName is readable label for the wallet + type: string address: description: Address is the Filecoin full address of the wallet type: string + balance: + description: Balance is in Fil cached from chain + type: number + balancePlus: + description: BalancePlus is in Fil+ cached from chain + type: number + balanceUpdatedAt: + description: BalanceUpdatedAt is a timestamp when balance info was last pulled + from chain + type: string + contactInfo: + description: ContactInfo is optional email for SP wallets + type: string id: - description: ID is the short ID of the wallet + type: integer + location: + description: Location is optional region, country for SP wallets type: string privateKey: description: PrivateKey is the private key of the wallet type: string + walletType: + $ref: '#/definitions/model.WalletType' type: object + model.WalletType: + enum: + - UserWallet + - SPWallet + type: string + x-enum-varnames: + - UserWallet + - SPWallet schedule.CreateRequest: properties: allowedPieceCids: @@ -8177,6 +8210,12 @@ definitions: type: object store.PieceReader: type: object + wallet.CreateRequest: + properties: + keyType: + description: This is either "secp256k1" or "bls" + type: string + type: object wallet.ImportRequest: properties: privateKey: @@ -11847,6 +11886,36 @@ paths: summary: Remove a wallet tags: - Wallet + /wallet/create: + post: + consumes: + - application/json + operationId: CreateWallet + parameters: + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/wallet.CreateRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Wallet' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.HTTPError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.HTTPError' + summary: Create new wallet + tags: + - Wallet produces: - application/json swagger: "2.0" diff --git a/go.mod b/go.mod index 612b2d2d..fc1ffe8c 100644 --- a/go.mod +++ b/go.mod @@ -10,13 +10,14 @@ require ( github.com/cockroachdb/errors v1.11.3 github.com/data-preservation-programs/table v0.0.3 github.com/dustin/go-humanize v1.0.1 - github.com/fatih/color v1.17.0 - github.com/filecoin-project/go-address v1.1.0 + github.com/fatih/color v1.18.0 + github.com/filecoin-project/go-address v1.2.0 github.com/filecoin-project/go-cbor-util v0.0.1 - github.com/filecoin-project/go-fil-commcid v0.1.0 + github.com/filecoin-project/go-crypto v0.1.0 + github.com/filecoin-project/go-fil-commcid v0.2.0 github.com/filecoin-project/go-fil-commp-hashhash v0.2.1-0.20230811065821-2e9c683db589 github.com/filecoin-project/go-fil-markets v1.28.3 - github.com/filecoin-project/go-state-types v0.12.0 + github.com/filecoin-project/go-state-types v0.16.0 github.com/filecoin-project/lassie v0.23.2 github.com/filecoin-shipyard/boostly v0.0.0-20230813165216-a449c35ece79 github.com/fxamacker/cbor/v2 v2.4.0 @@ -35,7 +36,7 @@ require ( github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ipfs-routing v0.3.0 - github.com/ipfs/go-ipld-cbor v0.1.0 + github.com/ipfs/go-ipld-cbor v0.2.0 github.com/ipfs/go-ipld-format v0.6.0 github.com/ipfs/go-ipld-legacy v0.2.1 github.com/ipfs/go-log v1.0.5 @@ -63,6 +64,7 @@ require ( github.com/multiformats/go-varint v0.0.7 github.com/orlangure/gnomock v0.30.0 github.com/parnurzeal/gorequest v0.2.16 + github.com/phoreproject/bls v0.0.0-20200525203911-a88a5ae26844 github.com/rclone/rclone v1.62.2 github.com/rjNemo/underscore v0.5.0 github.com/robfig/cron/v3 v3.0.1 @@ -75,11 +77,18 @@ require ( go.mongodb.org/mongo-driver v1.12.1 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/text v0.22.0 + golang.org/x/text v0.23.0 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da gorm.io/driver/mysql v1.5.0 gorm.io/driver/postgres v1.5.0 gorm.io/driver/sqlite v1.5.2 - gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 + gorm.io/gorm v1.25.12 +) + +require ( + github.com/google/go-cmp v0.7.0 // indirect + github.com/shirou/gopsutil/v3 v3.23.3 // indirect + golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect ) require ( @@ -126,12 +135,12 @@ require ( github.com/elastic/gosigar v0.14.3 // indirect github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect - github.com/filecoin-project/go-amt-ipld/v4 v4.0.0 // indirect + github.com/filecoin-project/go-amt-ipld/v4 v4.4.0 // indirect github.com/filecoin-project/go-bitfield v0.2.4 // indirect github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7 // indirect github.com/filecoin-project/go-ds-versioning v0.1.2 // indirect github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect - github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 // indirect + github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 // indirect github.com/filecoin-project/go-padreader v0.0.1 // indirect github.com/filecoin-project/go-retrieval-types v1.2.0 // indirect github.com/filecoin-project/go-statemachine v1.0.3 // indirect @@ -139,12 +148,13 @@ require ( github.com/filecoin-project/specs-actors v0.9.13 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/gammazero/deque v0.2.1 // indirect github.com/geoffgarside/ber v1.1.0 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/glebarez/go-sqlite v1.21.1 // indirect github.com/go-chi/chi/v5 v5.0.8 // indirect + github.com/go-gormigrate/gormigrate/v2 v2.1.4 github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect @@ -244,7 +254,6 @@ require ( github.com/miekg/dns v1.1.63 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/montanaflynn/stats v0.7.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect @@ -290,7 +299,7 @@ require ( github.com/pion/turn/v4 v4.0.0 // indirect github.com/pion/webrtc/v4 v4.0.8 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/errors v0.9.1 github.com/pkg/sftp v1.13.6-0.20230213180117-971c283182b6 // indirect github.com/pkg/xattr v0.4.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -309,7 +318,6 @@ require ( github.com/rfjakob/eme v1.1.2 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shirou/gopsutil/v3 v3.23.3 // indirect github.com/shoenig/go-m1cpu v0.1.4 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect @@ -326,7 +334,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect - github.com/whyrusleeping/cbor-gen v0.1.2 // indirect + github.com/whyrusleeping/cbor-gen v0.3.1 // indirect github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect github.com/wlynxg/anet v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -340,6 +348,8 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/zeebo/blake3 v0.2.3 // indirect github.com/zeebo/errs v1.3.0 // indirect + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect @@ -348,24 +358,22 @@ require ( go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/mock v0.5.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect + golang.org/x/crypto v0.36.0 // indirect golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.34.0 // indirect + golang.org/x/net v0.35.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.28.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.29.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + golang.org/x/tools v0.30.0 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.36.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.5.1 // indirect + gotest.tools/v3 v3.5.2 // indirect lukechampine.com/blake3 v1.3.0 // indirect modernc.org/libc v1.22.3 // indirect modernc.org/mathutil v1.5.0 // indirect diff --git a/go.sum b/go.sum index 74329b33..8d929c15 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,7 @@ github.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzO github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo= github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI= +github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -158,6 +159,7 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPc github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210507181900-4e0be8d2fbb4/go.mod h1:UkVqoxmJlLgUvBjJD+GdJz6mgdSdf3UjX83xfwUAYDk= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dlespiau/covertool v0.0.0-20180314162135-b0c4c6d0583a/go.mod h1:/eQMcW3eA1bzKx23ZYI2H3tXPdJB5JWYTHzoUPBvQY4= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -192,8 +194,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/filecoin-project/dagstore v0.5.2 h1:Nd6oXdnolbbVhpMpkYT5PJHOjQp4OBSntHpMV5pxj3c= github.com/filecoin-project/dagstore v0.5.2/go.mod h1:mdqKzYrRBHf1pRMthYfMv3n37oOw0Tkx7+TxPt240M0= github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200910194244-f640612a1a1f/go.mod h1:+If3s2VxyjZn+KGGZIoRXBDSFQ9xL404JBJGf4WhEj0= @@ -201,12 +203,14 @@ github.com/filecoin-project/filecoin-ffi v0.30.4-0.20220519234331-bfd1f5f9fe38 h github.com/filecoin-project/filecoin-ffi v0.30.4-0.20220519234331-bfd1f5f9fe38/go.mod h1:GM5pXRYvQM7wyH6V2WtPnJ2k1jt+qotRkWLxBSRCOuE= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= github.com/filecoin-project/go-address v0.0.5/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= -github.com/filecoin-project/go-address v1.1.0 h1:ofdtUtEsNxkIxkDw67ecSmvtzaVSdcea4boAmLbnHfE= github.com/filecoin-project/go-address v1.1.0/go.mod h1:5t3z6qPmIADZBtuE9EIzi0EwzcRy2nVhpo0I/c1r0OA= +github.com/filecoin-project/go-address v1.2.0 h1:NHmWUE/J7Pi2JZX3gZt32XuY69o9StVZeJxdBodIwOE= +github.com/filecoin-project/go-address v1.2.0/go.mod h1:kQEQ4qZ99a51X7DjT9HiMT4yR6UwLJ9kznlxsOIeDAg= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-amt-ipld/v4 v4.0.0 h1:XM81BJ4/6h3FV0WfFjh74cIDIgqMbJsMBLM0fIuLUUk= github.com/filecoin-project/go-amt-ipld/v4 v4.0.0/go.mod h1:gF053YQ4BIpzTNDoEwHZas7U3oAwncDVGvOHyY8oDpE= +github.com/filecoin-project/go-amt-ipld/v4 v4.4.0 h1:6kvvMeSpIy4GTU5t3vPHZgWYIMRzGRKLJ73s/cltsoc= +github.com/filecoin-project/go-amt-ipld/v4 v4.4.0/go.mod h1:msgmUxTyRBZ6iXt+5dnUDnIb7SEFqdPsbB1wyo/G3ts= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW8p9au0C68JPgk= github.com/filecoin-project/go-bitfield v0.2.4/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= @@ -217,24 +221,26 @@ github.com/filecoin-project/go-commp-utils v0.1.3 h1:rTxbkNXZU7FLgdkBk8RsQIEOuPO github.com/filecoin-project/go-commp-utils v0.1.3/go.mod h1:3ENlD1pZySaUout0p9ANQrY3fDFoXdqyX04J+dWpK30= github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082a837/go.mod h1:e2YBjSblNVoBckkbv3PPqsq71q98oFkFqL7s1etViGo= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-crypto v0.0.1 h1:AcvpSGGCgjaY8y1az6AMfKQWreF/pWO2JJGLl6gCq6o= -github.com/filecoin-project/go-crypto v0.0.1/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0= +github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7 h1:v+zJS5B6pA3ptWZS4t8tbt1Hz9qENnN4nVr1w99aSWc= github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7/go.mod h1:V3Y4KbttaCwyg1gwkP7iai8CbQx4mZUGjd3h9GZWLKE= github.com/filecoin-project/go-ds-versioning v0.1.2 h1:to4pTadv3IeV1wvgbCbN6Vqd+fu+7tveXgv/rCEZy6w= github.com/filecoin-project/go-ds-versioning v0.1.2/go.mod h1:C9/l9PnB1+mwPa26BBVpCjG/XQCB0yj/q5CK2J8X1I4= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-commcid v0.0.0-20201016201715-d41df56b4f6a/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-commcid v0.1.0 h1:3R4ds1A9r6cr8mvZBfMYxTS88OqLYEo6roi+GiIeOh8= github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= +github.com/filecoin-project/go-fil-commcid v0.2.0 h1:B+5UX8XGgdg/XsdUpST4pEBviKkFOw+Fvl2bLhSKGpI= +github.com/filecoin-project/go-fil-commcid v0.2.0/go.mod h1:8yigf3JDIil+/WpqR5zoKyP0jBPCOGtEqq/K1CcMy9Q= github.com/filecoin-project/go-fil-commp-hashhash v0.2.1-0.20230811065821-2e9c683db589 h1:PP5FU5JVVDb7zODWZlgzbdmQDtwu3Mm0bK9Bg/Om5yc= github.com/filecoin-project/go-fil-commp-hashhash v0.2.1-0.20230811065821-2e9c683db589/go.mod h1:VH3fAFOru4yyWar4626IoS5+VGE8SfZiBODJLUigEo4= github.com/filecoin-project/go-fil-markets v1.28.3 h1:2cFu7tLZYrfNz4LnxjgERaVD7k5+Wwp0H76mnnTGPBk= github.com/filecoin-project/go-fil-markets v1.28.3/go.mod h1:eryxo/oVgIxaR5g5CNr9PlvZOi+u/bak0IsPL/PT1hk= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= -github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 h1:rVVNq0x6RGQIzCo1iiJlGFm9AGIZzeifggxtKMU7zmI= github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 h1:nYs6OPUF8KbZ3E8o9p9HJnQaE8iugjHR5WYVMcicDJc= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0/go.mod h1:s0qiHRhFyrgW0SvdQMSJFQxNa4xEIG5XvqCBZUEgcbc= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= github.com/filecoin-project/go-padreader v0.0.1 h1:8h2tVy5HpoNbr2gBRr+WD6zV6VD6XHig+ynSGJg8ZOs= github.com/filecoin-project/go-padreader v0.0.1/go.mod h1:VYVPJqwpsfmtoHnAmPx6MUwmrK6HIcDqZJiuZhtmfLQ= @@ -246,8 +252,8 @@ github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= 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/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024= -github.com/filecoin-project/go-state-types v0.12.0 h1:l+54FdFf3Exkzx7cpYCKoWUPReX7SUQlmT/h+9obVEM= -github.com/filecoin-project/go-state-types v0.12.0/go.mod h1:hm9GXjYuqB1xJs58Ei/ZKy8Nfb0532HP6bR9DI8a+kM= +github.com/filecoin-project/go-state-types v0.16.0 h1:ajIREDzTGfq71ofIQ29iZR1WXxmkvd2nQNc6ApcP1wI= +github.com/filecoin-project/go-state-types v0.16.0/go.mod h1:YCESyrqnyu17y0MazbV6Uwma5+BrMvEKEQp5QWeIf9g= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.3 h1:N07o6alys+V1tNoSTi4WuuoeNC4erS/6jE74+NsgQuk= github.com/filecoin-project/go-statemachine v1.0.3/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= @@ -266,12 +272,11 @@ github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= @@ -299,6 +304,8 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gormigrate/gormigrate/v2 v2.1.4 h1:KOPEt27qy1cNzHfMZbp9YTmEuzkY4F4wrdsJW9WFk1U= +github.com/go-gormigrate/gormigrate/v2 v2.1.4/go.mod h1:y/6gPAH6QGAgP1UfHMiXcqGeJ88/GRQbfCReE1JJD5Y= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -435,10 +442,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -448,6 +454,7 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190309163659-77426154d546/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -537,7 +544,6 @@ github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnO github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= -github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= @@ -584,8 +590,8 @@ github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9 github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-cbor v0.0.6-0.20211211231443-5d9b9e1f6fa8/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= -github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs= -github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk= +github.com/ipfs/go-ipld-cbor v0.2.0 h1:VHIW3HVIjcMd8m4ZLZbrYpwjzqlVUfjLM7oK4T5/YF0= +github.com/ipfs/go-ipld-cbor v0.2.0/go.mod h1:Cp8T7w1NKcu4AQJLqK0tWpd1nkgTxEVB5C6kVpLW6/0= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= @@ -628,7 +634,6 @@ github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6 github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s= github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 h1:QAI/Ridj0+foHD6epbxmB4ugxz9B4vmNdYSmQLGa05E= github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0/go.mod h1:odxGcpiQZLzP5+yGu84Ljo8y3EzCvNAQKEodHNsHLXA= -github.com/ipld/go-ipld-prime v0.19.0/go.mod h1:Q9j3BaVXwaA3o5JUDNvptDDr/x8+F7FG6XJ8WI3ILg4= github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo= @@ -641,7 +646,6 @@ github.com/ipni/go-libipni v0.6.6 h1:Ms2a0AkPgv1pCblSgqM8tKUz9NHmzn8JP0PO8fYUYZM github.com/ipni/go-libipni v0.6.6/go.mod h1:jh/TDrsKlKuwzHfaYIGTuHudFkX4ioe9zx0835x1fiQ= github.com/ipni/index-provider v0.12.0 h1:R3F6dxxKNv4XkE4GJZNLOG0bDEbBQ/S5iztXwSD8jhQ= github.com/ipni/index-provider v0.12.0/go.mod h1:GhyrADJp7n06fqoc1djzkvL4buZYHzV8SoWrlxEo5F4= -github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= @@ -720,9 +724,7 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -828,6 +830,7 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mmcloughlin/avo v0.0.0-20190318053554-7a0eb66183da/go.mod h1:lf5GMZxA5kz8dnCweJuER5Rmbx6dDu6qvw0fO3uYKK8= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -859,7 +862,6 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= @@ -869,7 +871,6 @@ github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpK github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= @@ -924,6 +925,8 @@ github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uC github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= +github.com/phoreproject/bls v0.0.0-20200525203911-a88a5ae26844 h1:Yflyn+XFLEu7RPzxovgEVLP6Es8JLJrHqdXunpm2ak4= +github.com/phoreproject/bls v0.0.0-20200525203911-a88a5ae26844/go.mod h1:xHJKf2TLXUA39Dhv8k5QmQOxLsbrb1KeTS/3ERfLeqc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= @@ -992,7 +995,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= @@ -1091,7 +1093,6 @@ github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN2 github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= @@ -1144,6 +1145,7 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= @@ -1158,12 +1160,10 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 h1:zMsHhfK9+Wdl1F7sIKLyx3wrOFofpb3rWFbA4HgcK5k= github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3/go.mod h1:R0Gbuw7ElaGSLOZUSwBm/GgVwMd30jWxBDdAyMOeTuc= -github.com/warpfork/go-testmark v0.10.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= @@ -1181,8 +1181,8 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210303213153-67a261a1d291/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.1.2 h1:WQFlrPhpcQl+M2/3dP5cvlTLWPVsL6LGBb9jJt6l/cA= -github.com/whyrusleeping/cbor-gen v0.1.2/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= +github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= @@ -1234,6 +1234,10 @@ github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= +gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= +gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= +gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= +gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= @@ -1295,6 +1299,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= +golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8= +golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1302,6 +1308,7 @@ golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1317,15 +1324,15 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1374,6 +1381,7 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190326090315-15845e8f865b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1411,8 +1419,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1438,8 +1446,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1451,6 +1459,7 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1506,7 +1515,6 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1517,10 +1525,11 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1528,10 +1537,11 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1544,10 +1554,11 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1559,11 +1570,13 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190106171756-3ef68632349c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190325223049-1d95b17f1b04/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1611,14 +1624,14 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -1746,12 +1759,12 @@ gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1 gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1761,7 +1774,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= @@ -1780,6 +1792,7 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/handler/admin/init.go b/handler/admin/init.go index 27b860ad..2bec942d 100644 --- a/handler/admin/init.go +++ b/handler/admin/init.go @@ -18,7 +18,8 @@ import ( // - An error, if any occurred during the operation. func (DefaultHandler) InitHandler(ctx context.Context, db *gorm.DB) error { db = db.WithContext(ctx) - err := model.AutoMigrate(db) + + err := model.GetMigrator(db).Migrate() if err != nil { return errors.WithStack(err) } diff --git a/handler/admin/reset.go b/handler/admin/reset.go index 4a2da222..c88397a6 100644 --- a/handler/admin/reset.go +++ b/handler/admin/reset.go @@ -21,12 +21,13 @@ import ( // - An error, if any occurred during the operation. func (DefaultHandler) ResetHandler(ctx context.Context, db *gorm.DB) error { db = db.WithContext(ctx) - err := model.DropAll(db) + migrator := model.GetMigrator(db) + err := migrator.DropAll() if err != nil { return errors.WithStack(err) } - err = model.AutoMigrate(db) + err = migrator.Migrate() if err != nil { return errors.WithStack(err) } diff --git a/handler/deal/list_test.go b/handler/deal/list_test.go index 96005ebf..b5bd9456 100644 --- a/handler/deal/list_test.go +++ b/handler/deal/list_test.go @@ -6,6 +6,7 @@ import ( "github.com/data-preservation-programs/singularity/model" "github.com/data-preservation-programs/singularity/util/testutil" + "github.com/gotidy/ptr" "github.com/stretchr/testify/require" "gorm.io/gorm" ) @@ -14,7 +15,7 @@ func TestListHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, SourceStorages: []model.Storage{{ Name: "storage", @@ -28,7 +29,7 @@ func TestListHandler(t *testing.T) { PreparationID: 1, }, State: model.DealActive, - ClientID: "f01", + ClientID: ptr.Of(model.WalletID(1)), Provider: "provider", }, }).Error diff --git a/handler/deal/schedule/create_test.go b/handler/deal/schedule/create_test.go index 4e1da85f..843adf39 100644 --- a/handler/deal/schedule/create_test.go +++ b/handler/deal/schedule/create_test.go @@ -190,7 +190,7 @@ func TestCreateHandler_InvalidProvider(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) @@ -207,7 +207,7 @@ func TestCreateHandler_DealSizeNotSetForCron(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) @@ -227,7 +227,7 @@ func TestCreateHandler_ScheduleDealSizeSetForNonCron(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) @@ -248,7 +248,7 @@ func TestCreateHandler_Success(t *testing.T) { err := db.Create(&model.Preparation{ Name: "name", Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) diff --git a/handler/deal/schedule/list_test.go b/handler/deal/schedule/list_test.go index e0c906f2..8169eedd 100644 --- a/handler/deal/schedule/list_test.go +++ b/handler/deal/schedule/list_test.go @@ -14,7 +14,7 @@ func TestListHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) diff --git a/handler/deal/schedule/pause_test.go b/handler/deal/schedule/pause_test.go index 17090f82..b7238460 100644 --- a/handler/deal/schedule/pause_test.go +++ b/handler/deal/schedule/pause_test.go @@ -15,7 +15,7 @@ func TestPauseHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) diff --git a/handler/deal/schedule/remove_test.go b/handler/deal/schedule/remove_test.go index afd825d3..dbb6c6ee 100644 --- a/handler/deal/schedule/remove_test.go +++ b/handler/deal/schedule/remove_test.go @@ -16,7 +16,7 @@ func TestRemoveSchedule_Success(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) @@ -27,7 +27,7 @@ func TestRemoveSchedule_Success(t *testing.T) { require.NoError(t, err) err = db.Create(&model.Deal{ - ClientID: "f01", + ClientID: ptr.Of(model.WalletID(1)), ScheduleID: ptr.Of(model.ScheduleID(1)), }).Error require.NoError(t, err) @@ -57,7 +57,7 @@ func TestRemoveSchedule_StillActive(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) diff --git a/handler/deal/schedule/resume_test.go b/handler/deal/schedule/resume_test.go index 85d87b95..eb4c20fc 100644 --- a/handler/deal/schedule/resume_test.go +++ b/handler/deal/schedule/resume_test.go @@ -15,7 +15,7 @@ func TestResumeHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "f01", + ActorID: "f01", }}, }).Error require.NoError(t, err) diff --git a/handler/deal/send-manual.go b/handler/deal/send-manual.go index 498cc7bb..3fe9a754 100644 --- a/handler/deal/send-manual.go +++ b/handler/deal/send-manual.go @@ -71,8 +71,8 @@ func (DefaultHandler) SendManualHandler( ) (*model.Deal, error) { db = db.WithContext(ctx) // Get the wallet object - wallet := model.Wallet{} - err := db.Where("id = ? OR address = ?", request.ClientAddress, request.ClientAddress).First(&wallet).Error + var wallet = model.Wallet{} + err := wallet.FindByIDOrAddr(db, request.ClientAddress) if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.Wrapf(handlererror.ErrNotFound, "client address %s not found", request.ClientAddress) } diff --git a/handler/deal/send-manual_test.go b/handler/deal/send-manual_test.go index 0d55f66a..b7272971 100644 --- a/handler/deal/send-manual_test.go +++ b/handler/deal/send-manual_test.go @@ -41,7 +41,7 @@ var proposal = Proposal{ func TestSendManualHandler_WalletNotFound(t *testing.T) { wallet := model.Wallet{ - ID: "f09999", + ActorID: "f09999", Address: "f10000", } @@ -59,7 +59,7 @@ func TestSendManualHandler_WalletNotFound(t *testing.T) { func TestSendManualHandler_InvalidPieceCID(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -79,7 +79,7 @@ func TestSendManualHandler_InvalidPieceCID(t *testing.T) { func TestSendManualHandler_InvalidPieceCID_NOTCOMMP(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -99,7 +99,7 @@ func TestSendManualHandler_InvalidPieceCID_NOTCOMMP(t *testing.T) { func TestSendManualHandler_InvalidPieceSize(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -119,7 +119,7 @@ func TestSendManualHandler_InvalidPieceSize(t *testing.T) { func TestSendManualHandler_InvalidPieceSize_NotPowerOfTwo(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -139,7 +139,7 @@ func TestSendManualHandler_InvalidPieceSize_NotPowerOfTwo(t *testing.T) { func TestSendManualHandler_InvalidRootCID(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -159,7 +159,7 @@ func TestSendManualHandler_InvalidRootCID(t *testing.T) { func TestSendManualHandler_InvalidDuration(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -179,7 +179,7 @@ func TestSendManualHandler_InvalidDuration(t *testing.T) { func TestSendManualHandler_InvalidStartDelay(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } @@ -199,7 +199,7 @@ func TestSendManualHandler_InvalidStartDelay(t *testing.T) { func TestSendManualHandler(t *testing.T) { wallet := model.Wallet{ - ID: "f01000", + ActorID: "f01000", Address: "f10000", } diff --git a/handler/file/deals_test.go b/handler/file/deals_test.go index b2b5838e..5785cf70 100644 --- a/handler/file/deals_test.go +++ b/handler/file/deals_test.go @@ -75,15 +75,18 @@ func TestGetFileDealsHandler(t *testing.T) { err = db.Create(cars).Error require.NoError(t, err) + wallet := &model.Wallet{ActorID: "f01", Address: "f11"} + err = db.Create(wallet).Error + require.NoError(t, err) deals := []model.Deal{{ PieceCID: model.CID(testCid1), - Wallet: &model.Wallet{}, + Wallet: wallet, }, { PieceCID: model.CID(testCid2), - Wallet: &model.Wallet{}, + Wallet: wallet, }, { PieceCID: model.CID(testCid2), - Wallet: &model.Wallet{}, + Wallet: wallet, }} err = db.Create(deals).Error require.NoError(t, err) diff --git a/handler/file/retrieve_test.go b/handler/file/retrieve_test.go index 46ea5b35..792c02fc 100644 --- a/handler/file/retrieve_test.go +++ b/handler/file/retrieve_test.go @@ -138,13 +138,17 @@ func TestRetrieveFileHandler(t *testing.T) { require.NoError(t, err) } + wallet := &model.Wallet{ActorID: "f01", Address: "f11"} + err = db.Create(wallet).Error + require.NoError(t, err) + deals := make([]model.Deal, 0, 4) for i, testCid := range testCids { deal := model.Deal{ State: model.DealActive, PieceCID: model.CID(testCid), Provider: "apples" + strconv.Itoa(i), - Wallet: &model.Wallet{}, + Wallet: wallet, } err = db.Create(&deal).Error require.NoError(t, err) @@ -158,7 +162,7 @@ func TestRetrieveFileHandler(t *testing.T) { State: state, PieceCID: model.CID(testCid), Provider: "oranges" + strconv.Itoa(i), - Wallet: &model.Wallet{}, + Wallet: wallet, } err = db.Create(&deal).Error require.NoError(t, err) @@ -409,7 +413,7 @@ func BenchmarkFilecoinRetrieve(b *testing.B) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() db = db.WithContext(ctx) - require.NoError(b, model.AutoMigrate(db)) + require.NoError(b, model.GetMigrator(db).Migrate()) path := b.TempDir() lsys := cidlink.DefaultLinkSystem() @@ -484,12 +488,16 @@ func BenchmarkFilecoinRetrieve(b *testing.B) { require.NoError(b, err) } + wallet := &model.Wallet{ActorID: "f01", Address: "f11"} + err = db.Create(wallet).Error + require.NoError(b, err) + for i, testCid := range testCids { deal := model.Deal{ State: model.DealActive, PieceCID: model.CID(testCid), Provider: "apples" + strconv.Itoa(i), - Wallet: &model.Wallet{}, + Wallet: wallet, } err = db.Create(&deal).Error require.NoError(b, err) @@ -502,7 +510,7 @@ func BenchmarkFilecoinRetrieve(b *testing.B) { State: state, PieceCID: model.CID(testCid), Provider: "oranges" + strconv.Itoa(i), - Wallet: &model.Wallet{}, + Wallet: wallet, } err = db.Create(&deal).Error require.NoError(b, err) diff --git a/handler/wallet/attach.go b/handler/wallet/attach.go index e2b374bf..c02d1b9c 100644 --- a/handler/wallet/attach.go +++ b/handler/wallet/attach.go @@ -38,7 +38,7 @@ func (DefaultHandler) AttachHandler( } var w model.Wallet - err = db.Where("address = ? OR id = ?", wallet, wallet).First(&w).Error + err = w.FindByIDOrAddr(db, wallet) if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.Wrapf(handlererror.ErrNotFound, "wallet %s not found", wallet) } diff --git a/handler/wallet/attach_test.go b/handler/wallet/attach_test.go index 1a0ee203..9a8ddca9 100644 --- a/handler/wallet/attach_test.go +++ b/handler/wallet/attach_test.go @@ -14,7 +14,7 @@ import ( func TestAttachHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Wallet{ - ID: "test", + ActorID: "test", }).Error require.NoError(t, err) err = db.Create(&model.Preparation{}).Error diff --git a/handler/wallet/create.go b/handler/wallet/create.go new file mode 100644 index 00000000..3bd7f118 --- /dev/null +++ b/handler/wallet/create.go @@ -0,0 +1,154 @@ +package wallet + +import ( + "context" + "crypto/rand" + "encoding/base64" + "encoding/hex" + "encoding/json" + + "github.com/cockroachdb/errors" + "github.com/data-preservation-programs/singularity/database" + "github.com/data-preservation-programs/singularity/handler/handlererror" + "github.com/data-preservation-programs/singularity/model" + "github.com/data-preservation-programs/singularity/util" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-crypto" + g1 "github.com/phoreproject/bls/g1pubs" + "golang.org/x/xerrors" + "gorm.io/gorm" +) + +type KeyType string + +const ( + KTSecp256k1 KeyType = "secp256k1" + KTBLS KeyType = "bls" + // TODO: add support for "delegated" or "secp256k1-ledger" types? +) + +func (kt KeyType) String() string { + return string(kt) +} + +// GenerateKey generates a new keypair and returns the private key and address. +// The keypair is generated using the specified key type (secp256k1 or BLS). +func GenerateKey(keyType string) (string, string, error) { + var privKey string + var addr address.Address + var err error + + switch keyType { + case KTSecp256k1.String(): + kb := make([]byte, 32) + _, err = rand.Read(kb) + if err != nil { + return "", "", xerrors.Errorf("failed to generate %s private key: %w", keyType, err) + } + + // Format the private key as a Lotus exported key (JSON format) + privKeyJSON := map[string]interface{}{ + "Type": "secp256k1", + "PrivateKey": base64.StdEncoding.EncodeToString(kb), + } + + privKeyBytes, err := json.Marshal(privKeyJSON) + if err != nil { + return "", "", xerrors.Errorf("failed to marshal private key to JSON: %w", err) + } + privKey = hex.EncodeToString(privKeyBytes) + + // Get the public key from private key + pubKey := crypto.PublicKey(kb) + addr, err = address.NewSecp256k1Address(pubKey) + if err != nil { + return "", "", xerrors.Errorf("failed to generate address from %s key: %w", keyType, err) + } + case KTBLS.String(): + priv, err := g1.RandKey(rand.Reader) + if err != nil { + return "", "", xerrors.Errorf("failed to generate %s private key: %w", keyType, err) + } + + // Format the private key as a Lotus exported key (JSON format) + // Convert the private key to base64 format + privKeyBytes := priv.Serialize() + privKeyJSON := map[string]interface{}{ + "Type": "bls", + "PrivateKey": base64.StdEncoding.EncodeToString(privKeyBytes[:]), + } + + privKeyJSONBytes, err := json.Marshal(privKeyJSON) + if err != nil { + return "", "", xerrors.Errorf("failed to marshal private key to JSON: %w", err) + } + privKey = hex.EncodeToString(privKeyJSONBytes) + + // Get the public key from private key + pub := g1.PrivToPub(priv) + pubKey := pub.Serialize() + addr, err = address.NewBLSAddress(pubKey[:]) + if err != nil { + return "", "", xerrors.Errorf("failed to generate address from %s key: %w", keyType, err) + } + default: + return "", "", xerrors.Errorf("unsupported key type: %s", keyType) + } + + return privKey, addr.String(), nil +} + +type CreateRequest struct { + KeyType string `json:"keyType"` // This is either "secp256k1" or "bls" +} + +// @ID CreateWallet +// @Summary Create new wallet +// @Tags Wallet +// @Accept json +// @Produce json +// @Param request body CreateRequest true "Request body" +// @Success 200 {object} model.Wallet +// @Failure 400 {object} api.HTTPError +// @Failure 500 {object} api.HTTPError +// @Router /wallet/create [post] +func _() {} + +// CreateHandler creates a new wallet using offline keypair generation and a new record in the local database. +// +// Parameters: +// - ctx: The context for database transactions and other operations. +// - db: A pointer to the gorm.DB instance representing the database connection. +// +// Returns: +// - A pointer to the created Wallet model if successful. +// - An error, if any occurred during the database insert operation. +func (DefaultHandler) CreateHandler( + ctx context.Context, + db *gorm.DB, + request CreateRequest, +) (*model.Wallet, error) { + db = db.WithContext(ctx) + + // Generate a new keypair + privateKey, address, err := GenerateKey(request.KeyType) + if err != nil { + return nil, errors.WithStack(err) + } + + wallet := model.Wallet{ + Address: address, + PrivateKey: privateKey, + } + err = database.DoRetry(ctx, func() error { + return db.Create(&wallet).Error + }) + if util.IsDuplicateKeyError(err) { + return nil, errors.Wrap(handlererror.ErrDuplicateRecord, "wallet already exists") + } + if err != nil { + return nil, errors.WithStack(err) + } + + return &wallet, nil +} diff --git a/handler/wallet/create_test.go b/handler/wallet/create_test.go new file mode 100644 index 00000000..a966c48f --- /dev/null +++ b/handler/wallet/create_test.go @@ -0,0 +1,35 @@ +package wallet + +import ( + "context" + "testing" + + "github.com/data-preservation-programs/singularity/util/testutil" + "github.com/stretchr/testify/require" + "gorm.io/gorm" +) + +func TestCreateHandler(t *testing.T) { + testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { + t.Run("success-secp256k1", func(t *testing.T) { + w, err := Default.CreateHandler(ctx, db, CreateRequest{KeyType: KTSecp256k1.String()}) + require.NoError(t, err) + require.NotEmpty(t, w.Address) + require.Equal(t, "f1", w.Address[:2]) + require.NotEmpty(t, w.PrivateKey) + }) + + t.Run("success-bls", func(t *testing.T) { + w, err := Default.CreateHandler(ctx, db, CreateRequest{KeyType: KTBLS.String()}) + require.NoError(t, err) + require.NotEmpty(t, w.Address) + require.Equal(t, "f3", w.Address[:2]) + require.NotEmpty(t, w.PrivateKey) + }) + + t.Run("invalid-key-type", func(t *testing.T) { + _, err := Default.CreateHandler(ctx, db, CreateRequest{KeyType: "invalid-type"}) + require.Error(t, err) + }) + }) +} diff --git a/handler/wallet/detach.go b/handler/wallet/detach.go index 7dee510f..6ea3d8d6 100644 --- a/handler/wallet/detach.go +++ b/handler/wallet/detach.go @@ -39,7 +39,7 @@ func (DefaultHandler) DetachHandler( } found, err := underscore.Find(preparation.Wallets, func(w model.Wallet) bool { - return w.ID == wallet || w.Address == wallet + return w.ActorID == wallet || w.Address == wallet }) if err != nil { return nil, errors.Wrapf(handlererror.ErrNotFound, "wallet %s not attached to preparation %d", wallet, preparationID) diff --git a/handler/wallet/detach_test.go b/handler/wallet/detach_test.go index 268da587..eba0205f 100644 --- a/handler/wallet/detach_test.go +++ b/handler/wallet/detach_test.go @@ -15,7 +15,7 @@ func TestDetachHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "test", + ActorID: "test", }}, }).Error require.NoError(t, err) diff --git a/handler/wallet/import.go b/handler/wallet/import.go index 3775d8cc..e27c162c 100644 --- a/handler/wallet/import.go +++ b/handler/wallet/import.go @@ -73,7 +73,7 @@ func (DefaultHandler) ImportHandler( } wallet := model.Wallet{ - ID: result, + ActorID: result, Address: result[:1] + addr.String()[1:], PrivateKey: request.PrivateKey, } diff --git a/handler/wallet/interface.go b/handler/wallet/interface.go index 163dc1c6..0a88d848 100644 --- a/handler/wallet/interface.go +++ b/handler/wallet/interface.go @@ -17,6 +17,11 @@ type Handler interface { preparation string, wallet string, ) (*model.Preparation, error) + CreateHandler( + ctx context.Context, + db *gorm.DB, + request CreateRequest, + ) (*model.Wallet, error) DetachHandler( ctx context.Context, db *gorm.DB, @@ -60,6 +65,11 @@ func (m *MockWallet) AttachHandler(ctx context.Context, db *gorm.DB, preparation return args.Get(0).(*model.Preparation), args.Error(1) } +func (m *MockWallet) CreateHandler(ctx context.Context, db *gorm.DB, request CreateRequest) (*model.Wallet, error) { + args := m.Called(ctx, db, request) + return args.Get(0).(*model.Wallet), args.Error(1) +} + func (m *MockWallet) DetachHandler(ctx context.Context, db *gorm.DB, preparation string, wallet string) (*model.Preparation, error) { args := m.Called(ctx, db, preparation, wallet) return args.Get(0).(*model.Preparation), args.Error(1) diff --git a/handler/wallet/listattached_test.go b/handler/wallet/listattached_test.go index 26fb17fc..9f830d84 100644 --- a/handler/wallet/listattached_test.go +++ b/handler/wallet/listattached_test.go @@ -15,7 +15,7 @@ func TestListAttachedHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { err := db.Create(&model.Preparation{ Wallets: []model.Wallet{{ - ID: "test", + ActorID: "test", }}, }).Error require.NoError(t, err) diff --git a/handler/wallet/remove.go b/handler/wallet/remove.go index cb5ecbfd..30a37eec 100644 --- a/handler/wallet/remove.go +++ b/handler/wallet/remove.go @@ -2,6 +2,7 @@ package wallet import ( "context" + "strconv" "github.com/cockroachdb/errors" "github.com/data-preservation-programs/singularity/database" @@ -27,7 +28,12 @@ func (DefaultHandler) RemoveHandler( db = db.WithContext(ctx) var affected int64 err := database.DoRetry(ctx, func() error { - tx := db.Where("address = ? OR id = ?", address, address).Delete(&model.Wallet{}) + var tx *gorm.DB + if id, err := strconv.Atoi(address); err == nil { + tx = db.Where("id = ?", id).Delete(&model.Wallet{}) + } else { + tx = db.Where("address = ? OR actor_id = ?", address, address).Delete(&model.Wallet{}) + } affected = tx.RowsAffected return tx.Error }) diff --git a/handler/wallet/remove_test.go b/handler/wallet/remove_test.go index dd52ecc0..8539cc96 100644 --- a/handler/wallet/remove_test.go +++ b/handler/wallet/remove_test.go @@ -15,7 +15,7 @@ func TestRemoveHandler(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { t.Run("success", func(t *testing.T) { err := db.Create(&model.Wallet{ - ID: "test", + ActorID: "test", }).Error require.NoError(t, err) err = Default.RemoveHandler(ctx, db, "test") diff --git a/migrate/migrate-dataset.go b/migrate/migrate-dataset.go index db3c5c74..38c97b54 100644 --- a/migrate/migrate-dataset.go +++ b/migrate/migrate-dataset.go @@ -263,9 +263,9 @@ func MigrateDataset(cctx *cli.Context) error { return errors.Wrap(err, "failed to connect to mongo") } - err = model.AutoMigrate(db) + err = model.GetMigrator(db).Migrate() if err != nil { - return errors.Wrap(err, "failed to auto-migrate database") + return errors.Wrap(err, "failed to migrate database") } resp, err := mg.Database("singularity").Collection("scanningrequests").Find(ctx, bson.M{}) diff --git a/migrate/migrations/202505010830_initial_schema.go b/migrate/migrations/202505010830_initial_schema.go new file mode 100644 index 00000000..989f3795 --- /dev/null +++ b/migrate/migrations/202505010830_initial_schema.go @@ -0,0 +1,249 @@ +package migrations + +import ( + "strconv" + "time" + + "github.com/go-gormigrate/gormigrate/v2" + "github.com/ipfs/go-cid" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +// NOTE: This recreates original models at time of transition from AutoMigrate +// to versioned migrations so that future modifications to the actual models +// don't change this initial schema definition. +type StringSlice []string +type ConfigMap map[string]string +type CID cid.Cid +type ClientConfig struct { + ConnectTimeout *time.Duration `cbor:"1,keyasint,omitempty" json:"connectTimeout,omitempty" swaggertype:"primitive,integer"` // HTTP Client Connect timeout + Timeout *time.Duration `cbor:"2,keyasint,omitempty" json:"timeout,omitempty" swaggertype:"primitive,integer"` // IO idle timeout + ExpectContinueTimeout *time.Duration `cbor:"3,keyasint,omitempty" json:"expectContinueTimeout,omitempty" swaggertype:"primitive,integer"` // Timeout when using expect / 100-continue in HTTP + InsecureSkipVerify *bool `cbor:"4,keyasint,omitempty" json:"insecureSkipVerify,omitempty"` // Do not verify the server SSL certificate (insecure) + NoGzip *bool `cbor:"5,keyasint,omitempty" json:"noGzip,omitempty"` // Don't set Accept-Encoding: gzip + UserAgent *string `cbor:"6,keyasint,omitempty" json:"userAgent,omitempty"` // Set the user-agent to a specified string + CaCert []string `cbor:"7,keyasint,omitempty" json:"caCert,omitempty"` // Paths to CA certificate used to verify servers + ClientCert *string `cbor:"8,keyasint,omitempty" json:"clientCert,omitempty"` // Path to Client SSL certificate (PEM) for mutual TLS auth + ClientKey *string `cbor:"9,keyasint,omitempty" json:"clientKey,omitempty"` // Path to Client SSL private key (PEM) for mutual TLS auth + Headers map[string]string `cbor:"10,keyasint,omitempty" json:"headers,omitempty"` // Set HTTP header for all transactions + DisableHTTP2 *bool `cbor:"11,keyasint,omitempty" json:"disableHttp2,omitempty"` // Disable HTTP/2 in the transport + DisableHTTPKeepAlives *bool `cbor:"12,keyasint,omitempty" json:"disableHttpKeepAlives,omitempty"` // Disable HTTP keep-alives and use each connection once. + RetryMaxCount *int `cbor:"13,keyasint,omitempty" json:"retryMaxCount,omitempty"` // Maximum number of retries. Default is 10 retries. + RetryDelay *time.Duration `cbor:"14,keyasint,omitempty" json:"retryDelay,omitempty" swaggertype:"primitive,integer"` // Delay between retries. Default is 1s. + RetryBackoff *time.Duration `cbor:"15,keyasint,omitempty" json:"retryBackoff,omitempty" swaggertype:"primitive,integer"` // Constant backoff between retries. Default is 1s. + RetryBackoffExponential *float64 `cbor:"16,keyasint,omitempty" json:"retryBackoffExponential,omitempty"` // Exponential backoff between retries. Default is 1.0. + SkipInaccessibleFile *bool `cbor:"17,keyasint,omitempty" json:"skipInaccessibleFile,omitempty"` // Skip inaccessible files. Default is false. + UseServerModTime *bool `cbor:"18,keyasint,omitempty" json:"useServerModTime,omitempty"` // Use server modified time instead of object metadata + LowLevelRetries *int `cbor:"19,keyasint,omitempty" json:"lowlevelRetries,omitempty"` // Maximum number of retries for low-level client errors. Default is 10 retries. + ScanConcurrency *int `cbor:"20,keyasint,omitempty" json:"scanConcurrency,omitempty"` // Maximum number of concurrent scan requests. Default is 1. +} +type WorkerType string +type Worker struct { + ID string `gorm:"primaryKey" json:"id"` + LastHeartbeat time.Time `json:"lastHeartbeat"` + Hostname string `json:"hostname"` + Type WorkerType `json:"type"` +} +type Global struct { + Key string `gorm:"primaryKey" json:"key"` + Value string `json:"value"` +} +type Wallet struct { + ID string `gorm:"primaryKey;size:15" json:"id"` // ID is the short ID of the wallet + Address string `gorm:"index" json:"address"` // Address is the Filecoin full address of the wallet + PrivateKey string `json:"privateKey,omitempty" table:"-"` // PrivateKey is the private key of the wallet +} +type PreparationID uint32 +type Preparation struct { + ID PreparationID `gorm:"primaryKey" json:"id"` + Name string `gorm:"unique" json:"name"` + CreatedAt time.Time `json:"createdAt" table:"verbose;format:2006-01-02 15:04:05"` + UpdatedAt time.Time `json:"updatedAt" table:"verbose;format:2006-01-02 15:04:05"` + DeleteAfterExport bool `json:"deleteAfterExport"` // DeleteAfterExport is a flag that indicates whether the source files should be deleted after export. + MaxSize int64 `json:"maxSize"` + PieceSize int64 `json:"pieceSize"` + NoInline bool `json:"noInline"` + NoDag bool `json:"noDag"` + Wallets []Wallet `gorm:"many2many:wallet_assignments" json:"wallets,omitempty" swaggerignore:"true" table:"expand"` + SourceStorages []Storage `gorm:"many2many:source_attachments;constraint:OnDelete:CASCADE" json:"sourceStorages,omitempty" table:"expand;header:Source Storages:"` + OutputStorages []Storage `gorm:"many2many:output_attachments;constraint:OnDelete:CASCADE" json:"outputStorages,omitempty" table:"expand;header:Output Storages:"` +} + +func (s *Preparation) FindByIDOrName(db *gorm.DB, name string, preloads ...string) error { + id, err := strconv.ParseUint(name, 10, 32) + if err == nil { + for _, preload := range preloads { + db = db.Preload(preload) + } + return db.First(s, id).Error + } else { + for _, preload := range preloads { + db = db.Preload(preload) + } + return db.Where("name = ?", name).First(s).Error + } +} +func (s *Preparation) SourceAttachments(db *gorm.DB, preloads ...string) ([]SourceAttachment, error) { + for _, preload := range preloads { + db = db.Preload(preload) + } + var attachments []SourceAttachment + err := db.Where("preparation_id = ?", s.ID).Find(&attachments).Error + return attachments, errors.Wrap(err, "failed to find source attachments") +} + +type StorageID uint32 +type Storage struct { + ID StorageID `cbor:"-" gorm:"primaryKey" json:"id"` + Name string `cbor:"-" gorm:"unique" json:"name"` + CreatedAt time.Time `cbor:"-" json:"createdAt" table:"verbose;format:2006-01-02 15:04:05"` + UpdatedAt time.Time `cbor:"-" json:"updatedAt" table:"verbose;format:2006-01-02 15:04:05"` + Type string `cbor:"1,keyasint,omitempty" json:"type"` + Path string `cbor:"2,keyasint,omitempty" json:"path"` // Path is the path to the storage root. + Config ConfigMap `cbor:"3,keyasint,omitempty" gorm:"type:JSON" json:"config" table:"verbose"` // Config is a map of key-value pairs that can be used to store RClone options. + ClientConfig ClientConfig `cbor:"4,keyasint,omitempty" gorm:"type:JSON" json:"clientConfig" table:"verbose"` // ClientConfig is the HTTP configuration for the storage, if applicable. + PreparationsAsSource []Preparation `cbor:"-" gorm:"many2many:source_attachments;constraint:OnDelete:CASCADE" json:"preparationsAsSource,omitempty" table:"expand;header:As Source: "` + PreparationsAsOutput []Preparation `cbor:"-" gorm:"many2many:output_attachments;constraint:OnDelete:CASCADE" json:"preparationsAsOutput,omitempty" table:"expand;header:As Output: "` +} +type ScheduleID uint32 +type ScheduleState string +type Schedule struct { + ID ScheduleID `gorm:"primaryKey" json:"id"` + CreatedAt time.Time `json:"createdAt" table:"verbose;format:2006-01-02 15:04:05"` + UpdatedAt time.Time `json:"updatedAt" table:"verbose;format:2006-01-02 15:04:05"` + URLTemplate string `json:"urlTemplate" table:"verbose"` + HTTPHeaders ConfigMap `gorm:"type:JSON" json:"httpHeaders" table:"verbose"` + Provider string `json:"provider"` + PricePerGBEpoch float64 `json:"pricePerGbEpoch" table:"verbose"` + PricePerGB float64 `json:"pricePerGb" table:"verbose"` + PricePerDeal float64 `json:"pricePerDeal" table:"verbose"` + TotalDealNumber int `json:"totalDealNumber" table:"verbose"` + TotalDealSize int64 `json:"totalDealSize"` + Verified bool `json:"verified"` + KeepUnsealed bool `json:"keepUnsealed" table:"verbose"` + AnnounceToIPNI bool `gorm:"column:announce_to_ipni" json:"announceToIpni" table:"verbose"` + StartDelay time.Duration `json:"startDelay" swaggertype:"primitive,integer"` + Duration time.Duration `json:"duration" swaggertype:"primitive,integer"` + State ScheduleState `json:"state"` + ScheduleCron string `json:"scheduleCron"` + ScheduleCronPerpetual bool `json:"scheduleCronPerpetual"` + ScheduleDealNumber int `json:"scheduleDealNumber"` + ScheduleDealSize int64 `json:"scheduleDealSize"` + MaxPendingDealNumber int `json:"maxPendingDealNumber"` + MaxPendingDealSize int64 `json:"maxPendingDealSize"` + Notes string `json:"notes"` + ErrorMessage string `json:"errorMessage" table:"verbose"` + AllowedPieceCIDs StringSlice `gorm:"type:JSON;column:allowed_piece_cids" json:"allowedPieceCids" table:"verbose"` + Force bool `json:"force"` + PreparationID PreparationID `json:"preparationId"` + Preparation *Preparation `gorm:"foreignKey:PreparationID;constraint:OnDelete:CASCADE" json:"preparation,omitempty" swaggerignore:"true" table:"expand"` +} +type DealState string +type DealID uint64 +type Deal struct { + ID DealID `gorm:"primaryKey" json:"id" table:"verbose"` + CreatedAt time.Time `json:"createdAt" table:"verbose;format:2006-01-02 15:04:05"` + UpdatedAt time.Time `json:"updatedAt" table:"verbose;format:2006-01-02 15:04:05"` + LastVerifiedAt *time.Time `json:"lastVerifiedAt" table:"verbose;format:2006-01-02 15:04:05"` // LastVerifiedAt is the last time the deal was verified as active by the tracker + DealID *uint64 `gorm:"unique" json:"dealId"` + State DealState `gorm:"index:idx_pending" json:"state"` + Provider string `json:"provider"` + ProposalID string `json:"proposalId" table:"verbose"` + Label string `json:"label" table:"verbose"` + PieceCID CID `gorm:"column:piece_cid;index;size:255" json:"pieceCid" swaggertype:"string"` + PieceSize int64 `json:"pieceSize"` + StartEpoch int32 `json:"startEpoch"` + EndEpoch int32 `json:"endEpoch" table:"verbose"` + SectorStartEpoch int32 `json:"sectorStartEpoch" table:"verbose"` + Price string `json:"price"` + Verified bool `json:"verified"` + ErrorMessage string `json:"errorMessage" table:"verbose"` + ScheduleID *ScheduleID `json:"scheduleId" table:"verbose"` + Schedule *Schedule `gorm:"foreignKey:ScheduleID;constraint:OnDelete:SET NULL" json:"schedule,omitempty" swaggerignore:"true" table:"expand"` + ClientID string `gorm:"index:idx_pending" json:"clientId"` + Wallet *Wallet `gorm:"foreignKey:ClientID;constraint:OnDelete:SET NULL" json:"wallet,omitempty" swaggerignore:"true" table:"expand"` +} +type OutputAttachment struct { + ID uint32 `gorm:"primaryKey"` + PreparationID PreparationID + StorageID StorageID +} +type SourceAttachment struct { + ID uint32 `gorm:"primaryKey"` + PreparationID PreparationID + StorageID StorageID +} +type Job struct { + ID uint32 `gorm:"primaryKey"` + PreparationID PreparationID + Status string + CreatedAt time.Time +} +type File struct { + ID uint32 `gorm:"primaryKey"` + Path string + Size int64 + ModifiedAt time.Time +} +type FileRange struct { + ID uint32 `gorm:"primaryKey"` + FileID uint32 + Offset int64 + Length int64 +} +type Directory struct { + ID uint32 `gorm:"primaryKey"` + Path string + Size int64 +} +type Car struct { + ID uint32 `gorm:"primaryKey"` + RootCID CID + Size int64 +} +type CarBlock struct { + ID uint32 `gorm:"primaryKey"` + CarID uint32 + CID CID + Size int64 +} + +// Create migration for initial database schema +func _202505010830_initial_schema() *gormigrate.Migration { + var InitTables = []any{ + &Worker{}, + &Global{}, + &Preparation{}, + &Storage{}, + &OutputAttachment{}, + &SourceAttachment{}, + &Job{}, + &File{}, + &FileRange{}, + &Directory{}, + &Car{}, + &CarBlock{}, + &Deal{}, + &Schedule{}, + &Wallet{}, + } + + return &gormigrate.Migration{ + ID: "202505010830", + Migrate: func(tx *gorm.DB) error { + // NOTE: this should match any existing database at the time of transition + // to versioned migration strategy + return tx.AutoMigrate(InitTables...) + }, + Rollback: func(tx *gorm.DB) error { + for _, table := range InitTables { + err := tx.Migrator().DropTable(table) + if err != nil { + return errors.Wrap(err, "failed to drop table") + } + } + return nil + }, + } +} diff --git a/migrate/migrations/202505010840_wallet_actor_id.go b/migrate/migrations/202505010840_wallet_actor_id.go new file mode 100644 index 00000000..2291f8f8 --- /dev/null +++ b/migrate/migrations/202505010840_wallet_actor_id.go @@ -0,0 +1,173 @@ +package migrations + +import ( + "fmt" + "time" + + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// Create migration for initial database schema +func _202505010840_wallet_actor_id() *gormigrate.Migration { + // Table names + const WALLET_TABLE = "wallets" + const DEAL_TABLE = "deals" + + // Temporary struct for old Wallet schema + type OldWallet struct { + ID string `gorm:"primaryKey;size:15" json:"id"` // ID is the short ID of the wallet + Address string `gorm:"index" json:"address"` // Address is the Filecoin full address of the wallet + PrivateKey string `json:"privateKey,omitempty" table:"-"` // PrivateKey is the private key of the wallet + } + + type WalletType string + const ( + UserWallet WalletType = "UserWallet" + SPWallet WalletType = "SPWallet" + ) + + type WalletID uint + + // Temporary struct for new Wallet schema + type NewWallet struct { + ID WalletID `gorm:"primaryKey" json:"id"` + ActorID string `gorm:"index;size:15" json:"actorId"` // ActorID is the short ID of the wallet + ActorName string `json:"actorName"` // ActorName is readable label for the wallet + Address string `gorm:"uniqueIndex;size:86" json:"address"` // Address is the Filecoin full address of the wallet + Balance float64 `json:"balance"` // Balance is in Fil cached from chain + BalancePlus float64 `json:"balancePlus"` // BalancePlus is in Fil+ cached from chain + BalanceUpdatedAt *time.Time `json:"balanceUpdatedAt" table:"verbose;format:2006-01-02 15:04:05"` // BalanceUpdatedAt is a timestamp when balance info was last pulled from chain + ContactInfo string `json:"contactInfo"` // ContactInfo is optional email for SP wallets + Location string `json:"location"` // Location is optional region, country for SP wallets + PrivateKey string `json:"privateKey,omitempty" table:"-"` // PrivateKey is the private key of the wallet + WalletType WalletType `gorm:"default:'UserWallet'" json:"walletType"` + } + + type NewDeal struct { + ID uint64 `gorm:"column:id"` + ClientActorID string `json:"clientActorId"` + ClientID *WalletID `gorm:"index:idx_pending" json:"clientId"` + Wallet *Wallet `gorm:"foreignKey:ClientID;constraint:OnDelete:SET NULL" json:"wallet,omitempty" swaggerignore:"true" table:"expand"` + } + type OldDeal struct { + ID uint64 `gorm:"column:id"` + ClientID string `gorm:"index:idx_pending" json:"clientId"` + Wallet *Wallet `gorm:"foreignKey:ClientID;constraint:OnDelete:SET NULL" json:"wallet,omitempty" swaggerignore:"true" table:"expand"` + } + + return &gormigrate.Migration{ + ID: "202505010840", + Migrate: func(tx *gorm.DB) error { + // Create new table + if err := tx.Migrator().AutoMigrate(&NewWallet{}); err != nil { + return fmt.Errorf("failed to create new wallets table: %w", err) + } + + // Copy data from old to new table + var oldWallets []OldWallet + if err := tx.Table(WALLET_TABLE).Find(&oldWallets).Error; err != nil { + return err + } + // Create map to store old ID => new ID of wallet + idMap := make(map[string]WalletID) + for _, oldWallet := range oldWallets { + newWallet := NewWallet{ + ActorID: oldWallet.ID, + Address: oldWallet.Address, + PrivateKey: oldWallet.PrivateKey, + WalletType: UserWallet, + } + if err := tx.Create(&newWallet).Error; err != nil { + return err + } + idMap[newWallet.ActorID] = newWallet.ID + } + + // Modify Deals table to replace ActorID FK with new ID column + // Drop old FK constraint since Wallet ID type changed + if err := tx.Migrator().DropConstraint(DEAL_TABLE, "fk_deals_wallet"); err != nil { + // constraint might not exist or have different name, so continue on + fmt.Printf("Warning: could not drop foreign key constraint: %v\n", err) + } + // Rename old column to make it clear it's not the FK + if err := tx.Migrator().RenameColumn(DEAL_TABLE, "client_id", "client_actor_id"); err != nil { + return fmt.Errorf("failed to rename ClientID to ClientActorID: %w", err) + } + // Add new column for updated type + if err := tx.Table(DEAL_TABLE).Migrator().AddColumn(&NewDeal{}, "ClientID"); err != nil { + return fmt.Errorf("failed to create new client_id column: %w", err) + } + // Update data using ID map + var dealRows []NewDeal + if err := tx.Table(DEAL_TABLE).Select("id, client_actor_id, client_id").Find(&dealRows).Error; err != nil { + return fmt.Errorf("failed to fetch deal rows: %w", err) + } + for _, deal := range dealRows { + if err := tx.Table(DEAL_TABLE).Where("id = ?", deal.ID).Update("client_id", idMap[deal.ClientActorID]).Error; err != nil { + return fmt.Errorf("failed to update deal %d with new ClientID: %w", deal.ID, err) + } + } + + // Add new FK constraint on deals table + if err := tx.Table(DEAL_TABLE).Migrator().CreateConstraint(&NewDeal{}, "Wallet"); err != nil { + return fmt.Errorf("failed to add foreign key constraint: %w", err) + } + + // Drop old wallets table and rename new wallets table + if err := tx.Migrator().DropTable(WALLET_TABLE); err != nil { + return err + } + return tx.Migrator().RenameTable(&NewWallet{}, WALLET_TABLE) + }, + Rollback: func(tx *gorm.DB) error { + // Create old table + err := tx.Migrator().CreateTable(&OldWallet{}) + if err != nil { + return err + } + + // Copy data from new to old table + var newWallets []NewWallet + if err := tx.Table(WALLET_TABLE).Find(&newWallets).Error; err != nil { + return err + } + + for _, newWallet := range newWallets { + oldWallet := OldWallet{ + ID: newWallet.ActorID, + Address: newWallet.Address, + PrivateKey: newWallet.PrivateKey, + } + if err := tx.Create(&oldWallet).Error; err != nil { + return err + } + } + + // Modify Deal table back to original FK + // Drop old FK constraint since Wallet ID type changed + if err := tx.Migrator().DropConstraint(DEAL_TABLE, "fk_deals_wallet"); err != nil { + // constraint might not exist or have different name, so continue on + fmt.Printf("Warning: could not drop foreign key constraint: %v\n", err) + } + // Drop new column + if err := tx.Table(DEAL_TABLE).Migrator().DropColumn(&NewDeal{}, "ClientID"); err != nil { + return fmt.Errorf("failed to drop ClientID column: %w", err) + } + // Rename old column back to FK + if err := tx.Migrator().RenameColumn(DEAL_TABLE, "client_actor_id", "client_id"); err != nil { + return fmt.Errorf("failed to rename ClientID to ClientActorID: %w", err) + } + // Add original constraint back + if err := tx.Table(DEAL_TABLE).Migrator().CreateConstraint(&OldDeal{}, "Wallet"); err != nil { + return fmt.Errorf("failed to add foreign key constraint: %w", err) + } + + // Drop new table and rename old table + if err := tx.Migrator().DropTable(WALLET_TABLE); err != nil { + return err + } + return tx.Migrator().RenameTable(&OldWallet{}, WALLET_TABLE) + }, + } +} diff --git a/migrate/migrations/migrations.go b/migrate/migrations/migrations.go new file mode 100644 index 00000000..8931f781 --- /dev/null +++ b/migrate/migrations/migrations.go @@ -0,0 +1,13 @@ +package migrations + +import ( + "github.com/go-gormigrate/gormigrate/v2" +) + +// Get collection of all migrations in order +func GetMigrations() []*gormigrate.Migration { + return []*gormigrate.Migration{ + _202505010830_initial_schema(), + _202505010840_wallet_actor_id(), + } +} diff --git a/model/basetypes.go b/model/basetypes.go index 2341d85f..85527f00 100644 --- a/model/basetypes.go +++ b/model/basetypes.go @@ -8,10 +8,9 @@ import ( "strings" "time" - "slices" - "github.com/cockroachdb/errors" "github.com/ipfs/go-cid" + "slices" ) var ( diff --git a/model/migrate.go b/model/migrate.go index b2953c42..2a8a945d 100644 --- a/model/migrate.go +++ b/model/migrate.go @@ -5,6 +5,8 @@ import ( "encoding/base64" "github.com/cockroachdb/errors" + "github.com/data-preservation-programs/singularity/migrate/migrations" + "github.com/go-gormigrate/gormigrate/v2" "github.com/google/uuid" logging "github.com/ipfs/go-log/v2" "gorm.io/gorm" @@ -31,78 +33,161 @@ var Tables = []any{ var logger = logging.Logger("model") -// AutoMigrate attempts to automatically migrate the database schema. +// Options for gormigrate instance +var options = &gormigrate.Options{ + TableName: "migrations", + IDColumnName: "id", + IDColumnSize: 255, + UseTransaction: false, + ValidateUnknownMigrations: false, +} + +// NOTE: this NEEDS to match the values in MigrationOptions above // -// This function performs a few operations: -// 1. Automatically migrates the tables in the database to match the structures defined in the application. -// 2. Creates an instance ID if it doesn't already exist. -// 3. Generates a new encryption salt and stores it in the database if it doesn't already exist. +// type struct { +// ID string `gorm:"primaryKey;column:;size:"` +// } +type migration struct { + ID string `gorm:"primaryKey;column:id;size:255"` +} + +// Handle initializing any database if no migrations are found // -// The purpose of the auto-migration feature is to simplify schema changes and manage -// basic system configurations without manually altering the database. This is especially -// useful during development or when deploying updates that include schema changes. +// In the case of existing database: +// 1. Migrations table is created and first migration is inserted, which should match the existing, if outdated, data +// 2. Any remaining migrations are run // -// Parameters: -// - db: A pointer to a gorm.DB object, which provides database access. -// -// Returns: -// - An error if any issues arise during the process, otherwise nil. -func AutoMigrate(db *gorm.DB) error { - logger.Info("Auto migrating tables") - err := db.AutoMigrate(Tables...) - if err != nil { - return errors.Wrap(err, "failed to auto migrate") - } +// In the case of a new database: +// 1. Automatically migrates the tables in the database to match the current structures defined in the application. +// 2. Creates an instance ID if it doesn't already exist. +// 3. Generates a new encryption salt and stores it in the database if it doesn't already exist. +func _init(db *gorm.DB) error { + logger.Info("Initializing database") - logger.Debug("Creating instance id") - err = db.Clauses(clause.OnConflict{ - DoNothing: true, - }).Create(&Global{Key: "instance_id", Value: uuid.NewString()}).Error - if err != nil { - return errors.Wrap(err, "failed to create instance id") + // If this is an existing database before versioned migration strategy was implemented + if db.Migrator().HasTable("wallets") && !db.Migrator().HasColumn("wallets", "actor_id") { + // NOTE: We're going to have to recreate some internals of Gormigrate. It would be cleaner + // to use them directly but they're private methods. The general idea is to run all the + // migration functions _except_ the first which is hopefully the state of the database + // when they were on the older automigrate strategy. + logger.Info("Manually creating versioned migration table in existing database") + + // Create migrations table + err := db.Table(options.TableName).AutoMigrate(&migration{}) + if err != nil { + return errors.Wrap(err, "failed to create migrations table on init") + } + + logger.Info("Manually running missing migrations") + // Skip first migration, run the rest to get current + for _, m := range migrations.GetMigrations()[1:] { + err = m.Migrate(db) + if err != nil { + return errors.Wrap(err, "failed to run migration with ID: "+m.ID) + } + } + } else { + logger.Info("Auto migrating tables in clean database") + // This is a brand new database, run automigrate script on current schema + err := db.AutoMigrate(Tables...) + if err != nil { + return errors.Wrap(err, "failed to auto migrate") + } + + logger.Debug("Creating instance id") + err = db.Clauses(clause.OnConflict{ + DoNothing: true, + }).Create(&Global{Key: "instance_id", Value: uuid.NewString()}).Error + if err != nil { + return errors.Wrap(err, "failed to create instance id") + } + + salt := make([]byte, 8) + _, err = rand.Read(salt) + if err != nil { + return errors.Wrap(err, "failed to generate salt") + } + encoded := base64.StdEncoding.EncodeToString(salt) + row := Global{ + Key: "salt", + Value: encoded, + } + + logger.Debug("Creating encryption salt") + err = db.Clauses(clause.OnConflict{ + DoNothing: true, + }).Create(row).Error + if err != nil { + return errors.Wrap(err, "failed to create salt") + } } - salt := make([]byte, 8) - _, err = rand.Read(salt) + return nil +} + +type migrator struct { + gormigrate.Gormigrate + db *gorm.DB + Options gormigrate.Options +} + +// Drop all current database tables +func (m *migrator) DropAll() error { + tables, err := m.db.Migrator().GetTables() if err != nil { - return errors.Wrap(err, "failed to generate salt") + return errors.Wrap(err, "Failed to get tables") } - encoded := base64.StdEncoding.EncodeToString(salt) - row := Global{ - Key: "salt", - Value: encoded, + for _, t := range tables { + err = m.db.Migrator().DropTable(t) + if err != nil { + return errors.Wrap(err, "Failed to drop all tables") + } } + return nil +} - logger.Debug("Creating encryption salt") - err = db.Clauses(clause.OnConflict{ - DoNothing: true, - }).Create(row).Error +// Get all migrations run +func (m *migrator) GetMigrationsRun() ([]migration, error) { + var migrations []migration + err := m.db.Find(&migrations).Error if err != nil { - return errors.Wrap(err, "failed to create salt") + return nil, err } + return migrations, nil +} - return nil +// Get ID of last migration ran +func (m *migrator) GetLastMigration() (string, error) { + migrations, err := m.GetMigrationsRun() + if len(migrations) == 0 || err != nil { + return "", err + } + return migrations[len(migrations)-1].ID, nil } -// DropAll removes all tables specified in the Tables slice from the database. -// -// This function is typically used during development or testing where a clean database -// slate is required. It iterates over the predefined Tables list and drops each table. -// Care should be taken when using this function in production environments as it will -// result in data loss. +// Has migration ID ran +func (m *migrator) HasRunMigration(id string) (bool, error) { + var count int64 + err := m.db.Table(m.Options.TableName).Where(m.Options.IDColumnName+" = ?", id).Count(&count).Error + return count > 0, err +} + +// Setup new Gormigrate instance // // Parameters: // - db: A pointer to a gorm.DB object, which provides database access. // // Returns: -// - An error if any issues arise during the table drop process, otherwise nil. -func DropAll(db *gorm.DB) error { - logger.Info("Dropping all tables") - for _, table := range Tables { - err := db.Migrator().DropTable(table) - if err != nil { - return errors.Wrap(err, "failed to drop table") - } +// - A migration interface +func GetMigrator(db *gorm.DB) *migrator { + g := gormigrate.New(db, options, migrations.GetMigrations()) + + // Initialize database with current schema if no previous migrations are found + g.InitSchema(_init) + + return &migrator{ + *g, + db, + *options, } - return nil } diff --git a/model/replication.go b/model/replication.go index 4bcada94..9a2e69e2 100644 --- a/model/replication.go +++ b/model/replication.go @@ -4,6 +4,9 @@ import ( "fmt" "strconv" "time" + + "github.com/cockroachdb/errors" + "gorm.io/gorm" ) type DealState string @@ -81,6 +84,7 @@ type Deal struct { LastVerifiedAt *time.Time `json:"lastVerifiedAt" table:"verbose;format:2006-01-02 15:04:05"` // LastVerifiedAt is the last time the deal was verified as active by the tracker DealID *uint64 `gorm:"unique" json:"dealId"` State DealState `gorm:"index:idx_pending" json:"state"` + ClientActorID string `json:"clientActorId"` Provider string `json:"provider"` ProposalID string `json:"proposalId" table:"verbose"` Label string `json:"label" table:"verbose"` @@ -96,13 +100,13 @@ type Deal struct { // Associations ScheduleID *ScheduleID `json:"scheduleId" table:"verbose"` Schedule *Schedule `gorm:"foreignKey:ScheduleID;constraint:OnDelete:SET NULL" json:"schedule,omitempty" swaggerignore:"true" table:"expand"` - ClientID string `gorm:"index:idx_pending" json:"clientId"` + ClientID *WalletID `gorm:"index:idx_pending" json:"clientId"` Wallet *Wallet `gorm:"foreignKey:ClientID;constraint:OnDelete:SET NULL" json:"wallet,omitempty" swaggerignore:"true" table:"expand"` } // Key returns a mostly unique key to match deal from locally proposed deals and deals from the chain. func (d Deal) Key() string { - return fmt.Sprintf("%s-%s-%s-%d-%d", d.ClientID, d.Provider, d.PieceCID.String(), d.StartEpoch, d.EndEpoch) + return fmt.Sprintf("%s-%s-%s-%d-%d", d.ClientActorID, d.Provider, d.PieceCID.String(), d.StartEpoch, d.EndEpoch) } type ScheduleID uint32 @@ -141,8 +145,49 @@ type Schedule struct { Preparation *Preparation `gorm:"foreignKey:PreparationID;constraint:OnDelete:CASCADE" json:"preparation,omitempty" swaggerignore:"true" table:"expand"` } +// WalletType distinguishes between user wallets and storage provider wallets +type WalletType string + +const ( + UserWallet WalletType = "UserWallet" + SPWallet WalletType = "SPWallet" +) + +var WalletTypes = []WalletType{ + UserWallet, + SPWallet, +} + +var WalletTypeStrings = []string{ + string(UserWallet), + string(SPWallet), +} + +type WalletID uint + type Wallet struct { - ID string `gorm:"primaryKey;size:15" json:"id"` // ID is the short ID of the wallet - Address string `gorm:"index" json:"address"` // Address is the Filecoin full address of the wallet - PrivateKey string `json:"privateKey,omitempty" table:"-"` // PrivateKey is the private key of the wallet + ID WalletID `gorm:"primaryKey" json:"id"` + ActorID string `gorm:"index;size:15" json:"actorId"` // ActorID is the short ID of the wallet + ActorName string `json:"actorName"` // ActorName is readable label for the wallet + Address string `gorm:"uniqueIndex;size:86" json:"address"` // Address is the Filecoin full address of the wallet + Balance float64 `json:"balance"` // Balance is in Fil cached from chain + BalancePlus float64 `json:"balancePlus"` // BalancePlus is in Fil+ cached from chain + BalanceUpdatedAt *time.Time `json:"balanceUpdatedAt" table:"verbose;format:2006-01-02 15:04:05"` // BalanceUpdatedAt is a timestamp when balance info was last pulled from chain + ContactInfo string `json:"contactInfo"` // ContactInfo is optional email for SP wallets + Location string `json:"location"` // Location is optional region, country for SP wallets + PrivateKey string `json:"privateKey,omitempty" table:"-"` // PrivateKey is the private key of the wallet + WalletType WalletType `gorm:"default:'UserWallet'" json:"walletType"` +} + +// Find Wallet by ID, ActorID, or Address +func (wallet *Wallet) FindByIDOrAddr(db *gorm.DB, param interface{}) error { + switch v := param.(type) { + case uint, uint64: + return db.Where("id = ?", v).First(wallet).Error + case string: + // TODO: should we determine whether "f0.." or "f1..", for example? + return db.Where("actor_id = ? OR address = ?", v, v).First(wallet).Error + default: + return errors.Errorf("unsupported parameter type: %T", param) + } } diff --git a/replication/makedeal.go b/replication/makedeal.go index b074b2d7..d8dc039b 100644 --- a/replication/makedeal.go +++ b/replication/makedeal.go @@ -5,11 +5,10 @@ import ( "encoding/base64" "encoding/json" "fmt" + "slices" "strings" "time" - "slices" - "github.com/cockroachdb/errors" "github.com/data-preservation-programs/singularity/analytics" "github.com/data-preservation-programs/singularity/model" @@ -518,7 +517,7 @@ func (d DealConfig) GetPrice(pieceSize int64, duration time.Duration) big.Int { func (d DealMakerImpl) MakeDeal(ctx context.Context, walletObj model.Wallet, car model.Car, dealConfig DealConfig, ) (*model.Deal, error) { - logger.Infow("making deal", "client", walletObj.ID, "pieceCID", car.PieceCID.String(), "provider", dealConfig.Provider) + logger.Infow("making deal", "client", walletObj.ActorID, "pieceCID", car.PieceCID.String(), "provider", dealConfig.Provider) now := time.Now().UTC() addr, err := address.NewFromString(walletObj.Address) if err != nil { @@ -589,14 +588,14 @@ func (d DealMakerImpl) MakeDeal(ctx context.Context, walletObj model.Wallet, } dealModel := &model.Deal{ - State: model.DealProposed, - ClientID: walletObj.ID, - Provider: dealConfig.Provider, - Label: cid.Cid(car.RootCID).String(), - PieceCID: car.PieceCID, - PieceSize: car.PieceSize, - //nolint:gosec // G115: Safe conversion, max int32 epoch won't occur until year 4062 - StartEpoch: int32(startEpoch), + State: model.DealProposed, + ClientID: &walletObj.ID, + ClientActorID: walletObj.ActorID, + Provider: dealConfig.Provider, + Label: cid.Cid(car.RootCID).String(), + PieceCID: car.PieceCID, + PieceSize: car.PieceSize, + StartEpoch: int32(startEpoch), //nolint:gosec // G115: Safe conversion, max int32 epoch won't occur until year 4062 EndEpoch: int32(endEpoch), Price: dealConfig.GetPrice(car.PieceSize, dealConfig.Duration).String(), @@ -635,7 +634,7 @@ func queueDealEvent(deal model.Deal) { DataCID: deal.Label, PieceSize: deal.PieceSize, Provider: deal.Provider, - Client: deal.ClientID, + Client: deal.ClientActorID, Verified: deal.Verified, StartEpoch: deal.StartEpoch, EndEpoch: deal.EndEpoch - deal.StartEpoch, diff --git a/replication/makedeal_test.go b/replication/makedeal_test.go index b1496c2f..81ca77ee 100644 --- a/replication/makedeal_test.go +++ b/replication/makedeal_test.go @@ -116,7 +116,7 @@ func TestDealMaker_MakeDeal(t *testing.T) { maker := NewDealMaker(nil, client, time.Hour, time.Second) defer maker.Close() wallet := model.Wallet{ - ID: "f047684", + ActorID: "f047684", Address: addr, PrivateKey: key, } diff --git a/replication/wallet_test.go b/replication/wallet_test.go index cc41d3d9..3a23394b 100644 --- a/replication/wallet_test.go +++ b/replication/wallet_test.go @@ -48,10 +48,10 @@ func TestDatacapWalletChooser_Choose(t *testing.T) { // Set up the test data wallets := []model.Wallet{ - {ID: "1", Address: "address1"}, - {ID: "2", Address: "address2"}, - {ID: "3", Address: "address3"}, - {ID: "4", Address: "address4"}, + {ActorID: "1", Address: "address1"}, + {ActorID: "2", Address: "address2"}, + {ActorID: "3", Address: "address3"}, + {ActorID: "4", Address: "address4"}, } // Set up expectations for the lotusClient mock @@ -82,10 +82,11 @@ func TestDatacapWalletChooser_Choose(t *testing.T) { err := db.Create(&wallets).Error require.NoError(t, err) err = db.Create(&model.Deal{ - ClientID: "3", - Verified: true, - State: model.DealProposed, - PieceSize: 500000, + ClientID: &wallets[2].ID, + ClientActorID: wallets[2].ActorID, + Verified: true, + State: model.DealProposed, + PieceSize: 500000, }).Error require.NoError(t, err) @@ -111,8 +112,8 @@ func TestRandomWalletChooser(t *testing.T) { chooser := &RandomWalletChooser{} ctx := context.Background() wallet, err := chooser.Choose(ctx, []model.Wallet{ - {ID: "1", Address: "address1"}, - {ID: "2", Address: "address2"}, + {ActorID: "1", Address: "address1"}, + {ActorID: "2", Address: "address2"}, }) require.NoError(t, err) require.Contains(t, wallet.Address, "address") diff --git a/service/dealpusher/dealpusher.go b/service/dealpusher/dealpusher.go index a9f1a037..f687dd4c 100644 --- a/service/dealpusher/dealpusher.go +++ b/service/dealpusher/dealpusher.go @@ -435,9 +435,6 @@ func NewDealPusher(db *gorm.DB, lotusURL string, } lotusClient := util.NewLotusClient(lotusURL, lotusToken) dealMaker := replication.NewDealMaker(lotusClient, h, time.Hour, time.Minute) - if err != nil { - return nil, errors.Wrap(err, "failed to init deal maker") - } return &DealPusher{ dbNoContext: db, activeScheduleCancelFunc: make(map[model.ScheduleID]context.CancelFunc), diff --git a/service/dealpusher/dealpusher_test.go b/service/dealpusher/dealpusher_test.go index 909d5ec4..ab1fe9ce 100644 --- a/service/dealpusher/dealpusher_test.go +++ b/service/dealpusher/dealpusher_test.go @@ -41,7 +41,8 @@ func (m *MockDealMaker) MakeDeal(ctx context.Context, walletObj model.Wallet, ca deal.ID = 0 deal.PieceCID = car.PieceCID deal.PieceSize = car.PieceSize - deal.ClientID = walletObj.ID + deal.ClientID = &walletObj.ID + deal.ClientActorID = walletObj.ActorID deal.Provider = dealConfig.Provider deal.Verified = dealConfig.Verified deal.ProposalID = uuid.NewString() @@ -112,7 +113,7 @@ func TestDealMakerService_FailtoSend(t *testing.T) { SourceStorages: []model.Storage{{}}, Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: client, Address: "f0xx", }, }}, State: model.ScheduleActive, @@ -168,7 +169,7 @@ func TestDealMakerService_Cron(t *testing.T) { SourceStorages: []model.Storage{{}}, Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: client, Address: "f0xx", }, }}, State: model.ScheduleActive, @@ -263,7 +264,7 @@ func TestDealMakerService_ScheduleWithConstraints(t *testing.T) { SourceStorages: []model.Storage{{}}, Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: client, Address: "f0xx", }, }}, State: model.ScheduleActive, @@ -367,12 +368,12 @@ func TestDealmakerService_Force(t *testing.T) { ctx, cancel := context.WithCancel(ctx) defer cancel() provider := "f0miner" - client := "f0client" + clientActorID := "f0client" schedule := model.Schedule{ Preparation: &model.Preparation{ Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: clientActorID, Address: "f0xx", }, }, SourceStorages: []model.Storage{{}}, @@ -381,6 +382,7 @@ func TestDealmakerService_Force(t *testing.T) { Provider: provider, Force: true, } + clientID := &schedule.Preparation.Wallets[0].ID err = db.Create(&schedule).Error require.NoError(t, err) mockDealmaker.On("MakeDeal", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&model.Deal{ @@ -399,11 +401,12 @@ func TestDealmakerService_Force(t *testing.T) { require.NoError(t, err) err = db.Create([]model.Deal{ { - Provider: provider, - ClientID: client, - PieceCID: pieceCID, - PieceSize: 1024, - State: model.DealProposed, + Provider: provider, + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCID, + PieceSize: 1024, + State: model.DealProposed, }, }).Error require.NoError(t, err) @@ -426,12 +429,12 @@ func TestDealMakerService_MaxReplica(t *testing.T) { ctx, cancel := context.WithCancel(ctx) defer cancel() provider := "f0miner" - client := "f0client" + clientActorID := "f0client" schedule := model.Schedule{ Preparation: &model.Preparation{ Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: clientActorID, Address: "f0xx", }, }, SourceStorages: []model.Storage{{}}, @@ -439,6 +442,7 @@ func TestDealMakerService_MaxReplica(t *testing.T) { State: model.ScheduleActive, Provider: provider, } + clientID := &schedule.Preparation.Wallets[0].ID err = db.Create(&schedule).Error require.NoError(t, err) mockDealmaker.On("MakeDeal", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&model.Deal{ @@ -456,12 +460,13 @@ func TestDealMakerService_MaxReplica(t *testing.T) { require.NoError(t, err) err = db.Create([]model.Deal{ { - ScheduleID: &schedule.ID, - Provider: "another", - ClientID: client, - PieceCID: pieceCID, - PieceSize: 1024, - State: model.DealProposed, + ScheduleID: &schedule.ID, + Provider: "another", + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCID, + PieceSize: 1024, + State: model.DealProposed, }}).Error require.NoError(t, err) service.runOnce(ctx) @@ -492,12 +497,12 @@ func TestDealMakerService_NewScheduleOneOff(t *testing.T) { // All deal proposal will be accepted // Create test schedule provider := "f0miner" - client := "f0client" + clientActorID := "f0client" schedule := model.Schedule{ Preparation: &model.Preparation{ Wallets: []model.Wallet{ { - ID: client, Address: "f0xx", + ActorID: clientActorID, Address: "f0xx", }, }, SourceStorages: []model.Storage{{}}, @@ -506,6 +511,7 @@ func TestDealMakerService_NewScheduleOneOff(t *testing.T) { Provider: provider, AllowedPieceCIDs: underscore.Map(pieceCIDs[:5], func(cid model.CID) string { return cid.String() }), } + clientID := &schedule.Preparation.Wallets[0].ID err = db.Create(&schedule).Error require.NoError(t, err) @@ -566,35 +572,39 @@ func TestDealMakerService_NewScheduleOneOff(t *testing.T) { // Test5 is not proposed err = db.Create([]model.Deal{ { - ScheduleID: &schedule.ID, - Provider: provider, - ClientID: client, - PieceCID: pieceCIDs[0], - PieceSize: 1024, - State: model.DealProposed, + ScheduleID: &schedule.ID, + Provider: provider, + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCIDs[0], + PieceSize: 1024, + State: model.DealProposed, }, { - ScheduleID: &schedule.ID, - Provider: provider, - ClientID: client, - PieceCID: pieceCIDs[1], - PieceSize: 1024, - State: model.DealProposalExpired, + ScheduleID: &schedule.ID, + Provider: provider, + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCIDs[1], + PieceSize: 1024, + State: model.DealProposalExpired, }, { - ScheduleID: &schedule.ID, - Provider: provider, - ClientID: client, - PieceCID: pieceCIDs[2], - PieceSize: 1024, - State: model.DealActive, + ScheduleID: &schedule.ID, + Provider: provider, + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCIDs[2], + PieceSize: 1024, + State: model.DealActive, }, { - Provider: provider, - ClientID: client, - PieceCID: pieceCIDs[3], - PieceSize: 1024, - State: model.DealProposed, + Provider: provider, + ClientID: clientID, + ClientActorID: clientActorID, + PieceCID: pieceCIDs[3], + PieceSize: 1024, + State: model.DealProposed, }, }).Error require.NoError(t, err) diff --git a/service/dealtracker/dealtracker.go b/service/dealtracker/dealtracker.go index 36a2714c..967cbb01 100644 --- a/service/dealtracker/dealtracker.go +++ b/service/dealtracker/dealtracker.go @@ -382,7 +382,7 @@ type KnownDeal struct { } type UnknownDeal struct { ID model.DealID - ClientID string + ClientID *model.WalletID Provider string PieceCID model.CID StartEpoch int32 @@ -432,8 +432,8 @@ func (d *DealTracker) runOnce(ctx context.Context) error { walletIDs := make(map[string]struct{}) for _, wallet := range wallets { - Logger.Infof("tracking deals for wallet %s", wallet.ID) - walletIDs[wallet.ID] = struct{}{} + Logger.Infof("tracking deals for wallet %s", wallet.ActorID) + walletIDs[wallet.ActorID] = struct{}{} } knownDeals := make(map[uint64]model.DealState) @@ -454,14 +454,14 @@ func (d *DealTracker) runOnce(ctx context.Context) error { unknownDeals := make(map[string][]UnknownDeal) rows, err = db.Model(&model.Deal{}).Where("deal_id IS NULL AND state NOT IN ?", []model.DealState{model.DealExpired, model.DealProposalExpired}). - Select("id", "deal_id", "state", "client_id", "provider", "piece_cid", + Select("id", "deal_id", "state", "client_id", "client_actor_id", "provider", "piece_cid", "start_epoch", "end_epoch").Rows() if err != nil { return errors.WithStack(err) } for rows.Next() { var deal model.Deal - err = rows.Scan(&deal.ID, &deal.DealID, &deal.State, &deal.ClientID, &deal.Provider, &deal.PieceCID, &deal.StartEpoch, &deal.EndEpoch) + err = rows.Scan(&deal.ID, &deal.DealID, &deal.State, &deal.ClientID, &deal.ClientActorID, &deal.Provider, &deal.PieceCID, &deal.StartEpoch, &deal.EndEpoch) if err != nil { return errors.WithStack(err) } @@ -552,11 +552,17 @@ func (d *DealTracker) runOnce(ctx context.Context) error { if err != nil { return errors.Wrapf(err, "failed to parse piece CID %s", deal.Proposal.PieceCID.Root) } + + var wallet model.Wallet + if err := db.Where("actor_id = ?", deal.Proposal.Client).First(&wallet).Error; err != nil { + return errors.Wrapf(err, "failed to find wallet for client %s", deal.Proposal.Client) + } + err = database.DoRetry(ctx, func() error { return db.Create(&model.Deal{ DealID: &dealID, State: newState, - ClientID: deal.Proposal.Client, + ClientID: &wallet.ID, Provider: deal.Proposal.Provider, Label: deal.Proposal.Label, PieceCID: model.CID(root), diff --git a/service/dealtracker/dealtracker_test.go b/service/dealtracker/dealtracker_test.go index eb2444d9..3832a489 100644 --- a/service/dealtracker/dealtracker_test.go +++ b/service/dealtracker/dealtracker_test.go @@ -151,10 +151,11 @@ func TestTrackDeal(t *testing.T) { func TestRunOnce(t *testing.T) { testutil.All(t, func(ctx context.Context, t *testing.T, db *gorm.DB) { - err := db.Create(&model.Wallet{ - ID: "t0100", + wallet := model.Wallet{ + ActorID: "t0100", Address: "t3xxx", - }).Error + } + err := db.Create(&wallet).Error require.NoError(t, err) d1 := uint64(1) d2 := uint64(2) @@ -171,7 +172,8 @@ func TestRunOnce(t *testing.T) { { DealID: &d1, State: model.DealActive, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal1", Label: "label1", @@ -185,7 +187,8 @@ func TestRunOnce(t *testing.T) { { DealID: &d2, State: model.DealPublished, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal2", Label: "label2", @@ -198,7 +201,8 @@ func TestRunOnce(t *testing.T) { }, { State: model.DealProposed, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal3", Label: "label3", @@ -212,7 +216,8 @@ func TestRunOnce(t *testing.T) { { DealID: &d4, State: model.DealActive, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal4", Label: "label4", @@ -225,7 +230,8 @@ func TestRunOnce(t *testing.T) { }, { State: model.DealActive, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal5", Label: "label5", @@ -239,7 +245,8 @@ func TestRunOnce(t *testing.T) { { DealID: &d6, State: model.DealPublished, - ClientID: "t0100", + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, Provider: "sp1", ProposalID: "proposal6", Label: "label6", diff --git a/testdb/main.go b/testdb/main.go index 26e92636..1ee4ad39 100644 --- a/testdb/main.go +++ b/testdb/main.go @@ -42,12 +42,12 @@ func run() error { return errors.WithStack(err) } defer closer.Close() - err = model.DropAll(db) + err = model.GetMigrator(db).DropAll() if err != nil { return errors.WithStack(err) } - err = model.AutoMigrate(db) + err = model.GetMigrator(db).Migrate() if err != nil { return errors.WithStack(err) } @@ -76,7 +76,7 @@ func createPreparation(ctx context.Context, db *gorm.DB) error { } // Setup wallet wallet := model.Wallet{ - ID: fmt.Sprintf("f0%d", r.Intn(10000)), + ActorID: fmt.Sprintf("f0%d", r.Intn(10000)), Address: "f1" + randomLetterString(39), } @@ -138,7 +138,7 @@ func createPreparation(ctx context.Context, db *gorm.DB) error { } var files []model.File - for i := 0; i < r.Intn(10_000); i++ { + for i := range r.Intn(10_000) { size := r.Int63n(1 << 20) rCID := randomCID() files = append(files, model.File{ @@ -338,11 +338,12 @@ func createPreparation(ctx context.Context, db *gorm.DB) error { //nolint:gosec // G115: Safe conversion, max int32 epoch won't occur until year 4062 StartEpoch: int32(10000 + r.Intn(10000)), //nolint:gosec // G115: Safe conversion, max int32 epoch won't occur until year 4062 - EndEpoch: int32(20000 + r.Intn(10000)), - Price: "0", - Verified: true, - ScheduleID: ptr.Of(schedule.ID), - ClientID: wallet.ID, + EndEpoch: int32(20000 + r.Intn(10000)), + Price: "0", + Verified: true, + ScheduleID: ptr.Of(schedule.ID), + ClientID: &wallet.ID, + ClientActorID: wallet.ActorID, } if state == model.DealActive { //nolint:gosec // G115: Safe conversion, max int32 epoch won't occur until year 4062 diff --git a/util/testutil/testutils.go b/util/testutil/testutils.go index 600479aa..4e94b601 100644 --- a/util/testutil/testutils.go +++ b/util/testutil/testutils.go @@ -186,7 +186,7 @@ func doOne(t *testing.T, backend string, testFunc func(ctx context.Context, t *t defer cancel() db = db.WithContext(ctx) - err := model.AutoMigrate(db) + err := model.GetMigrator(db).Migrate() require.NoError(t, err) // Clear any existing data from tables with unique constraints diff --git a/version.json b/version.json index 4f8ae529..1cbaa132 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,4 @@ { "version": "v0.6.0-RC3" -} \ No newline at end of file +} +