diff --git a/.github/workflows/manual-deploy-ten-bridge.yml b/.github/workflows/manual-deploy-ten-bridge.yml index a6ab57c4b2..e5ab7feb69 100644 --- a/.github/workflows/manual-deploy-ten-bridge.yml +++ b/.github/workflows/manual-deploy-ten-bridge.yml @@ -58,7 +58,7 @@ jobs: name: ${{ github.event.inputs.testnet_type }}-fe-ten-bridge location: "uksouth" restart-policy: "Never" - environment-variables: NEXT_PUBLIC_BRIDGE_API_HOST_ENVIRONMENT=${{ github.event.inputs.testnet_type }} NEXT_PUBLIC_FE_VERSION=${{ GITHUB.RUN_NUMBER }}-${{ GITHUB.SHA }} + environment-variables: NEXT_PUBLIC_BRIDGE_API_HOST=https://${{ github.event.inputs.testnet_type }}.ten.xyz/v1 NEXT_PUBLIC_FE_VERSION=${{ GITHUB.RUN_NUMBER }}-${{ GITHUB.SHA }} command-line: npm run start-prod ports: "80" cpu: 2 diff --git a/changelog.md b/changelog.md index 5cccebdc59..f687f7d2ab 100644 --- a/changelog.md +++ b/changelog.md @@ -3,31 +3,38 @@ # Ten Testnet Change Log # August 2024-08-08 (v0.26.0) -* This is an L2 deployment release meaning state will be lost in order to upgrade the network. The release - predominantly fixes known minor issues in the network, including issues deploying and interacting - with contracts using ethers6, and extracting event logs from tx receipts for bridge operations. +* This is an L2 deployment release meaning state will be lost in order to upgrade the network. The release adds in + rate limiting to the TEN gateway, support for using proxy deployments, and for using the ethers6 web3 library. * A full list of the PRs merged in this release is as below; - * `db6e507e` Revert refactor event log filtering for subscriptions (#2013) - * `b043708a` Initiate bridge deployment (#2012) - * `475b7057` Disable rate limiting on local testnet (#2005) - * `86418f6d` Stopped returning errors on republish. (#2008) - * `396c113d` Only configure docker autorestart on the main containers (#2007) - * `e30e4eaa` Filter out irrelevant l1 txs, before sending into the enclave (#2006) - * `7b62b2e4` Revert message address indexing (#2002) - * `65d96465` Add dummy fields to keep ethers6 happy (#2003) - * `c3ad0a44` Fix for dependency (#2000) - * `3f7f12f9` Implement mock maxpriorityfeepergas (#1999) - * `9e91e5c2` Add ten headers (#1998) - * `ad61bdb0` Gateway rate limiting (#1942) - * `9bd08a23` Fix getblock rpc (#1997) - * `ec5315b6` Personal transaction/contract deployment details page (#1990) - * `97792e4e` Getstorageat with whitelist for proxies deployment (#1987) - * `e9b29779` Allow cors all origins to fix firefox error (#1991) - * `b13272b3` Replace custom query with personal transactions (#1986) - * `81ad4043` Refactor event log filtering for subscriptions (#1988) - * `6a4bc5b9` Fix event sql query (#1984) - * `a3a901bf` Frontend updates (#1932) - * `3b75a255` Block binding fix (#1982) + * `86ee4106` Add network config endpoint (#2016) + * `f692c269` Change network test port (#2018) + * `9b870e0b` Correct print output of the faucet (#2019) + * `1eb7c28e` Improve deadline error (#2015) + * `9e72c760` Remove file logger from the gateway (#2010) + * `68813df6` Increase new heads timeout (#2014) + * `3846fa56` Upgrade local geth version to pos (#1950) + * `d32dfda7` Change log for v0.26 (#2011) + * `db6e507e` Revert refactor event log filtering for subscriptions (#2013) + * `b043708a` Initiate bridge deployment (#2012) + * `475b7057` Disable rate limiting on local testnet (#2005) + * `86418f6d` Stopped returning errors on republish. (#2008) + * `396c113d` Only configure docker autorestart on the main containers (#2007) + * `e30e4eaa` Filter out irrelevant l1 txs, before sending into the enclave (#2006) + * `7b62b2e4` Revert message address indexing (#2002) + * `65d96465` Add dummy fields to keep ethers6 happy (#2003) + * `c3ad0a44` Fix for dependency (#2000) + * `3f7f12f9` Implement mock maxpriorityfeepergas (#1999) + * `9e91e5c2` Add ten headers (#1998) + * `ad61bdb0` Gateway rate limiting (#1942) + * `9bd08a23` Fix getblock rpc (#1997) + * `ec5315b6` Personal transaction/contract deployment details page (#1990) + * `97792e4e` Getstorageat with whitelist for proxies deployment (#1987) + * `e9b29779` Allow cors all origins to fix firefox error (#1991) + * `b13272b3` Replace custom query with personal transactions (#1986) + * `81ad4043` Refactor event log filtering for subscriptions (#1988) + * `6a4bc5b9` Fix event sql query (#1984) + * `a3a901bf` Frontend updates (#1932) + * `3b75a255` Block binding fix (#1982) # July 2024-07-03 (v0.25.0) * This is an L2 deployment release meaning state will be lost in order to upgrade the network. Any dApps on the diff --git a/contracts/src/bridge/frontend/Dockerfile b/contracts/src/bridge/frontend/Dockerfile index 1618f5b024..0b68092cf4 100644 --- a/contracts/src/bridge/frontend/Dockerfile +++ b/contracts/src/bridge/frontend/Dockerfile @@ -8,11 +8,11 @@ COPY ./contracts/src/bridge/frontend /home/obscuro/go-obscuro/contracts/src/brid WORKDIR /home/obscuro/go-obscuro/contracts/src/bridge/frontend # ARG for build-time variable -ARG BRIDGE_ENVIRONMENT +ARG API_HOST ARG GOOGLE_ANALYTICS_ID # ENV for URL to be used in the app -ENV NEXT_PUBLIC_BRIDGE_API_HOST_ENVIRONMENT=${BRIDGE_ENVIRONMENT} +ENV NEXT_PUBLIC_BRIDGE_API_HOST=${API_HOST} ENV NEXT_PUBLIC_BRIDGE_GOOGLE_ANALYTICS_ID=${GOOGLE_ANALYTICS_ID} RUN npm install diff --git a/go/enclave/nodetype/common.go b/go/enclave/nodetype/common.go index bff4a94447..c414f63c81 100644 --- a/go/enclave/nodetype/common.go +++ b/go/enclave/nodetype/common.go @@ -20,7 +20,7 @@ func ExportCrossChainData(ctx context.Context, storage storage.Storage, fromSeqN return nil, errutil.ErrCrossChainBundleNoBatches } - //todo - siliev - all those fetches need to be atomic + // todo - siliev - all those fetches need to be atomic header, err := storage.FetchHeadBatchHeader(ctx) if err != nil { return nil, err diff --git a/integration/constants.go b/integration/constants.go index ace11bc1da..386599e773 100644 --- a/integration/constants.go +++ b/integration/constants.go @@ -3,20 +3,20 @@ package integration // Tracks the start ports handed out to different tests, in a bid to minimise conflicts. // Note: the max should not exceed 30000 because the OS can use those ports and we'll get conflicts const ( - StartPortEth2NetworkTests = 10000 - StartPortTenscanUnitTest = 11000 - StartPortNodeRunnerTest = 12000 - StartPortSimulationGethInMem = 14000 - StartPortSimulationInMem = 15000 - StartPortSimulationFullNetwork = 16000 - StartPortNetworkTests = 17000 - StartPortSmartContractTests = 18000 - StartPortContractDeployerTest1 = 19000 - StartPortContractDeployerTest2 = 21000 - StartPortFaucetUnitTest = 22000 - StartPortFaucetHTTPUnitTest = 23000 - StartPortTenGatewayUnitTest = 24000 - StartPortWalletExtensionUnitTest = 25000 + StartPortEth2NetworkTests = 10000 + StartPortTenscanUnitTest = 11000 + StartPortNodeRunnerTest = 12000 + StartPortSimulationGethInMem = 14000 + StartPortSimulationInMem = 15000 + StartPortSimulationFullNetwork = 16000 + DoNotUse = 17000 // port conflict on this address + StartPortSmartContractTests = 18000 + StartPortContractDeployerTest1 = 19000 + StartPortContractDeployerTest2 = 21000 + StartPortFaucetUnitTest = 22000 + StartPortFaucetHTTPUnitTest = 23000 + StartPortTenGatewayUnitTest = 24000 + StartPortNetworkTests = 25000 DefaultGethWSPortOffset = 100 DefaultGethAUTHPortOffset = 200 diff --git a/tools/faucet/cmd/main.go b/tools/faucet/cmd/main.go index b865ceba1b..d22030eee5 100644 --- a/tools/faucet/cmd/main.go +++ b/tools/faucet/cmd/main.go @@ -29,7 +29,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("💡 Faucet started - visit http://%s/viewingkeys/ to generate an ephemeral viewing key.\n", cfg.Host) + fmt.Printf("💡 Faucet started on http://%s:%d\n", cfg.Host, cfg.HTTPPort) // Create a channel to receive signals signalCh := make(chan os.Signal, 1) diff --git a/tools/walletextension/common/common.go b/tools/walletextension/common/common.go index a9a099b362..94ac8be729 100644 --- a/tools/walletextension/common/common.go +++ b/tools/walletextension/common/common.go @@ -3,9 +3,6 @@ package common import ( "encoding/json" "fmt" - "os" - - gethforklog "github.com/ten-protocol/go-ten/lib/gethfork/log" gethrpc "github.com/ten-protocol/go-ten/lib/gethfork/rpc" @@ -79,13 +76,3 @@ func (r *RPCRequest) Clone() *RPCRequest { Params: r.Params, } } - -// NewFileLogger is a logger factory function -func NewFileLogger() gethlog.Logger { - // Open or create your log file - file, err := os.OpenFile("gateway_logs.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644) - if err != nil { - panic(err) - } - return gethlog.NewLogger(gethlog.NewGlogHandler(gethforklog.NewTerminalHandler(file, false))) -} diff --git a/tools/walletextension/common/constants.go b/tools/walletextension/common/constants.go index 3fdb4d63a2..5b72b8ee35 100644 --- a/tools/walletextension/common/constants.go +++ b/tools/walletextension/common/constants.go @@ -24,6 +24,7 @@ const ( PathRevoke = "/revoke/" PathHealth = "/health/" PathNetworkHealth = "/network-health/" + PathNetworkConfig = "/network-config/" WSProtocol = "ws://" HTTPProtocol = "http://" EncryptedTokenQueryParameter = "token" diff --git a/tools/walletextension/httpapi/routes.go b/tools/walletextension/httpapi/routes.go index abb8f9573a..cbdb5baf8e 100644 --- a/tools/walletextension/httpapi/routes.go +++ b/tools/walletextension/httpapi/routes.go @@ -58,6 +58,10 @@ func NewHTTPRoutes(walletExt *rpcapi.Services) []node.Route { Name: common.APIVersion1 + common.PathVersion, Func: httpHandler(walletExt, versionRequestHandler), }, + { + Name: common.APIVersion1 + common.PathNetworkConfig, + Func: httpHandler(walletExt, networkConfigRequestHandler), + }, } } @@ -317,6 +321,57 @@ func networkHealthRequestHandler(walletExt *rpcapi.Services, userConn UserConn) } } +func networkConfigRequestHandler(walletExt *rpcapi.Services, userConn UserConn) { + // read the request + _, err := userConn.ReadRequest() + if err != nil { + walletExt.Logger().Error("error reading request", log.ErrKey, err) + return + } + + // Call the RPC method to get the network configuration + networkConfig, err := walletExt.GetTenNetworkConfig() + if err != nil { + walletExt.Logger().Error("error fetching network config", log.ErrKey, err) + } + + // Define a struct to represent the response + type NetworkConfigResponse struct { + ManagementContractAddress string `json:"ManagementContractAddress"` + L1StartHash string `json:"L1StartHash"` + MessageBusAddress string `json:"MessageBusAddress"` + L2MessageBusAddress string `json:"L2MessageBusAddress"` + ImportantContracts map[string]string `json:"ImportantContracts"` + } + + // Convert the TenNetworkInfo fields to strings + importantContracts := make(map[string]string) + for name, address := range networkConfig.ImportantContracts { + importantContracts[name] = address.Hex() + } + + networkConfigResponse := NetworkConfigResponse{ + ManagementContractAddress: networkConfig.ManagementContractAddress.Hex(), + L1StartHash: networkConfig.L1StartHash.Hex(), + MessageBusAddress: networkConfig.MessageBusAddress.Hex(), + L2MessageBusAddress: networkConfig.L2MessageBusAddress.Hex(), + ImportantContracts: importantContracts, + } + + // Marshal the response into JSON format + data, err := json.Marshal(networkConfigResponse) + if err != nil { + walletExt.Logger().Error("error marshaling response", log.ErrKey, err) + return + } + + // Write the response back to the user + err = userConn.WriteResponse(data) + if err != nil { + walletExt.Logger().Error("error writing success response", log.ErrKey, err) + } +} + // Handles request to /version endpoint. func versionRequestHandler(walletExt *rpcapi.Services, userConn UserConn) { // read the request diff --git a/tools/walletextension/rpcapi/transaction_api.go b/tools/walletextension/rpcapi/transaction_api.go index 3833db0e77..a0a8baedd4 100644 --- a/tools/walletextension/rpcapi/transaction_api.go +++ b/tools/walletextension/rpcapi/transaction_api.go @@ -101,7 +101,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. } func (s *TransactionAPI) SendTransaction(ctx context.Context, args gethapi.TransactionArgs) (common.Hash, error) { - txRec, err := ExecAuthRPC[common.Hash](ctx, s.we, &ExecCfg{account: args.From}, "eth_sendTransaction", args) + txRec, err := ExecAuthRPC[common.Hash](ctx, s.we, &ExecCfg{account: args.From, timeout: sendTransactionDuration}, "eth_sendTransaction", args) if err != nil { return common.Hash{}, err } @@ -131,7 +131,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args gethapi.Trans } func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { - txRec, err := ExecAuthRPC[common.Hash](ctx, s.we, &ExecCfg{tryAll: true}, "eth_sendRawTransaction", input) + txRec, err := ExecAuthRPC[common.Hash](ctx, s.we, &ExecCfg{tryAll: true, timeout: sendTransactionDuration}, "eth_sendRawTransaction", input) if err != nil { return common.Hash{}, err } diff --git a/tools/walletextension/rpcapi/utils.go b/tools/walletextension/rpcapi/utils.go index a90eacb810..13d6197b2d 100644 --- a/tools/walletextension/rpcapi/utils.go +++ b/tools/walletextension/rpcapi/utils.go @@ -34,13 +34,15 @@ const ( ethCallAddrPadding = "000000000000000000000000" notAuthorised = "not authorised" + serverBusy = "server busy. please retry later" longCacheTTL = 5 * time.Hour shortCacheTTL = 1 * time.Minute // hardcoding the maximum time for an RPC request // this value will be propagated to the node and enclave and all the operations - maximumRPCCallDuration = 5 * time.Second + maximumRPCCallDuration = 5 * time.Second + sendTransactionDuration = 20 * time.Second ) var rpcNotImplemented = fmt.Errorf("rpc endpoint not implemented") @@ -52,6 +54,7 @@ type ExecCfg struct { tryUntilAuthorised bool adjustArgs func(acct *GWAccount) []any cacheCfg *CacheCfg + timeout time.Duration } type CacheStrategy uint8 @@ -136,10 +139,19 @@ func ExecAuthRPC[R any](ctx context.Context, w *Services, cfg *ExecCfg, method s } // wrap the context with a timeout to prevent long executions - timeoutContext, cancelCtx := context.WithTimeout(ctx, maximumRPCCallDuration) + deadline := cfg.timeout + // if not set, use default + if deadline == 0 { + deadline = maximumRPCCallDuration + } + timeoutContext, cancelCtx := context.WithTimeout(ctx, deadline) defer cancelCtx() err := rpcClient.CallContext(timeoutContext, &result, method, adjustedArgs...) + // return a friendly error to the user + if err != nil && errors.Is(err, context.DeadlineExceeded) { + return nil, fmt.Errorf(serverBusy) + } return result, err }) if err != nil { @@ -265,7 +277,7 @@ func withCache[R any](cache cache.Cache, cfg *CacheCfg, cacheKey []byte, onCache func audit(services *Services, msg string, params ...any) { if services.Config.VerboseFlag { - services.FileLogger.Info(fmt.Sprintf(msg, params...)) + services.logger.Info(fmt.Sprintf(msg, params...)) } } diff --git a/tools/walletextension/rpcapi/wallet_extension.go b/tools/walletextension/rpcapi/wallet_extension.go index fae47871f7..6d7c036b85 100644 --- a/tools/walletextension/rpcapi/wallet_extension.go +++ b/tools/walletextension/rpcapi/wallet_extension.go @@ -41,7 +41,6 @@ type Services struct { HostAddrWS string // The WS address on which the Ten host can be reached Storage storage.Storage logger gethlog.Logger - FileLogger gethlog.Logger stopControl *stopcontrol.StopControl version string Cache cache.Cache @@ -58,7 +57,6 @@ type NewHeadNotifier interface { } func NewServices(hostAddrHTTP string, hostAddrWS string, storage storage.Storage, stopControl *stopcontrol.StopControl, version string, logger gethlog.Logger, config *common.Config) *Services { - newFileLogger := common.NewFileLogger() newGatewayCache, err := cache.NewCache(logger) if err != nil { logger.Error(fmt.Errorf("could not create cache. Cause: %w", err).Error()) @@ -101,7 +99,6 @@ func NewServices(hostAddrHTTP string, hostAddrWS string, storage storage.Storage HostAddrWS: hostAddrWS, Storage: storage, logger: logger, - FileLogger: newFileLogger, stopControl: stopControl, version: version, Cache: newGatewayCache, @@ -147,7 +144,7 @@ func subscribeToNewHeadsWithRetry(ch chan *tencommon.BatchHeader, services Servi } return err }, - retry.NewTimeoutStrategy(10*time.Minute, 1*time.Second), + retry.NewTimeoutStrategy(20*time.Minute, 1*time.Second), ) if err != nil { logger.Error("could not subscribe for new head blocks.", log.ErrKey, err) @@ -283,6 +280,14 @@ func (w *Services) GetTenNodeHealthStatus() (bool, error) { return *res, err } +func (w *Services) GetTenNetworkConfig() (tencommon.TenNetworkInfo, error) { + res, err := withPlainRPCConnection[tencommon.TenNetworkInfo](context.Background(), w, func(client *gethrpc.Client) (*tencommon.TenNetworkInfo, error) { + res, err := obsclient.NewObsClient(client).GetConfig() + return res, err + }) + return *res, err +} + func (w *Services) GenerateUserMessageToSign(encryptionToken []byte, formatsSlice []string) (string, error) { // Check if the formats are valid for _, format := range formatsSlice {