From 1e76ead37aff288b84f65dec989ff801ebf83417 Mon Sep 17 00:00:00 2001 From: Karel Moravec Date: Thu, 16 May 2024 18:56:47 +0200 Subject: [PATCH] feat: add derived keys mapping to parties engine --- core/banking/engine.go | 10 +++- core/banking/engine_test.go | 5 +- core/banking/mocks/mocks.go | 55 +++++++++++++------ core/banking/oneoff_transfers.go | 2 +- core/banking/oneoff_transfers_test.go | 4 +- core/collateral/engine.go | 19 ------- core/execution/amm/engine.go | 10 +++- core/execution/amm/engine_test.go | 17 ++++-- core/execution/common/interfaces.go | 6 +- core/execution/common/mocks/mocks.go | 37 ++++++++++++- core/execution/engine.go | 4 ++ core/execution/engine_snapshot.go | 1 + core/execution/engine_snapshot_test.go | 6 +- core/execution/future/market.go | 3 +- core/execution/future/market_snapshot.go | 5 +- core/execution/future/market_snapshot_test.go | 3 +- core/execution/future/market_test.go | 6 +- core/execution/snapshot_test.go | 4 ++ core/governance/market_cp_restore_test.go | 3 +- core/integration/setup_test.go | 3 +- core/parties/engine.go | 23 ++++++++ core/protocol/all_services.go | 6 +- 22 files changed, 168 insertions(+), 64 deletions(-) diff --git a/core/banking/engine.go b/core/banking/engine.go index bfb692520f4..4a13dade0aa 100644 --- a/core/banking/engine.go +++ b/core/banking/engine.go @@ -40,7 +40,7 @@ import ( "golang.org/x/exp/maps" ) -//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/banking Assets,Notary,Collateral,Witness,TimeService,EpochService,Topology,MarketActivityTracker,ERC20BridgeView,EthereumEventSource +//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/banking Assets,Notary,Collateral,Witness,TimeService,EpochService,Topology,MarketActivityTracker,ERC20BridgeView,EthereumEventSource,Parties var ( ErrWrongAssetTypeUsedInBuiltinAssetChainEvent = errors.New("non builtin asset used for builtin asset chain event") @@ -83,7 +83,6 @@ type Collateral interface { GovernanceTransferFunds(ctx context.Context, transfers []*types.Transfer, accountTypes []types.AccountType, references []string) ([]*types.LedgerMovement, error) PropagateAssetUpdate(ctx context.Context, asset types.Asset) error GetSystemAccountBalance(asset, market string, accountType types.AccountType) (*num.Uint, error) - IsAMMKeyOwner(owner, ammKey string) (bool, error) } // Witness provide foreign chain resources validations. @@ -121,6 +120,10 @@ type EthereumEventSource interface { UpdateCollateralStartingBlock(uint64) } +type Parties interface { + CheckDerivedKeyOwnership(party types.PartyID, derivedKey string) (bool, error) +} + const ( pendingState uint32 = iota okState @@ -144,6 +147,7 @@ type Engine struct { notary Notary assets Assets top Topology + parties Parties // assetActions tracks all the asset actions the engine must process on network // tick. @@ -235,6 +239,7 @@ func New(log *logging.Logger, secondaryBridgeView ERC20BridgeView, primaryEthEventSource EthereumEventSource, secondaryEthEventSource EthereumEventSource, + parties Parties, ) (e *Engine) { log = log.Named(namedLogger) log.SetLevel(cfg.Level.Get()) @@ -251,6 +256,7 @@ func New(log *logging.Logger, top: top, primaryEthEventSource: primaryEthEventSource, secondaryEthEventSource: secondaryEthEventSource, + parties: parties, assetActions: map[string]*assetAction{}, seenAssetActions: treeset.NewWithStringComparator(), withdrawals: map[string]withdrawalRef{}, diff --git a/core/banking/engine_test.go b/core/banking/engine_test.go index 6644ef8b3f9..e8f06cb4136 100644 --- a/core/banking/engine_test.go +++ b/core/banking/engine_test.go @@ -55,6 +55,7 @@ type testEngine struct { marketActivityTracker *mocks.MockMarketActivityTracker ethSource *mocks.MockEthereumEventSource secondaryBridgeView *mocks.MockERC20BridgeView + parties *mocks.MockParties } func getTestEngine(t *testing.T) *testEngine { @@ -79,7 +80,8 @@ func getTestEngine(t *testing.T) *testEngine { notary.EXPECT().OfferSignatures(gomock.Any(), gomock.Any()).AnyTimes() epoch.EXPECT().NotifyOnEpoch(gomock.Any(), gomock.Any()).AnyTimes() - eng := banking.New(logging.NewTestLogger(), banking.NewDefaultConfig(), col, witness, tsvc, assets, notary, broker, top, marketActivityTracker, primaryBridgeView, secondaryBridgeView, ethSource, nil) + parties := mocks.NewMockParties(ctrl) + eng := banking.New(logging.NewTestLogger(), banking.NewDefaultConfig(), col, witness, tsvc, assets, notary, broker, top, marketActivityTracker, primaryBridgeView, secondaryBridgeView, ethSource, nil, parties) require.NoError(t, eng.OnMaxQuantumAmountUpdate(context.Background(), num.DecimalOne())) eng.OnPrimaryEthChainIDUpdated("1") @@ -98,6 +100,7 @@ func getTestEngine(t *testing.T) *testEngine { secondaryBridgeView: secondaryBridgeView, marketActivityTracker: marketActivityTracker, ethSource: ethSource, + parties: parties, } } diff --git a/core/banking/mocks/mocks.go b/core/banking/mocks/mocks.go index 260e76a74f9..ca43e06ad52 100644 --- a/core/banking/mocks/mocks.go +++ b/core/banking/mocks/mocks.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: code.vegaprotocol.io/vega/core/banking (interfaces: Assets,Notary,Collateral,Witness,TimeService,EpochService,Topology,MarketActivityTracker,ERC20BridgeView,EthereumEventSource) +// Source: code.vegaprotocol.io/vega/core/banking (interfaces: Assets,Notary,Collateral,Witness,TimeService,EpochService,Topology,MarketActivityTracker,ERC20BridgeView,EthereumEventSource,Parties) // Package mocks is a generated GoMock package. package mocks @@ -258,21 +258,6 @@ func (mr *MockCollateralMockRecorder) GovernanceTransferFunds(arg0, arg1, arg2, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GovernanceTransferFunds", reflect.TypeOf((*MockCollateral)(nil).GovernanceTransferFunds), arg0, arg1, arg2, arg3) } -// IsAMMKeyOwner mocks base method. -func (m *MockCollateral) IsAMMKeyOwner(arg0, arg1 string) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsAMMKeyOwner", arg0, arg1) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsAMMKeyOwner indicates an expected call of IsAMMKeyOwner. -func (mr *MockCollateralMockRecorder) IsAMMKeyOwner(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAMMKeyOwner", reflect.TypeOf((*MockCollateral)(nil).IsAMMKeyOwner), arg0, arg1) -} - // PropagateAssetUpdate mocks base method. func (m *MockCollateral) PropagateAssetUpdate(arg0 context.Context, arg1 types.Asset) error { m.ctrl.T.Helper() @@ -722,3 +707,41 @@ func (mr *MockEthereumEventSourceMockRecorder) UpdateCollateralStartingBlock(arg mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCollateralStartingBlock", reflect.TypeOf((*MockEthereumEventSource)(nil).UpdateCollateralStartingBlock), arg0) } + +// MockParties is a mock of Parties interface. +type MockParties struct { + ctrl *gomock.Controller + recorder *MockPartiesMockRecorder +} + +// MockPartiesMockRecorder is the mock recorder for MockParties. +type MockPartiesMockRecorder struct { + mock *MockParties +} + +// NewMockParties creates a new mock instance. +func NewMockParties(ctrl *gomock.Controller) *MockParties { + mock := &MockParties{ctrl: ctrl} + mock.recorder = &MockPartiesMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockParties) EXPECT() *MockPartiesMockRecorder { + return m.recorder +} + +// CheckDerivedKeyOwnership mocks base method. +func (m *MockParties) CheckDerivedKeyOwnership(arg0 types.PartyID, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckDerivedKeyOwnership", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CheckDerivedKeyOwnership indicates an expected call of CheckDerivedKeyOwnership. +func (mr *MockPartiesMockRecorder) CheckDerivedKeyOwnership(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckDerivedKeyOwnership", reflect.TypeOf((*MockParties)(nil).CheckDerivedKeyOwnership), arg0, arg1) +} diff --git a/core/banking/oneoff_transfers.go b/core/banking/oneoff_transfers.go index a7342c2572f..616b9a249b0 100644 --- a/core/banking/oneoff_transfers.go +++ b/core/banking/oneoff_transfers.go @@ -87,7 +87,7 @@ func (e *Engine) oneOffTransfer( } if transfer.FromDerivedKey != nil { - if _, err := e.col.IsAMMKeyOwner(transfer.From, *transfer.FromDerivedKey); err != nil { + if _, err := e.parties.CheckDerivedKeyOwnership(types.PartyID(transfer.From), *transfer.FromDerivedKey); err != nil { transfer.Status = types.TransferStatusRejected return err } diff --git a/core/banking/oneoff_transfers_test.go b/core/banking/oneoff_transfers_test.go index c7998bb3402..ea0e8b7730c 100644 --- a/core/banking/oneoff_transfers_test.go +++ b/core/banking/oneoff_transfers_test.go @@ -493,7 +493,7 @@ func testValidOneOffTransferWithFromDerivedKey(t *testing.T) { } e.col.EXPECT().GetPartyVestedRewardAccount(derivedKey, assetNameETH).Return(&vestedAccount, nil).Times(1) - e.col.EXPECT().IsAMMKeyOwner(partyKey, derivedKey).Return(true, nil).Times(1) + e.parties.EXPECT().CheckDerivedKeyOwnership(types.PartyID(partyKey), derivedKey).Return(true, nil).Times(1) // assert the calculation of fees and transfer request are correct e.col.EXPECT().TransferFunds(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn( @@ -652,7 +652,7 @@ func testOneOffTransferInvalidOwnerTransfersWithFromDerivedKey(t *testing.T) { e.assets.EXPECT().Get(gomock.Any()).Times(1).Return( assets.NewAsset(&mockAsset{name: assetNameETH, quantum: num.DecimalFromFloat(100)}), nil) - e.col.EXPECT().IsAMMKeyOwner(partyKey, derivedKey).Return(false, fmt.Errorf("not and amm owner")).Times(1) + e.parties.EXPECT().CheckDerivedKeyOwnership(types.PartyID(partyKey), derivedKey).Return(false, fmt.Errorf("not and amm owner")).Times(1) e.broker.EXPECT().Send(gomock.Any()).Times(1) assert.Error(t, e.TransferFunds(ctx, transfer), "not and amm owner") diff --git a/core/collateral/engine.go b/core/collateral/engine.go index f81cb95495d..7a9b1b2061b 100644 --- a/core/collateral/engine.go +++ b/core/collateral/engine.go @@ -123,9 +123,6 @@ type Engine struct { // we'll use it only once after an upgrade // to make sure asset are being created ensuredAssetAccounts bool - - // amm key` to party ID - ammKeyToParty map[string]string } // New instantiates a new collateral engine. @@ -147,7 +144,6 @@ func New(log *logging.Logger, conf Config, ts TimeService, broker Broker) *Engin vesting: map[string]map[string]*num.Uint{}, partiesAccsBalanceCache: map[string]*num.Uint{}, nextBalancesSnapshot: time.Time{}, - ammKeyToParty: map[string]string{}, } } @@ -3578,19 +3574,6 @@ func (e *Engine) CreatePartyMarginAccount(ctx context.Context, partyID, marketID return marginID, nil } -func (e *Engine) IsAMMKeyOwner(owner, ammKey string) (bool, error) { - party, ok := e.ammKeyToParty[ammKey] - if !ok { - return false, fmt.Errorf("amm key %s does not exists", ammKey) - } - - if party != owner { - return false, fmt.Errorf("party %s does not own %s", owner, ammKey) - } - - return true, nil -} - // CreatePartyAMMSubAccounts ... func (e *Engine) CreatePartyAMMsSubAccounts( ctx context.Context, @@ -3611,8 +3594,6 @@ func (e *Engine) CreatePartyAMMsSubAccounts( return nil, nil, err } - e.ammKeyToParty[ammKey] = party - return e.accs[generalID].Clone(), e.accs[marginID].Clone(), nil } diff --git a/core/execution/amm/engine.go b/core/execution/amm/engine.go index d1d85d9960c..29600c0cb7f 100644 --- a/core/execution/amm/engine.go +++ b/core/execution/amm/engine.go @@ -117,12 +117,12 @@ func (s *Sqrter) sqrt(u *num.Uint) num.Decimal { type Engine struct { log *logging.Logger - broker Broker - // TODO karel - use interface for market activity tracker + broker Broker marketActivityTracker *common.MarketActivityTracker collateral Collateral position Position + parties common.Parties marketID string assetID string @@ -155,6 +155,7 @@ func New( priceFactor num.Decimal, positionFactor num.Decimal, marketActivityTracker *common.MarketActivityTracker, + parties common.Parties, ) *Engine { return &Engine{ log: log, @@ -171,6 +172,7 @@ func New( rooter: &Sqrter{cache: map[string]num.Decimal{}}, priceFactor: priceFactor, positionFactor: positionFactor, + parties: parties, } } @@ -185,8 +187,9 @@ func NewFromProto( priceFactor num.Decimal, positionFactor num.Decimal, marketActivityTracker *common.MarketActivityTracker, + parties common.Parties, ) (*Engine, error) { - e := New(log, broker, collateral, marketID, assetID, position, priceFactor, positionFactor, marketActivityTracker) + e := New(log, broker, collateral, marketID, assetID, position, priceFactor, positionFactor, marketActivityTracker, parties) for _, v := range state.AmmPartyIds { e.ammParties[v.Key] = v.Value @@ -683,6 +686,7 @@ func (e *Engine) Confirm( pool.status = types.AMMPoolStatusActive e.add(pool) e.sendUpdate(ctx, pool) + e.parties.AssignDeriveKey(types.PartyID(pool.owner), pool.AMMParty) return nil } diff --git a/core/execution/amm/engine_test.go b/core/execution/amm/engine_test.go index e00abd658e3..7c9f621360a 100644 --- a/core/execution/amm/engine_test.go +++ b/core/execution/amm/engine_test.go @@ -622,11 +622,12 @@ func getCancelSubmission(t *testing.T, party, market string, method types.AMMCan } type tstEngine struct { - engine *Engine - broker *bmocks.MockBroker - col *mocks.MockCollateral - pos *mocks.MockPosition - ctrl *gomock.Controller + engine *Engine + broker *bmocks.MockBroker + col *mocks.MockCollateral + pos *mocks.MockPosition + parties *cmocks.MockParties + ctrl *gomock.Controller marketID string assetID string @@ -650,7 +651,10 @@ func getTestEngine(t *testing.T) *tstEngine { mat := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker) - eng := New(logging.NewTestLogger(), broker, col, marketID, assetID, pos, num.DecimalOne(), num.DecimalOne(), mat) + parties := cmocks.NewMockParties(ctrl) + parties.EXPECT().AssignDeriveKey(gomock.Any(), gomock.Any()).AnyTimes() + + eng := New(logging.NewTestLogger(), broker, col, marketID, assetID, pos, num.DecimalOne(), num.DecimalOne(), mat, parties) // do an ontick to initialise the idgen ctx := vgcontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) @@ -662,6 +666,7 @@ func getTestEngine(t *testing.T) *tstEngine { col: col, pos: pos, ctrl: ctrl, + parties: parties, marketID: marketID, assetID: assetID, } diff --git a/core/execution/common/interfaces.go b/core/execution/common/interfaces.go index 296dee3482d..8e94ad230a3 100644 --- a/core/execution/common/interfaces.go +++ b/core/execution/common/interfaces.go @@ -33,7 +33,7 @@ import ( var One = num.UintOne() -//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/execution/common TimeService,Assets,StateVarEngine,Collateral,OracleEngine,EpochEngine,AuctionState,LiquidityEngine,EquityLikeShares,MarketLiquidityEngine,Teams,AccountBalanceChecker,Banking +//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/execution/common TimeService,Assets,StateVarEngine,Collateral,OracleEngine,EpochEngine,AuctionState,LiquidityEngine,EquityLikeShares,MarketLiquidityEngine,Teams,AccountBalanceChecker,Banking,Parties //go:generate go run github.com/golang/mock/mockgen -destination mocks_amm/mocks.go -package mocks_amm code.vegaprotocol.io/vega/core/execution/common AMMPool,AMM @@ -238,6 +238,10 @@ type Banking interface { RegisterTradingFees(ctx context.Context, asset string, feesPerParty map[string]*num.Uint) } +type Parties interface { + AssignDeriveKey(party types.PartyID, derivedKey string) +} + type LiquidityEngine interface { GetLegacyOrders() []string OnEpochRestore(ep types.Epoch) diff --git a/core/execution/common/mocks/mocks.go b/core/execution/common/mocks/mocks.go index b4be86a62c5..8c1c827f729 100644 --- a/core/execution/common/mocks/mocks.go +++ b/core/execution/common/mocks/mocks.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: code.vegaprotocol.io/vega/core/execution/common (interfaces: TimeService,Assets,StateVarEngine,Collateral,OracleEngine,EpochEngine,AuctionState,LiquidityEngine,EquityLikeShares,MarketLiquidityEngine,Teams,AccountBalanceChecker,Banking) +// Source: code.vegaprotocol.io/vega/core/execution/common (interfaces: TimeService,Assets,StateVarEngine,Collateral,OracleEngine,EpochEngine,AuctionState,LiquidityEngine,EquityLikeShares,MarketLiquidityEngine,Teams,AccountBalanceChecker,Banking,Parties) // Package mocks is a generated GoMock package. package mocks @@ -2628,3 +2628,38 @@ func (mr *MockBankingMockRecorder) RegisterTradingFees(arg0, arg1, arg2 interfac mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterTradingFees", reflect.TypeOf((*MockBanking)(nil).RegisterTradingFees), arg0, arg1, arg2) } + +// MockParties is a mock of Parties interface. +type MockParties struct { + ctrl *gomock.Controller + recorder *MockPartiesMockRecorder +} + +// MockPartiesMockRecorder is the mock recorder for MockParties. +type MockPartiesMockRecorder struct { + mock *MockParties +} + +// NewMockParties creates a new mock instance. +func NewMockParties(ctrl *gomock.Controller) *MockParties { + mock := &MockParties{ctrl: ctrl} + mock.recorder = &MockPartiesMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockParties) EXPECT() *MockPartiesMockRecorder { + return m.recorder +} + +// AssignDeriveKey mocks base method. +func (m *MockParties) AssignDeriveKey(arg0 types.PartyID, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AssignDeriveKey", arg0, arg1) +} + +// AssignDeriveKey indicates an expected call of AssignDeriveKey. +func (mr *MockPartiesMockRecorder) AssignDeriveKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignDeriveKey", reflect.TypeOf((*MockParties)(nil).AssignDeriveKey), arg0, arg1) +} diff --git a/core/execution/engine.go b/core/execution/engine.go index 82fb32b1be1..225965e7f6f 100644 --- a/core/execution/engine.go +++ b/core/execution/engine.go @@ -86,6 +86,7 @@ type Engine struct { referralDiscountRewardService fee.ReferralDiscountRewardService volumeDiscountService fee.VolumeDiscountService banking common.Banking + parties common.Parties broker common.Broker timeService common.TimeService @@ -198,6 +199,7 @@ func NewEngine( referralDiscountRewardService fee.ReferralDiscountRewardService, volumeDiscountService fee.VolumeDiscountService, banking common.Banking, + parties common.Parties, ) *Engine { // setup logger log = log.Named(namedLogger) @@ -224,6 +226,7 @@ func NewEngine( referralDiscountRewardService: referralDiscountRewardService, volumeDiscountService: volumeDiscountService, banking: banking, + parties: parties, } // set the eligibility for proposer bonus checker @@ -756,6 +759,7 @@ func (e *Engine) submitMarket(ctx context.Context, marketConfig *types.Market, o e.referralDiscountRewardService, e.volumeDiscountService, e.banking, + e.parties, ) if err != nil { e.log.Error("failed to instantiate market", diff --git a/core/execution/engine_snapshot.go b/core/execution/engine_snapshot.go index 82ebd5eedc5..5f31777ff98 100644 --- a/core/execution/engine_snapshot.go +++ b/core/execution/engine_snapshot.go @@ -217,6 +217,7 @@ func (e *Engine) restoreMarket(ctx context.Context, em *types.ExecMarket) (*futu e.referralDiscountRewardService, e.volumeDiscountService, e.banking, + e.parties, ) if err != nil { e.log.Error("failed to instantiate market", diff --git a/core/execution/engine_snapshot_test.go b/core/execution/engine_snapshot_test.go index 89bb5a1b62b..e2d48dc6d16 100644 --- a/core/execution/engine_snapshot_test.go +++ b/core/execution/engine_snapshot_test.go @@ -96,9 +96,10 @@ func getMockedEngine(t *testing.T) *engineFake { volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) + parties := mocks.NewMockParties(ctrl) mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker) - exec := execution.NewEngine(log, execConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking) + exec := execution.NewEngine(log, execConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking, parties) epochEngine.NotifyOnEpoch(mat.OnEpochEvent, mat.OnEpochRestore) return &engineFake{ Engine: exec, @@ -163,8 +164,9 @@ func createEngine(t *testing.T) (*execution.Engine, *gomock.Controller) { referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker) banking := mocks.NewMockBanking(ctrl) + parties := mocks.NewMockParties(ctrl) - e := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking) + e := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking, parties) epochEngine.NotifyOnEpoch(mat.OnEpochEvent, mat.OnEpochRestore) return e, ctrl } diff --git a/core/execution/future/market.go b/core/execution/future/market.go index 6d9fa806c9b..f3d6a178c6d 100644 --- a/core/execution/future/market.go +++ b/core/execution/future/market.go @@ -195,6 +195,7 @@ func NewMarket( referralDiscountRewardService fee.ReferralDiscountRewardService, volumeDiscountService fee.VolumeDiscountService, banking common.Banking, + parties common.Parties, ) (*Market, error) { if len(mkt.ID) == 0 { return nil, common.ErrEmptyMarketID @@ -215,7 +216,7 @@ func NewMarket( asset := tradableInstrument.Instrument.Product.GetAsset() positionEngine := positions.NewSnapshotEngine(log, positionConfig, mkt.ID, broker) - ammEngine := amm.New(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, priceFactor, positionFactor, marketActivityTracker) + ammEngine := amm.New(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, priceFactor, positionFactor, marketActivityTracker, parties) // @TODO -> the raw auctionstate shouldn't be something exposed to the matching engine // as far as matching goes: it's either an auction or not diff --git a/core/execution/future/market_snapshot.go b/core/execution/future/market_snapshot.go index c582c7f3c57..c9a847f3f4a 100644 --- a/core/execution/future/market_snapshot.go +++ b/core/execution/future/market_snapshot.go @@ -68,6 +68,7 @@ func NewMarketFromSnapshot( referralDiscountRewardService fee.ReferralDiscountRewardService, volumeDiscountService fee.VolumeDiscountService, banking common.Banking, + parties common.Parties, ) (*Market, error) { mkt := em.Market @@ -93,9 +94,9 @@ func NewMarketFromSnapshot( var ammEngine *amm.Engine if em.Amm == nil { - ammEngine = amm.New(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, priceFactor, positionFactor, marketActivityTracker) + ammEngine = amm.New(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, priceFactor, positionFactor, marketActivityTracker, parties) } else { - ammEngine, err = amm.NewFromProto(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, em.Amm, priceFactor, positionFactor, marketActivityTracker) + ammEngine, err = amm.NewFromProto(log, broker, collateralEngine, mkt.GetID(), asset, positionEngine, em.Amm, priceFactor, positionFactor, marketActivityTracker, parties) if err != nil { return nil, err } diff --git a/core/execution/future/market_snapshot_test.go b/core/execution/future/market_snapshot_test.go index da88c867db9..239a7008213 100644 --- a/core/execution/future/market_snapshot_test.go +++ b/core/execution/future/market_snapshot_test.go @@ -258,8 +258,9 @@ func newMarketFromSnapshot(t *testing.T, ctx context.Context, ctrl *gomock.Contr volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) + parties := mocks.NewMockParties(ctrl) return future.NewMarketFromSnapshot(ctx, log, em, riskConfig, positionConfig, settlementConfig, matchingConfig, feeConfig, liquidityConfig, collateralEngine, oracleEngine, timeService, broker, stubs.NewStateVar(), cfgAsset, marketActivityTracker, - peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking) + peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties) } diff --git a/core/execution/future/market_test.go b/core/execution/future/market_test.go index 0410cffa94b..15e39ab0d11 100644 --- a/core/execution/future/market_test.go +++ b/core/execution/future/market_test.go @@ -245,11 +245,12 @@ func (tm *testMarket) Run(ctx context.Context, mktCfg types.Market) *testMarket referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() banking := mocks.NewMockBanking(tm.ctrl) + parties := mocks.NewMockParties(tm.ctrl) mktEngine, err := future.NewMarket(ctx, tm.log, riskConfig, positionConfig, settlementConfig, matchingConfig, feeConfig, liquidityConfig, collateralEngine, oracleEngine, &mktCfg, tm.timeService, tm.broker, mas, statevarEngine, marketActivityTracker, cfgAsset, - peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, + peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties, ) require.NoError(tm.t, err) @@ -657,11 +658,12 @@ func getTestMarket2WithDP( referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() banking := mocks.NewMockBanking(ctrl) + parties := mocks.NewMockParties(ctrl) mktEngine, err := future.NewMarket(context.Background(), log, riskConfig, positionConfig, settlementConfig, matchingConfig, feeConfig, liquidityConfig, collateralEngine, oracleEngine, mktCfg, timeService, broker, mas, statevar, marketActivityTracker, cfgAsset, - peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking) + peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties) if err != nil { t.Fatalf("couldn't create a market: %v", err) } diff --git a/core/execution/snapshot_test.go b/core/execution/snapshot_test.go index 055479fad96..b9e7805a946 100644 --- a/core/execution/snapshot_test.go +++ b/core/execution/snapshot_test.go @@ -629,6 +629,7 @@ func getEngine(t *testing.T, vegaPath paths.Paths, now time.Time) *snapshotTestD volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) + parties := mocks.NewMockParties(ctrl) eng := execution.NewEngine( log, @@ -643,6 +644,7 @@ func getEngine(t *testing.T, vegaPath paths.Paths, now time.Time) *snapshotTestD referralDiscountReward, volumeDiscount, banking, + parties, ) statsData := stats.New(log, stats.NewDefaultConfig()) @@ -698,6 +700,7 @@ func getEngineWithParties(t *testing.T, now time.Time, balance *num.Uint, partie volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) + partiesMock := mocks.NewMockParties(ctrl) eng := execution.NewEngine( log, @@ -712,6 +715,7 @@ func getEngineWithParties(t *testing.T, now time.Time, balance *num.Uint, partie referralDiscountReward, volumeDiscount, banking, + partiesMock, ) statsData := stats.New(log, stats.NewDefaultConfig()) diff --git a/core/governance/market_cp_restore_test.go b/core/governance/market_cp_restore_test.go index 29544e9f29c..ea8c14bb063 100644 --- a/core/governance/market_cp_restore_test.go +++ b/core/governance/market_cp_restore_test.go @@ -210,8 +210,9 @@ func createExecutionEngine(t *testing.T, tm time.Time) (*execution.Engine, *gove referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() execBanking := emocks.NewMockBanking(ctrl) + parties := emocks.NewMockParties(ctrl) - exec := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, marketTracker, asset, referralDiscountReward, volumeDiscount, execBanking) + exec := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, marketTracker, asset, referralDiscountReward, volumeDiscount, execBanking, parties) accounts := mocks.NewMockStakingAccounts(ctrl) witness := mocks.NewMockWitness(ctrl) diff --git a/core/integration/setup_test.go b/core/integration/setup_test.go index 44f8c264ed9..25c69ad8052 100644 --- a/core/integration/setup_test.go +++ b/core/integration/setup_test.go @@ -194,7 +194,7 @@ func newExecutionTestSetup() *executionTestSetup { execsetup.volumeDiscountProgram = volumediscount.New(execsetup.broker, execsetup.marketActivityTracker) execsetup.epochEngine.NotifyOnEpoch(execsetup.volumeDiscountProgram.OnEpoch, execsetup.volumeDiscountProgram.OnEpochRestore) - execsetup.banking = banking.New(execsetup.log, banking.NewDefaultConfig(), execsetup.collateralEngine, execsetup.witness, execsetup.timeService, execsetup.assetsEngine, execsetup.notary, execsetup.broker, execsetup.topology, execsetup.marketActivityTracker, stubs.NewBridgeViewStub(), stubs.NewBridgeViewStub(), eventForwarder, nil) + execsetup.banking = banking.New(execsetup.log, banking.NewDefaultConfig(), execsetup.collateralEngine, execsetup.witness, execsetup.timeService, execsetup.assetsEngine, execsetup.notary, execsetup.broker, execsetup.topology, execsetup.marketActivityTracker, stubs.NewBridgeViewStub(), stubs.NewBridgeViewStub(), eventForwarder, nil, execsetup.profilesEngine) execsetup.executionEngine = newExEng( execution.NewEngine( @@ -210,6 +210,7 @@ func newExecutionTestSetup() *executionTestSetup { execsetup.referralProgram, execsetup.volumeDiscountProgram, execsetup.banking, + execsetup.profilesEngine, ), execsetup.broker, ) diff --git a/core/parties/engine.go b/core/parties/engine.go index cdd23adefa2..f8fa066a425 100644 --- a/core/parties/engine.go +++ b/core/parties/engine.go @@ -38,6 +38,9 @@ type Engine struct { // profiles tracks all parties profiles by party ID. profiles map[types.PartyID]*types.PartyProfile minBalanceToUpdateProfile *num.Uint + + // derivedKeys tracks all derived keys assigned to a party + derivedKeys map[types.PartyID]map[string]struct{} } func (e *Engine) OnMinBalanceForUpdatePartyProfileUpdated(_ context.Context, min *num.Uint) error { @@ -45,6 +48,26 @@ func (e *Engine) OnMinBalanceForUpdatePartyProfileUpdated(_ context.Context, min return nil } +func (e *Engine) AssignDeriveKey(party types.PartyID, derivedKey string) { + if _, ok := e.derivedKeys[party]; !ok { + e.derivedKeys[party] = map[string]struct{}{} + } + e.derivedKeys[party][derivedKey] = struct{}{} +} + +func (e *Engine) CheckDerivedKeyOwnership(party types.PartyID, derivedKey string) (bool, error) { + derivedKeys, ok := e.derivedKeys[party] + if !ok { + return false, fmt.Errorf("party %q does not have any derived keys", party) + } + + if _, ok := derivedKeys[derivedKey]; !ok { + return false, fmt.Errorf("party %q does not own %q", party, derivedKey) + } + + return true, nil +} + func (e *Engine) CheckSufficientBalanceToUpdateProfile(party types.PartyID, balance *num.Uint) error { if balance.LT(e.minBalanceToUpdateProfile) { return fmt.Errorf("party %q does not have sufficient balance to update profile code, required balance %s available balance %s", party, e.minBalanceToUpdateProfile.String(), balance.String()) diff --git a/core/protocol/all_services.go b/core/protocol/all_services.go index 8b4482e8290..30e5b702421 100644 --- a/core/protocol/all_services.go +++ b/core/protocol/all_services.go @@ -326,12 +326,14 @@ func newServices( svcs.volumeDiscount.OnEpochRestore, ) - svcs.banking = banking.New(svcs.log, svcs.conf.Banking, svcs.collateral, svcs.witness, svcs.timeService, svcs.assets, svcs.notary, svcs.broker, svcs.topology, svcs.marketActivityTracker, svcs.primaryBridgeView, svcs.secondaryBridgeView, svcs.primaryEventForwarderEngine, svcs.secondaryEventForwarderEngine) + svcs.banking = banking.New(svcs.log, svcs.conf.Banking, svcs.collateral, svcs.witness, svcs.timeService, + svcs.assets, svcs.notary, svcs.broker, svcs.topology, svcs.marketActivityTracker, svcs.primaryBridgeView, + svcs.secondaryBridgeView, svcs.primaryEventForwarderEngine, svcs.secondaryEventForwarderEngine, svcs.partiesEngine) // instantiate the execution engine svcs.executionEngine = execution.NewEngine( svcs.log, svcs.conf.Execution, svcs.timeService, svcs.collateral, svcs.oracle, svcs.broker, svcs.statevar, - svcs.marketActivityTracker, svcs.assets, svcs.referralProgram, svcs.volumeDiscount, svcs.banking, + svcs.marketActivityTracker, svcs.assets, svcs.referralProgram, svcs.volumeDiscount, svcs.banking, svcs.partiesEngine, ) svcs.epochService.NotifyOnEpoch(svcs.executionEngine.OnEpochEvent, svcs.executionEngine.OnEpochRestore) svcs.epochService.NotifyOnEpoch(svcs.marketActivityTracker.OnEpochEvent, svcs.marketActivityTracker.OnEpochRestore)