From 0f711d70432a3f01ddc4bcc227c2d4407b2eca0c Mon Sep 17 00:00:00 2001 From: Brian Meek Date: Mon, 20 May 2024 14:56:58 -0700 Subject: [PATCH] Enforce rules entitlement checks on isEntitledToSpace (#7) --- core/Dockerfile | 2 +- core/node/auth/auth_impl.go | 105 +++++++++++++----- core/node/auth/auth_impl_cache.go | 5 +- core/node/auth/auth_impl_cache_test.go | 8 +- core/node/auth/fake_auth.go | 4 +- core/node/auth/space_contract.go | 5 +- core/node/auth/space_contract_v3.go | 5 +- core/node/cmd/root_cmd.go | 1 + core/node/config/config.go | 69 +++++++++++- core/node/default_config.yaml | 16 +++ core/node/rpc/add_event.go | 2 +- core/node/rpc/create_stream.go | 2 +- core/node/run_impl.sh | 3 + .../client_simulator/client_simulator.go | 37 +++--- core/xchain/cmd/root_cmd.go | 16 ++- core/xchain/config/config.go | 88 --------------- core/xchain/contracts/contracts.go | 3 +- core/xchain/create_multi.sh | 35 +++--- core/xchain/default_config.yaml | 34 ------ core/xchain/entitlement/check_operation.go | 3 +- core/xchain/entitlement/client_pool.go | 3 +- core/xchain/entitlement/entitlement.go | 7 +- core/xchain/entitlement/entitlement_test.go | 3 +- core/xchain/server/server.go | 6 +- core/xchain/server/server_test.go | 60 +++++----- 25 files changed, 282 insertions(+), 240 deletions(-) delete mode 100644 core/xchain/config/config.go delete mode 100644 core/xchain/default_config.yaml diff --git a/core/Dockerfile b/core/Dockerfile index a524628df..09c639171 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -48,7 +48,7 @@ COPY --from=builder /bin/xchain_node /usr/bin/xchain_node RUN setcap 'cap_net_bind_service=+ep' /usr/bin/stream_node COPY --from=builder /build/node/node/default_config.yaml /riveruser/stream_node/config/config.yaml -COPY --from=builder /build/xchain/xchain/default_config.yaml /riveruser/xchain_node/config/config.yaml +COPY --from=builder /build/node/node/default_config.yaml /riveruser/xchain_node/config/config.yaml RUN mkdir -p /riveruser/stream_node/logs RUN mkdir -p /riveruser/xchain_node/logs diff --git a/core/node/auth/auth_impl.go b/core/node/auth/auth_impl.go index 2bff4af46..a86ad68c1 100644 --- a/core/node/auth/auth_impl.go +++ b/core/node/auth/auth_impl.go @@ -3,6 +3,7 @@ package auth import ( "context" "fmt" + "strings" "sync" "time" @@ -13,12 +14,13 @@ import ( "github.com/river-build/river/core/node/infra" . "github.com/river-build/river/core/node/protocol" "github.com/river-build/river/core/node/shared" + "github.com/river-build/river/core/xchain/entitlement" "github.com/ethereum/go-ethereum/common" ) type ChainAuth interface { - IsEntitled(ctx context.Context, args *ChainAuthArgs) error + IsEntitled(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) error } var everyone = common.HexToAddress("0x1") // This represents an Ethereum address of "0x1" @@ -57,11 +59,12 @@ const ( ) type ChainAuthArgs struct { - kind chainAuthKind - spaceId shared.StreamId - channelId shared.StreamId - principal common.Address - permission Permission + kind chainAuthKind + spaceId shared.StreamId + channelId shared.StreamId + principal common.Address + permission Permission + linkedWallets string // a serialized list of linked wallets to comply with the cache key constraints } // Replaces principal with given wallet and returns new copy of args. @@ -71,6 +74,19 @@ func (args *ChainAuthArgs) withWallet(wallet common.Address) *ChainAuthArgs { return &ret } +func (args *ChainAuthArgs) withLinkedWallets(linkedWallets []common.Address) *ChainAuthArgs { + ret := *args + var builder strings.Builder + for i, addr := range linkedWallets { + if i > 0 { + builder.WriteString(",") + } + builder.WriteString(addr.Hex()) + } + ret.linkedWallets = builder.String() + return &ret +} + func newArgsForEnabledSpace(spaceId shared.StreamId) *ChainAuthArgs { return &ChainAuthArgs{ kind: chainAuthKindSpaceEnabled, @@ -163,10 +179,11 @@ func NewChainAuth( }, nil } -func (ca *chainAuth) IsEntitled(ctx context.Context, args *ChainAuthArgs) error { +func (ca *chainAuth) IsEntitled(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) error { // TODO: counter for cache hits here? result, _, err := ca.entitlementCache.executeUsingCache( ctx, + cfg, args, ca.checkEntitlement, ) @@ -190,28 +207,29 @@ func (ca *chainAuth) IsEntitled(ctx context.Context, args *ChainAuthArgs) error return nil } -func (ca *chainAuth) isWalletEntitled(ctx context.Context, args *ChainAuthArgs) (bool, error) { +func (ca *chainAuth) isWalletEntitled(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (bool, error) { log := dlog.FromCtx(ctx) if args.kind == chainAuthKindSpace { log.Debug("isWalletEntitled", "kind", "space", "args", args) - return ca.isEntitledToSpace(ctx, args) + return ca.isEntitledToSpace(ctx, cfg, args) } else if args.kind == chainAuthKindChannel { log.Debug("isWalletEntitled", "kind", "channel", "args", args) - return ca.isEntitledToChannel(ctx, args) + return ca.isEntitledToChannel(ctx, cfg, args) } else { return false, RiverError(Err_INTERNAL, "Unknown chain auth kind").Func("isWalletEntitled") } } -func (ca *chainAuth) isSpaceEnabledUncached(ctx context.Context, args *ChainAuthArgs) (CacheResult, error) { +func (ca *chainAuth) isSpaceEnabledUncached(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (CacheResult, error) { // This is awkward as we want enabled to be cached for 15 minutes, but the API returns the inverse isDisabled, err := ca.spaceContract.IsSpaceDisabled(ctx, args.spaceId) return &boolCacheResult{allowed: !isDisabled}, err } -func (ca *chainAuth) checkSpaceEnabled(ctx context.Context, spaceId shared.StreamId) error { +func (ca *chainAuth) checkSpaceEnabled(ctx context.Context, cfg *config.Config, spaceId shared.StreamId) error { isEnabled, cacheHit, err := ca.entitlementCache.executeUsingCache( ctx, + cfg, newArgsForEnabledSpace(spaceId), ca.isSpaceEnabledUncached, ) @@ -231,7 +249,7 @@ func (ca *chainAuth) checkSpaceEnabled(ctx context.Context, spaceId shared.Strea } } -func (ca *chainAuth) isChannelEnabledUncached(ctx context.Context, args *ChainAuthArgs) (CacheResult, error) { +func (ca *chainAuth) isChannelEnabledUncached(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (CacheResult, error) { // This is awkward as we want enabled to be cached for 15 minutes, but the API returns the inverse isDisabled, err := ca.spaceContract.IsChannelDisabled(ctx, args.spaceId, args.channelId) return &boolCacheResult{allowed: !isDisabled}, err @@ -239,11 +257,13 @@ func (ca *chainAuth) isChannelEnabledUncached(ctx context.Context, args *ChainAu func (ca *chainAuth) checkChannelEnabled( ctx context.Context, + cfg *config.Config, spaceId shared.StreamId, channelId shared.StreamId, ) error { isEnabled, cacheHit, err := ca.entitlementCache.executeUsingCache( ctx, + cfg, newArgsForEnabledChannel(spaceId, channelId), ca.isChannelEnabledUncached, ) @@ -280,6 +300,7 @@ func (scr *entitlementCacheResult) IsAllowed() bool { // If the call fails or the space is not found, the allowed flag is set to false so the negative caching time applies. func (ca *chainAuth) getSpaceEntitlementsForPermissionUncached( ctx context.Context, + cfg *config.Config, args *ChainAuthArgs, ) (CacheResult, error) { log := dlog.FromCtx(ctx) @@ -301,11 +322,21 @@ func (ca *chainAuth) getSpaceEntitlementsForPermissionUncached( return &entitlementCacheResult{allowed: true, entitlementData: entitlementData, owner: owner}, nil } -func (ca *chainAuth) isEntitledToSpaceUncached(ctx context.Context, args *ChainAuthArgs) (CacheResult, error) { +func deserializeWallets(serialized string) []common.Address { + addressStrings := strings.Split(serialized, ",") + linkedWallets := make([]common.Address, len(addressStrings)) + for i, addrStr := range addressStrings { + linkedWallets[i] = common.HexToAddress(addrStr) + } + return linkedWallets +} + +func (ca *chainAuth) isEntitledToSpaceUncached(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (CacheResult, error) { log := dlog.FromCtx(ctx) log.Debug("isEntitledToSpaceUncached", "args", args) result, cacheHit, err := ca.entitlementManagerCache.executeUsingCache( ctx, + cfg, args, ca.getSpaceEntitlementsForPermissionUncached, ) @@ -333,12 +364,25 @@ func (ca *chainAuth) isEntitledToSpaceUncached(ctx context.Context, args *ChainA entitlementData := temp.(*entitlementCacheResult) // Assuming result is of *entitlementCacheResult type log.Debug("entitlementData", "args", args, "entitlementData", entitlementData) - for _, entitlement := range entitlementData.entitlementData { - log.Debug("entitlement", "entitlement", entitlement) - if entitlement.entitlementType == "RuleEntitlement" { - // TODO implement rule entitlment - } else if entitlement.entitlementType == "UserEntitlement" { - for _, user := range entitlement.userEntitlement { + for _, ent := range entitlementData.entitlementData { + log.Debug("entitlement", "entitlement", ent) + if ent.entitlementType == "RuleEntitlement" { + re := ent.ruleEntitlement + log.Debug("RuleEntitlement", "ruleEntitlement", re) + result, err := entitlement.EvaluateRuleData(ctx, cfg, deserializeWallets(args.linkedWallets), re) + + if err != nil { + return &boolCacheResult{allowed: false}, AsRiverError(err).Func("isEntitledToSpace") + } + if result { + log.Debug("rule entitlement is true", "spaceId", args.spaceId) + return &boolCacheResult{allowed: true}, nil + } else { + log.Debug("rule entitlement is false", "spaceId", args.spaceId) + return &boolCacheResult{allowed: false}, nil + } + } else if ent.entitlementType == "UserEntitlement" { + for _, user := range ent.userEntitlement { if user == everyone { log.Debug("everyone is entitled to space", "spaceId", args.spaceId) return &boolCacheResult{allowed: true}, nil @@ -348,19 +392,19 @@ func (ca *chainAuth) isEntitledToSpaceUncached(ctx context.Context, args *ChainA } } } else { - log.Warn("Invalid entitlement type", "entitlement", entitlement) + log.Warn("Invalid entitlement type", "entitlement", ent) } } return &boolCacheResult{allowed: false}, nil } -func (ca *chainAuth) isEntitledToSpace(ctx context.Context, args *ChainAuthArgs) (bool, error) { +func (ca *chainAuth) isEntitledToSpace(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (bool, error) { if args.kind != chainAuthKindSpace { return false, RiverError(Err_INTERNAL, "Wrong chain auth kind") } - isEntitled, cacheHit, err := ca.entitlementCache.executeUsingCache(ctx, args, ca.isEntitledToSpaceUncached) + isEntitled, cacheHit, err := ca.entitlementCache.executeUsingCache(ctx, cfg, args, ca.isEntitledToSpaceUncached) if err != nil { return false, err } @@ -373,7 +417,7 @@ func (ca *chainAuth) isEntitledToSpace(ctx context.Context, args *ChainAuthArgs) return isEntitled.IsAllowed(), nil } -func (ca *chainAuth) isEntitledToChannelUncached(ctx context.Context, args *ChainAuthArgs) (CacheResult, error) { +func (ca *chainAuth) isEntitledToChannelUncached(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (CacheResult, error) { allowed, err := ca.spaceContract.IsEntitledToChannel( ctx, args.spaceId, @@ -384,12 +428,12 @@ func (ca *chainAuth) isEntitledToChannelUncached(ctx context.Context, args *Chai return &boolCacheResult{allowed: allowed}, err } -func (ca *chainAuth) isEntitledToChannel(ctx context.Context, args *ChainAuthArgs) (bool, error) { +func (ca *chainAuth) isEntitledToChannel(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (bool, error) { if args.kind != chainAuthKindChannel { return false, RiverError(Err_INTERNAL, "Wrong chain auth kind") } - isEntitled, cacheHit, err := ca.entitlementCache.executeUsingCache(ctx, args, ca.isEntitledToChannelUncached) + isEntitled, cacheHit, err := ca.entitlementCache.executeUsingCache(ctx, cfg, args, ca.isEntitledToChannelUncached) if err != nil { return false, err } @@ -452,19 +496,19 @@ func (ca *chainAuth) checkMembership( * If any of the operations fail before getting positive result, the whole operation fails. * A prerequisite for this function is that one of the linked wallets is a member of the space. */ -func (ca *chainAuth) checkEntitlement(ctx context.Context, args *ChainAuthArgs) (CacheResult, error) { +func (ca *chainAuth) checkEntitlement(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) (CacheResult, error) { log := dlog.FromCtx(ctx) ctx, cancel := context.WithTimeout(ctx, time.Millisecond*time.Duration(ca.contractCallsTimeoutMs)) defer cancel() if args.kind == chainAuthKindSpace { - err := ca.checkSpaceEnabled(ctx, args.spaceId) + err := ca.checkSpaceEnabled(ctx, cfg, args.spaceId) if err != nil { return &boolCacheResult{allowed: false}, nil } } else if args.kind == chainAuthKindChannel { - err := ca.checkChannelEnabled(ctx, args.spaceId, args.channelId) + err := ca.checkChannelEnabled(ctx, cfg, args.spaceId, args.channelId) if err != nil { return &boolCacheResult{allowed: false}, nil } @@ -480,6 +524,7 @@ func (ca *chainAuth) checkEntitlement(ctx context.Context, args *ChainAuthArgs) // Add the root key to the list of wallets. wallets = append(wallets, args.principal) + args = args.withLinkedWallets(wallets) isMemberCtx, isMemberCancel := context.WithCancel(ctx) defer isMemberCancel() @@ -534,7 +579,7 @@ func (ca *chainAuth) checkEntitlement(ctx context.Context, args *ChainAuthArgs) wg.Add(1) go func(address common.Address) { defer wg.Done() - result, err := ca.isWalletEntitled(ctx, args.withWallet(address)) + result, err := ca.isWalletEntitled(ctx, cfg, args.withWallet(address)) resultsChan <- entitlementCheckResult{allowed: result, err: err} }(wallet) } diff --git a/core/node/auth/auth_impl_cache.go b/core/node/auth/auth_impl_cache.go index 86eb51172..d9771fbb9 100644 --- a/core/node/auth/auth_impl_cache.go +++ b/core/node/auth/auth_impl_cache.go @@ -141,8 +141,9 @@ func newEntitlementManagerCache(ctx context.Context, cfg *config.ChainConfig) (* func (ec *entitlementCache) executeUsingCache( ctx context.Context, + cfg *config.Config, key *ChainAuthArgs, - onMiss func(context.Context, *ChainAuthArgs) (CacheResult, error), + onMiss func(context.Context, *config.Config, *ChainAuthArgs) (CacheResult, error), ) (CacheResult, bool, error) { // Check positive cache first if val, ok := ec.positiveCache.Get(*key); ok { @@ -167,7 +168,7 @@ func (ec *entitlementCache) executeUsingCache( } // Cache miss, execute the closure - result, err := onMiss(ctx, key) + result, err := onMiss(ctx, cfg, key) if err != nil { return nil, false, err } diff --git a/core/node/auth/auth_impl_cache_test.go b/core/node/auth/auth_impl_cache_test.go index 6a0f53a66..51016c8b0 100644 --- a/core/node/auth/auth_impl_cache_test.go +++ b/core/node/auth/auth_impl_cache_test.go @@ -25,6 +25,8 @@ func TestCache(t *testing.T) { ctx, cancel := test.NewTestContext() defer cancel() + cfg := &config.Config{} + c, err := newEntitlementCache( ctx, &config.ChainConfig{ @@ -41,8 +43,9 @@ func TestCache(t *testing.T) { var cacheMissForReal bool result, cacheHit, err := c.executeUsingCache( ctx, + cfg, NewChainAuthArgsForChannel(spaceId, channelId, "3", PermissionWrite), - func(context.Context, *ChainAuthArgs) (CacheResult, error) { + func(context.Context, *config.Config, *ChainAuthArgs) (CacheResult, error) { cacheMissForReal = true return &simpleCacheResult{allowed: true}, nil }, @@ -55,8 +58,9 @@ func TestCache(t *testing.T) { cacheMissForReal = false result, cacheHit, err = c.executeUsingCache( ctx, + cfg, NewChainAuthArgsForChannel(spaceId, channelId, "3", PermissionWrite), - func(context.Context, *ChainAuthArgs) (CacheResult, error) { + func(context.Context, *config.Config, *ChainAuthArgs) (CacheResult, error) { cacheMissForReal = true return &simpleCacheResult{allowed: false}, nil }, diff --git a/core/node/auth/fake_auth.go b/core/node/auth/fake_auth.go index 83e158dbd..fd030fcec 100644 --- a/core/node/auth/fake_auth.go +++ b/core/node/auth/fake_auth.go @@ -2,6 +2,8 @@ package auth import ( "context" + + "github.com/river-build/river/core/node/config" ) // This checkers always returns true, used for some testing scenarios. @@ -13,6 +15,6 @@ type fakeChainAuth struct{} var _ ChainAuth = (*fakeChainAuth)(nil) -func (a *fakeChainAuth) IsEntitled(ctx context.Context, args *ChainAuthArgs) error { +func (a *fakeChainAuth) IsEntitled(ctx context.Context, cfg *config.Config, args *ChainAuthArgs) error { return nil } diff --git a/core/node/auth/space_contract.go b/core/node/auth/space_contract.go index 07d3c68aa..fa7526367 100644 --- a/core/node/auth/space_contract.go +++ b/core/node/auth/space_contract.go @@ -3,15 +3,14 @@ package auth import ( "context" - v3 "github.com/river-build/river/core/xchain/contracts/v3" - "github.com/ethereum/go-ethereum/common" "github.com/river-build/river/core/node/shared" + "github.com/river-build/river/core/xchain/contracts" ) type SpaceEntitlements struct { entitlementType string - ruleEntitlement v3.IRuleEntitlementRuleData + ruleEntitlement *contracts.IRuleData userEntitlement []common.Address } diff --git a/core/node/auth/space_contract_v3.go b/core/node/auth/space_contract_v3.go index 8d55fffea..d3e1a3c64 100644 --- a/core/node/auth/space_contract_v3.go +++ b/core/node/auth/space_contract_v3.go @@ -16,6 +16,7 @@ import ( "github.com/river-build/river/core/node/shared" "github.com/river-build/river/core/xchain/bindings/erc721" "github.com/river-build/river/core/xchain/bindings/ierc5313" + "github.com/river-build/river/core/xchain/contracts" v3 "github.com/river-build/river/core/xchain/contracts/v3" "github.com/ethereum/go-ethereum/accounts/abi" @@ -183,7 +184,7 @@ func (sc *SpaceContractV3) GetSpaceEntitlementsForPermission( return nil, EMPTY_ADDRESS, err } - var ruleData v3.IRuleEntitlementRuleData + var ruleData contracts.IRuleData unpackedData, err := parsedABI.Unpack("getRuleData", entitlement.EntitlementData) if err != nil { @@ -223,7 +224,7 @@ func (sc *SpaceContractV3) GetSpaceEntitlementsForPermission( log.Warn("No data unpacked", "unpackedData", unpackedData) } - entitlements[i].ruleEntitlement = ruleData + entitlements[i].ruleEntitlement = &ruleData } else if entitlement.EntitlementType == "UserEntitlement" { entitlements[i].entitlementType = entitlement.EntitlementType diff --git a/core/node/cmd/root_cmd.go b/core/node/cmd/root_cmd.go index 5ff040f59..65ff5cf14 100644 --- a/core/node/cmd/root_cmd.go +++ b/core/node/cmd/root_cmd.go @@ -88,6 +88,7 @@ func initConfigAndLog() { if logNoColor { configStruct.Log.NoColor = true } + configStruct.Init() // If loaded successfully, set the global config cmdConfig = &configStruct diff --git a/core/node/config/config.go b/core/node/config/config.go index 12c8baf3d..4ce4d091c 100644 --- a/core/node/config/config.go +++ b/core/node/config/config.go @@ -2,6 +2,9 @@ package config import ( "encoding/hex" + "fmt" + "strconv" + "strings" "time" "github.com/ethereum/go-ethereum/common" @@ -9,6 +12,13 @@ import ( "github.com/river-build/river/core/node/shared" ) +type ContractVersion string + +const ( + VersionDev ContractVersion = "dev" + VersionV3 ContractVersion = "v3" +) + type TLSConfig struct { Cert string // Path to certificate file or BASE64 encoded certificate Key string `dlog:"omit" json:"-"` // Path to key file or BASE64 encoded key. Sensitive data, omitted from logging. @@ -76,7 +86,19 @@ type Config struct { // Disable base chain contract usage. DisableBaseChain bool - EnableTestAPIs bool + + // xChain configuration + ChainsString string `mapstructure:"chains"` + Chains map[uint64]string `mapstructure:"-"` // This is a derived field + EntitlementContract ContractConfig `mapstructure:"entitlement_contract"` + WalletLinkContract ContractConfig `mapstructure:"wallet_link_contract"` + contractVersion ContractVersion `mapstructure:"contract_version"` + TestEntitlementContract ContractConfig `mapstructure:"test_contract"` + TestCustomEntitlementContract ContractConfig `mapstructure:"test_custom_entitlement_contract"` + + // History indicates how far back xchain must look for entitlement check requests after start + History time.Duration + EnableTestAPIs bool } type NetworkConfig struct { @@ -239,3 +261,48 @@ func (c *Config) GetGraffiti() string { } return c.Graffiti } + +func (c *Config) GetContractVersion() ContractVersion { + if c.contractVersion == VersionV3 { + return VersionV3 + } else { + return VersionDev + } +} + +func (c *Config) GetEntitlementContractAddress() common.Address { + return c.EntitlementContract.Address +} + +func (c *Config) GetWalletLinkContractAddress() common.Address { + return c.WalletLinkContract.Address +} + +func (c *Config) GetTestEntitlementContractAddress() common.Address { + return c.TestEntitlementContract.Address +} + +func (c *Config) GetTestCustomEntitlementContractAddress() common.Address { + return c.TestCustomEntitlementContract.Address +} + +func (c *Config) Init() { + c.parseChains() +} + +func (c *Config) parseChains() { + chainUrls := make(map[uint64]string) + chainPairs := strings.Split(c.ChainsString, ",") + for _, pair := range chainPairs { + parts := strings.SplitN(pair, ":", 2) // Use SplitN to split into exactly two parts + if len(parts) == 2 { + chainID, err := strconv.Atoi(parts[0]) + if err != nil { + fmt.Printf("Error converting chainID to int: %v\n", err) + continue + } + chainUrls[uint64(chainID)] = parts[1] + } + } + c.Chains = chainUrls +} diff --git a/core/node/default_config.yaml b/core/node/default_config.yaml index 8ad40d95a..a580202af 100644 --- a/core/node/default_config.yaml +++ b/core/node/default_config.yaml @@ -110,3 +110,19 @@ graffiti: '' # Debug feature flags. disableBaseChain: false + +chains: '31337:http://localhost:8545,31338:http://localhost:8546,84532:https://sepolia.base.org,11155111:https://ethereum-sepolia-rpc.publicnode.com' + +history: 30s + +entitlement_contract: + address: '' + version: '3' + +test_contract: + address: '' + version: '3' + +wallet_link_contract: + address: '' + version: '3' diff --git a/core/node/rpc/add_event.go b/core/node/rpc/add_event.go index 5ad181436..b391088d5 100644 --- a/core/node/rpc/add_event.go +++ b/core/node/rpc/add_event.go @@ -74,7 +74,7 @@ func (s *Service) addParsedEvent( } if chainAuthArgs != nil { - err := s.chainAuth.IsEntitled(ctx, chainAuthArgs) + err := s.chainAuth.IsEntitled(ctx, s.config, chainAuthArgs) if err != nil { return err } diff --git a/core/node/rpc/create_stream.go b/core/node/rpc/create_stream.go index f59cf45d1..9ce8bff76 100644 --- a/core/node/rpc/create_stream.go +++ b/core/node/rpc/create_stream.go @@ -107,7 +107,7 @@ func (s *Service) createStream(ctx context.Context, req *CreateStreamRequest) (* // check entitlements if csRules.ChainAuth != nil { - err := s.chainAuth.IsEntitled(ctx, csRules.ChainAuth) + err := s.chainAuth.IsEntitled(ctx, s.config, csRules.ChainAuth) if err != nil { return nil, err } diff --git a/core/node/run_impl.sh b/core/node/run_impl.sh index c7c8cbb81..17aabb19c 100755 --- a/core/node/run_impl.sh +++ b/core/node/run_impl.sh @@ -59,9 +59,12 @@ if [ "$CONFIG" == "true" ]; then SPACE_FACTORY_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/spaceFactory.json) WALLET_LINK_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/walletLink.json) + BASE_REGISTRY_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/baseRegistry.json) RIVER_REGISTRY_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/river/addresses/riverRegistry.json) + export SPACE_FACTORY_ADDRESS export WALLET_LINK_ADDRESS + export BASE_REGISTRY_ADDRESS export RIVER_REGISTRY_ADDRESS source ../../contracts/.env.localhost diff --git a/core/xchain/client_simulator/client_simulator.go b/core/xchain/client_simulator/client_simulator.go index a8378a998..d8a5e1722 100644 --- a/core/xchain/client_simulator/client_simulator.go +++ b/core/xchain/client_simulator/client_simulator.go @@ -2,8 +2,6 @@ package client_simulator import ( "context" - "core/xchain/config" - "core/xchain/contracts" "core/xchain/entitlement" "core/xchain/examples" "crypto/ecdsa" @@ -11,13 +9,17 @@ import ( "math/big" "time" + "github.com/river-build/river/core/xchain/contracts" + + "github.com/river-build/river/core/node/config" + node_contracts "github.com/river-build/river/core/node/contracts" node_crypto "github.com/river-build/river/core/node/crypto" "github.com/river-build/river/core/node/dlog" xc "core/xchain/common" - e "core/xchain/contracts" + e "github.com/river-build/river/core/xchain/contracts" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -177,7 +179,7 @@ type postResult struct { type ClientSimulator interface { Start(ctx context.Context) Stop() - EvaluateRuleData(ctx context.Context, ruleData e.IRuleData) (bool, error) + EvaluateRuleData(ctx context.Context, cfg *config.Config, ruleData e.IRuleData) (bool, error) Wallet() *node_crypto.Wallet } @@ -213,7 +215,7 @@ func New( wallet *node_crypto.Wallet, ) (ClientSimulator, error) { entitlementGated, err := e.NewMockEntitlementGated( - cfg.GetMockEntitlementContractAddress(), + cfg.GetTestEntitlementContractAddress(), nil, cfg.GetContractVersion(), ) @@ -228,7 +230,7 @@ func New( var ( entitlementGatedABI = entitlementGated.GetAbi() entitlementGatedContract = bind.NewBoundContract( - cfg.GetMockEntitlementContractAddress(), + cfg.GetTestEntitlementContractAddress(), *entitlementGated.GetAbi(), nil, nil, @@ -282,7 +284,7 @@ func (cs *clientSimulator) Stop() { func (cs *clientSimulator) Start(ctx context.Context) { cs.baseChain.ChainMonitor.OnContractWithTopicsEvent( - cs.cfg.GetMockEntitlementContractAddress(), + cs.cfg.GetTestEntitlementContractAddress(), [][]common.Hash{{cs.entitlementGatedABI.Events["EntitlementCheckResultPosted"].ID}}, func(ctx context.Context, event types.Log) { cs.onEntitlementCheckResultPosted(ctx, event, cs.resultPosted) @@ -304,20 +306,26 @@ func (cs *clientSimulator) Start(ctx context.Context) { func (cs *clientSimulator) executeCheck(ctx context.Context, ruleData *e.IRuleData) error { log := dlog.FromCtx(ctx).With("application", "clientSimulator") + log.Info("ClientSimulator executing check", "ruleData", ruleData, "cfg", cs.cfg) pendingTx, err := cs.baseChain.TxPool.Submit( ctx, "RequestEntitlementCheck", func(opts *bind.TransactOpts) (*types.Transaction, error) { + log.Info("Calling RequestEntitlementCheck", "opts", opts, "ruleData", ruleData) gated, err := contracts.NewMockEntitlementGated( - cs.cfg.GetMockEntitlementContractAddress(), + cs.cfg.GetTestEntitlementContractAddress(), cs.baseChain.Client, cs.cfg.GetContractVersion(), ) if err != nil { + log.Error("Failed to get NewMockEntitlementGated", "err", err) return nil, err } - return gated.RequestEntitlementCheck(opts, big.NewInt(0), *ruleData) + log.Info("NewMockEntitlementGated", "gated", gated.RequestEntitlementCheck, "err", err) + tx, err := gated.RequestEntitlementCheck(opts, big.NewInt(0), *ruleData) + log.Info("RequestEntitlementCheck called", "tx", tx, "err", err) + return tx, err }, ) @@ -326,13 +334,13 @@ func (cs *clientSimulator) executeCheck(ctx context.Context, ruleData *e.IRuleDa customErr, stringErr, err := cs.decoder.DecodeEVMError(err) switch { case customErr != nil: - log.Error("Failed to submit entitlement check", "err", customErr) + log.Error("Failed to submit entitlement check", "type", "customErr", "err", customErr) return err case stringErr != nil: - log.Error("Failed to submit entitlement check", "err", stringErr) + log.Error("Failed to submit entitlement check", "type", "stringErr", "err", stringErr) return err case err != nil: - log.Error("Failed to submit entitlement check", "err", err) + log.Error("Failed to submit entitlement check", "type", "err", "err", err) return err } @@ -464,8 +472,9 @@ func (cs *clientSimulator) Wallet() *node_crypto.Wallet { return cs.wallet } -func (cs *clientSimulator) EvaluateRuleData(ctx context.Context, ruleData e.IRuleData) (bool, error) { +func (cs *clientSimulator) EvaluateRuleData(ctx context.Context, cfg *config.Config, ruleData e.IRuleData) (bool, error) { log := dlog.FromCtx(ctx).With("application", "clientSimulator") + log.Info("ClientSimulator evaluating rule data", "ruleData", ruleData) err := cs.executeCheck(ctx, &ruleData) if err != nil { @@ -527,7 +536,7 @@ func RunClientSimulator(ctx context.Context, cfg *config.Config, wallet *node_cr return } - cs.EvaluateRuleData(ctx, ruleData) + cs.EvaluateRuleData(ctx, cfg, ruleData) } func ToggleEntitlement(ctx context.Context, cfg *config.Config, wallet *node_crypto.Wallet) { diff --git a/core/xchain/cmd/root_cmd.go b/core/xchain/cmd/root_cmd.go index 1559d69cf..3c8659bc2 100644 --- a/core/xchain/cmd/root_cmd.go +++ b/core/xchain/cmd/root_cmd.go @@ -1,12 +1,13 @@ package cmd import ( - "core/xchain/config" "fmt" "os" "strings" - sconfig "github.com/river-build/river/core/node/config" + "github.com/mitchellh/mapstructure" + "github.com/river-build/river/core/node/config" + "github.com/river-build/river/core/node/infra" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -48,8 +49,15 @@ func initConfigAndLog() { fmt.Printf("Failed to read config file, file=%v, error=%v\n", configFile, err) } - var configStruct config.Config - if err := viper.Unmarshal(&configStruct, viper.DecodeHook(sconfig.DecodeDurationHook())); err != nil { + var ( + configStruct config.Config + decodeHooks = mapstructure.ComposeDecodeHookFunc( + config.DecodeAddressOrAddressFileHook(), + config.DecodeDurationHook(), + ) + ) + + if err := viper.Unmarshal(&configStruct, viper.DecodeHook(decodeHooks)); err != nil { fmt.Printf("Failed to unmarshal config, error=%v\n", err) } diff --git a/core/xchain/config/config.go b/core/xchain/config/config.go deleted file mode 100644 index 33c0f9d8b..000000000 --- a/core/xchain/config/config.go +++ /dev/null @@ -1,88 +0,0 @@ -package config - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - node_config "github.com/river-build/river/core/node/config" - infra "github.com/river-build/river/core/node/infra/config" -) - -type ContractVersion string - -const ( - VersionDev ContractVersion = "dev" - VersionV3 ContractVersion = "v3" -) - -// Viper uses mapstructure module to marshal settings into config struct. -type Config struct { - Metrics infra.MetricsConfig `mapstructure:"metrics"` - Log infra.LogConfig `mapstructure:"log"` - ChainsString string `mapstructure:"chains"` - Chains map[uint64]string `mapstructure:"-"` // This is a derived field - EntitlementContract ContractConfig `mapstructure:"entitlement_contract"` - WalletLinkContract ContractConfig `mapstructure:"wallet_link_contract"` - TestingContract ContractConfig `mapstructure:"test_contract"` - contractVersion ContractVersion `mapstructure:"contract_version"` - TestCustomEntitlementContract ContractConfig `mapstructure:"test_custom_entitlement_contract"` - - // History indicates how far back xchain must look for entitlement check requests after start - History time.Duration - - // Blockchain configuration - BaseChain node_config.ChainConfig - RiverChain node_config.ChainConfig -} - -type ContractConfig struct { - Address string -} - -func (c *Config) GetContractVersion() ContractVersion { - if c.contractVersion == VersionV3 { - return VersionV3 - } else { - return VersionDev - } -} - -func (c *Config) GetEntitlementContractAddress() common.Address { - return common.HexToAddress(c.EntitlementContract.Address) -} - -func (c *Config) GetWalletLinkContractAddress() common.Address { - return common.HexToAddress(c.WalletLinkContract.Address) -} - -func (c *Config) GetMockEntitlementContractAddress() common.Address { - return common.HexToAddress(c.TestingContract.Address) -} - -func (c *Config) GetTestCustomEntitlementContractAddress() common.Address { - return common.HexToAddress(c.TestCustomEntitlementContract.Address) -} - -func (c *Config) Init() { - c.parseChains() -} - -func (c *Config) parseChains() { - chainUrls := make(map[uint64]string) - chainPairs := strings.Split(c.ChainsString, ",") - for _, pair := range chainPairs { - parts := strings.SplitN(pair, ":", 2) // Use SplitN to split into exactly two parts - if len(parts) == 2 { - chainID, err := strconv.Atoi(parts[0]) - if err != nil { - fmt.Printf("Error converting chainID to int: %v\n", err) - continue - } - chainUrls[uint64(chainID)] = parts[1] - } - } - c.Chains = chainUrls -} diff --git a/core/xchain/contracts/contracts.go b/core/xchain/contracts/contracts.go index f6e9ae72c..ccf6943fb 100644 --- a/core/xchain/contracts/contracts.go +++ b/core/xchain/contracts/contracts.go @@ -2,11 +2,12 @@ package contracts import ( "context" - "core/xchain/config" dev "core/xchain/contracts/dev" v3 "core/xchain/contracts/v3" "math/big" + "github.com/river-build/river/core/node/config" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/core/xchain/create_multi.sh b/core/xchain/create_multi.sh index 381d4b524..ea7191808 100755 --- a/core/xchain/create_multi.sh +++ b/core/xchain/create_multi.sh @@ -42,12 +42,13 @@ cd "$(dirname "$0")" : ${RUN_ENV:?} : ${RIVER_ENV:?} -BASE_CHAIN_URL="ws://localhost:8545" -BASE_REGISTRY_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/baseRegistry.json) -SPACE_FACTORY_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/spaceFactory.json) -ENTITLEMENT_TEST_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/entitlementGatedExample.json) -CUSTOM_ENTITLEMENT_TEST_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/customEntitlementExample.json) -BASE_CHAIN_ID=31337 +: ${SPACE_FACTORY_ADDRESS:?} +: ${WALLET_LINK_ADDRESS:?} +: ${BASE_REGISTRY_ADDRESS:?} +: ${RIVER_REGISTRY_ADDRESS:?} + +export ENTITLEMENT_TEST_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/entitlementGatedExample.json) +export CUSTOM_ENTITLEMENT_TEST_ADDRESS=$(jq -r '.address' ../../packages/generated/deployments/${RIVER_ENV}/base/addresses/customEntitlementExample.json) make @@ -57,8 +58,6 @@ N=5 # Base directory for the instances BASE_DIR="./run_files/${RUN_ENV}" - - mkdir -p "${BASE_DIR}" # Loop to create N instances in parallel @@ -76,7 +75,8 @@ do # Copy node binary and config template cp "./bin/xchain_node" "${INSTANCE_DIR}/bin" - cp default_config.yaml "${INSTANCE_DIR}/config/config.yaml" + # Using the shared default_config.yaml with the node + cp ../node/default_config.yaml "${INSTANCE_DIR}/config/config.yaml" # Substitute METRIC_PORT and create config.yaml METRICS_PORT=$((9080 + i)) @@ -84,18 +84,11 @@ do echo "Creating instance_${i}" yq eval ".metrics.port = \"$METRICS_PORT\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".entitlement_contract.url = \"$BASE_CHAIN_URL\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".entitlement_contract.address = \"$BASE_REGISTRY_ADDRESS\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".entitlement_contract.chainId = \"$BASE_CHAIN_ID\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".wallet_link_contract.url = \"$BASE_CHAIN_URL\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".wallet_link_contract.address = \"$SPACE_FACTORY_ADDRESS\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".wallet_link_contract.chainId = \"$BASE_CHAIN_ID\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_contract.url = \"$BASE_CHAIN_URL\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_contract.address = \"$ENTITLEMENT_TEST_ADDRESS\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_contract.chainId = \"$BASE_CHAIN_ID\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_custom_entitlement_contract.url = \"$BASE_CHAIN_URL\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_custom_entitlement_contract.address = \"$CUSTOM_ENTITLEMENT_TEST_ADDRESS\"" -i "${INSTANCE_DIR}/config/config.yaml" - yq eval ".test_custom_entitlement_contract.chainId = \"$BASE_CHAIN_ID\"" -i "${INSTANCE_DIR}/config/config.yaml" + yq eval ".entitlement_contract.address = strenv(BASE_REGISTRY_ADDRESS)" -i "${INSTANCE_DIR}/config/config.yaml" + yq eval ".wallet_link_contract.address = strenv(WALLET_LINK_ADDRESS)" -i "${INSTANCE_DIR}/config/config.yaml" + yq eval ".test_contract.address = strenv(ENTITLEMENT_TEST_ADDRESS)" -i "${INSTANCE_DIR}/config/config.yaml" + yq eval ".architectContract.address = strenv(SPACE_FACTORY_ADDRESS)" -i "${INSTANCE_DIR}/config/config.yaml" + yq eval ".registryContract.address = strenv(RIVER_REGISTRY_ADDRESS)" -i "${INSTANCE_DIR}/config/config.yaml" yq eval ".log.level = \"debug\"" -i "${INSTANCE_DIR}/config/config.yaml" diff --git a/core/xchain/default_config.yaml b/core/xchain/default_config.yaml deleted file mode 100644 index 7f9f9f5f8..000000000 --- a/core/xchain/default_config.yaml +++ /dev/null @@ -1,34 +0,0 @@ -chains: '31337:http://localhost:8545,31338:http://localhost:8546,84532:https://sepolia.base.org,11155111:https://ethereum-sepolia-rpc.publicnode.com' -history: 30s -entitlement_contract: - url: '' - chainId: '' - address: '' -test_contract: - url: '' - chainId: '' - address: '' -architectContract: - address: '' - version: '' -wallet_link_contract: - address: '' - version: '' -log: - file: logs/dev.log - level: info - console: true - noColor: false - format: text -metrics: - enabled: true - port: '9081' -# Blockchain configuration -baseChain: - chainId: 31337 - networkUrl: 'http://127.0.0.1:8545' - blockTimeMs: 2000 -riverChain: - chainId: 31338 - networkUrl: 'http://127.0.0.1:8546' - blockTimeMs: 2000 diff --git a/core/xchain/entitlement/check_operation.go b/core/xchain/entitlement/check_operation.go index 17982ec63..aef3dec13 100644 --- a/core/xchain/entitlement/check_operation.go +++ b/core/xchain/entitlement/check_operation.go @@ -4,13 +4,14 @@ import ( "context" "core/xchain/bindings/erc20" "core/xchain/bindings/erc721" - "core/xchain/config" "core/xchain/contracts" "fmt" "math/big" "sync" "time" + "github.com/river-build/river/core/node/config" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/river-build/river/core/node/dlog" diff --git a/core/xchain/entitlement/client_pool.go b/core/xchain/entitlement/client_pool.go index 75e25ead0..17e7ea809 100644 --- a/core/xchain/entitlement/client_pool.go +++ b/core/xchain/entitlement/client_pool.go @@ -2,7 +2,8 @@ package entitlement import ( "context" - "core/xchain/config" + + "github.com/river-build/river/core/node/config" "github.com/ethereum/go-ethereum/ethclient" . "github.com/river-build/river/core/node/base" diff --git a/core/xchain/entitlement/entitlement.go b/core/xchain/entitlement/entitlement.go index 47132c750..8b37fdcb8 100644 --- a/core/xchain/entitlement/entitlement.go +++ b/core/xchain/entitlement/entitlement.go @@ -2,13 +2,14 @@ package entitlement import ( "context" - "core/xchain/config" "errors" "fmt" "math/big" "sync" - er "core/xchain/contracts" + "github.com/river-build/river/core/node/config" + + er "github.com/river-build/river/core/xchain/contracts" "github.com/ethereum/go-ethereum/common" "github.com/river-build/river/core/node/dlog" @@ -21,7 +22,7 @@ func EvaluateRuleData( ruleData *er.IRuleData, ) (bool, error) { log := dlog.FromCtx(ctx) - log.Debug("Evaluating rule data", "ruleData", ruleData) + log.Info("Evaluating rule data", "ruleData", ruleData) opTree, err := getOperationTree(ctx, ruleData) if err != nil { return false, err diff --git a/core/xchain/entitlement/entitlement_test.go b/core/xchain/entitlement/entitlement_test.go index 1ca6fb19f..80322dfc9 100644 --- a/core/xchain/entitlement/entitlement_test.go +++ b/core/xchain/entitlement/entitlement_test.go @@ -2,12 +2,13 @@ package entitlement import ( "context" - "core/xchain/config" "core/xchain/examples" "math/big" "testing" "time" + "github.com/river-build/river/core/node/config" + "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" diff --git a/core/xchain/server/server.go b/core/xchain/server/server.go index 10abb5b7f..6abcb699d 100644 --- a/core/xchain/server/server.go +++ b/core/xchain/server/server.go @@ -2,14 +2,16 @@ package server import ( "context" - "core/xchain/config" - "core/xchain/contracts" "core/xchain/entitlement" "core/xchain/util" "log/slog" "math/big" "time" + "github.com/river-build/river/core/xchain/contracts" + + "github.com/river-build/river/core/node/config" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" diff --git a/core/xchain/server/server_test.go b/core/xchain/server/server_test.go index 4604d917c..a0f9dfa35 100644 --- a/core/xchain/server/server_test.go +++ b/core/xchain/server/server_test.go @@ -7,9 +7,6 @@ import ( "context" "core/xchain/client_simulator" xc_common "core/xchain/common" - "core/xchain/config" - "core/xchain/contracts" - test_contracts "core/xchain/contracts/test" "core/xchain/entitlement" "core/xchain/server" "fmt" @@ -19,6 +16,11 @@ import ( "testing" "time" + "github.com/river-build/river/core/xchain/contracts" + test_contracts "github.com/river-build/river/core/xchain/contracts/test" + + "github.com/river-build/river/core/node/config" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -257,17 +259,17 @@ func (st *serviceTester) Config() *config.Config { BaseChain: node_config.ChainConfig{}, RiverChain: node_config.ChainConfig{}, ChainsString: fmt.Sprintf("%d:%s", ChainID, BaseRpcEndpoint), - TestingContract: config.ContractConfig{ - Address: st.mockEntitlementGatedAddress.String(), + TestEntitlementContract: config.ContractConfig{ + Address: st.mockEntitlementGatedAddress, }, EntitlementContract: config.ContractConfig{ - Address: st.entitlementCheckerAddress.String(), + Address: st.entitlementCheckerAddress, }, WalletLinkContract: config.ContractConfig{ - Address: st.walletLinkingAddress.String(), + Address: st.walletLinkingAddress, }, TestCustomEntitlementContract: config.ContractConfig{ - Address: st.mockCustomEntitlementAddress.String(), + Address: st.mockCustomEntitlementAddress, }, Log: infra.LogConfig{ NoColor: true, @@ -446,10 +448,11 @@ func expectEntitlementCheckResult( require *require.Assertions, cs client_simulator.ClientSimulator, ctx context.Context, + cfg *config.Config, data contracts.IRuleData, expected bool, ) { - result, err := cs.EvaluateRuleData(ctx, data) + result, err := cs.EvaluateRuleData(ctx, cfg, data) require.NoError(err) require.Equal(expected, result) } @@ -526,7 +529,8 @@ func TestErc721Entitlements(t *testing.T) { st.Start(t) bc := st.ClientSimulatorBlockchain() - cs, err := client_simulator.New(ctx, st.Config(), bc, bc.Wallet) + cfg := st.Config() + cs, err := client_simulator.New(ctx, cfg, bc, bc.Wallet) require.NoError(err) cs.Start(ctx) defer cs.Stop() @@ -535,22 +539,22 @@ func TestErc721Entitlements(t *testing.T) { auth, contractAddress, erc721 := deployMockErc721Contract(require, st) // Expect no NFT minted for the client simulator wallet - expectEntitlementCheckResult(require, cs, ctx, erc721Check(ChainID, contractAddress, 1), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc721Check(ChainID, contractAddress, 1), false) // Mint an NFT for client simulator wallet. mintTokenForWallet(require, auth, st, erc721, cs.Wallet(), 1) // Check if the wallet a 1 balance of the NFT - should pass - expectEntitlementCheckResult(require, cs, ctx, erc721Check(ChainID, contractAddress, 1), true) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc721Check(ChainID, contractAddress, 1), true) // Checking for balance of 2 should fail - expectEntitlementCheckResult(require, cs, ctx, erc721Check(ChainID, contractAddress, 2), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc721Check(ChainID, contractAddress, 2), false) // Create a set of 3 linked wallets using client simulator address. _, wallet1, wallet2, _ := generateLinkedWallets(ctx, require, tc.sentByRootKeyWallet, st, cs.Wallet()) // Sanity check: balance of 4 across all 3 wallets should fail - expectEntitlementCheckResult(require, cs, ctx, erc721Check(ChainID, contractAddress, 4), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc721Check(ChainID, contractAddress, 4), false) // Mint 2 NFTs for wallet1. mintTokenForWallet(require, auth, st, erc721, wallet1, 2) @@ -559,7 +563,7 @@ func TestErc721Entitlements(t *testing.T) { mintTokenForWallet(require, auth, st, erc721, wallet2, 1) // Accumulated balance of 4 across all 3 wallets should now pass - expectEntitlementCheckResult(require, cs, ctx, erc721Check(ChainID, contractAddress, 4), true) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc721Check(ChainID, contractAddress, 4), true) }) } } @@ -616,8 +620,9 @@ func TestErc20Entitlements(t *testing.T) { defer st.Close() st.Start(t) + cfg := st.Config() bc := st.ClientSimulatorBlockchain() - cs, err := client_simulator.New(ctx, st.Config(), bc, bc.Wallet) + cs, err := client_simulator.New(ctx, cfg, bc, bc.Wallet) require.NoError(err) cs.Start(ctx) defer cs.Stop() @@ -626,22 +631,22 @@ func TestErc20Entitlements(t *testing.T) { auth, contractAddress, erc20 := deployMockErc20Contract(require, st) // Check for balance of 1 should fail, as this wallet has no coins. - expectEntitlementCheckResult(require, cs, ctx, erc20Check(ChainID, contractAddress, 1), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc20Check(ChainID, contractAddress, 1), false) // Mint 10 tokens for the client simulator wallet. mintErc20TokensForWallet(require, auth, st, erc20, cs.Wallet(), 10) // Check for balance of 10 should pass. - expectEntitlementCheckResult(require, cs, ctx, erc20Check(ChainID, contractAddress, 10), true) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc20Check(ChainID, contractAddress, 10), true) // Checking for balance of 20 should fail - expectEntitlementCheckResult(require, cs, ctx, erc20Check(ChainID, contractAddress, 20), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc20Check(ChainID, contractAddress, 20), false) // Create a set of 3 linked wallets using client simulator address. _, wallet1, wallet2, _ := generateLinkedWallets(ctx, require, tc.sentByRootKeyWallet, st, cs.Wallet()) // Sanity check: balance of 30 across all 3 wallets should fail - expectEntitlementCheckResult(require, cs, ctx, erc20Check(ChainID, contractAddress, 30), false) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc20Check(ChainID, contractAddress, 30), false) // Mint 19 tokens for wallet1. mintErc20TokensForWallet(require, auth, st, erc20, wallet1, 19) @@ -649,7 +654,7 @@ func TestErc20Entitlements(t *testing.T) { mintErc20TokensForWallet(require, auth, st, erc20, wallet2, 1) // Accumulated balance of 30 across all 3 wallets should now pass - expectEntitlementCheckResult(require, cs, ctx, erc20Check(ChainID, contractAddress, 30), true) + expectEntitlementCheckResult(require, cs, ctx, cfg, erc20Check(ChainID, contractAddress, 30), true) }) } } @@ -716,23 +721,26 @@ func TestCustomEntitlements(t *testing.T) { defer st.Close() st.Start(t) + cfg := st.Config() bc := st.ClientSimulatorBlockchain() - cs, err := client_simulator.New(ctx, st.Config(), bc, bc.Wallet) + cs, err := client_simulator.New(ctx, cfg, bc, bc.Wallet) require.NoError(err) cs.Start(ctx) defer cs.Stop() // Deploy mock custom entitlement contract to anvil chain auth, contractAddress, customEntitlement := deployMockCustomEntitlement(require, st) + t.Log("Deployed custom entitlement contract", contractAddress.Hex(), ChainID) // Initially the check should fail. customCheck := customEntitlementCheck(ChainID, contractAddress) - expectEntitlementCheckResult(require, cs, ctx, customCheck, false) + t.Log("Checking entitlement for client simulator wallet", customCheck) + expectEntitlementCheckResult(require, cs, ctx, cfg, customCheck, false) toggleEntitlement(require, auth, customEntitlement, cs.Wallet(), true) // Check should now succeed. - expectEntitlementCheckResult(require, cs, ctx, customCheck, true) + expectEntitlementCheckResult(require, cs, ctx, cfg, customCheck, true) // Untoggle entitlement for client simulator wallet toggleEntitlement(require, auth, customEntitlement, cs.Wallet(), false) @@ -742,13 +750,13 @@ func TestCustomEntitlements(t *testing.T) { for _, wallet := range []*node_crypto.Wallet{wallet1, wallet2, wallet3} { // Check should fail for all wallets. - expectEntitlementCheckResult(require, cs, ctx, customCheck, false) + expectEntitlementCheckResult(require, cs, ctx, cfg, customCheck, false) // Toggle entitlement for a particular linked wallet toggleEntitlement(require, auth, customEntitlement, wallet, true) // Check should now succeed for the wallet. - expectEntitlementCheckResult(require, cs, ctx, customCheck, true) + expectEntitlementCheckResult(require, cs, ctx, cfg, customCheck, true) // Untoggle entitlement for the wallet toggleEntitlement(require, auth, customEntitlement, wallet, false)