Skip to content

Commit

Permalink
optimize eth clients & refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
semyon-dev committed Feb 20, 2025
1 parent dafa256 commit 67921df
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: install protoc (protobuf)
uses: arduino/setup-protoc@v3
with:
version: "27.2"
version: "29.3"
include-pre-releases: false

- name: chmod to allow run script
Expand Down
19 changes: 3 additions & 16 deletions authutils/auth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ func GetSignerAddressFromMessage(message, signature []byte) (signer *common.Addr
keyOwnerAddressFieldLog := zap.Any("keyOwnerAddress", keyOwnerAddress)
zap.L().Debug("Message signature parsed",
//messageFieldLog,
signatureFieldLog,
messageHashFieldLog,
//signatureFieldLog,
//messageHashFieldLog,
//publicKeyFieldLog,
keyOwnerAddressFieldLog)

Expand Down Expand Up @@ -106,22 +106,9 @@ func CompareWithLatestBlockNumber(blockNumberPassed *big.Int) error {
return nil
}

// CheckIfTokenHasExpired Check if the block number ( date on which the token was issued is not more than 1 month)
func CheckIfTokenHasExpired(expiredBlock *big.Int) error {
currentBlockNumber, err := CurrentBlock()
if err != nil {
return err
}

if expiredBlock.Cmp(currentBlockNumber) < 0 {
return fmt.Errorf("authentication failed as the Free Call Token passed has expired")
}
return nil
}

// CurrentBlock Get the current block number from on chain
func CurrentBlock() (*big.Int, error) {
if ethHttpClient, _, err := blockchain.CreateEthereumClients(); err != nil {
if ethHttpClient, err := blockchain.CreateHTTPEthereumClient(); err != nil {
return nil, err
} else {
defer ethHttpClient.RawClient.Close()
Expand Down
19 changes: 2 additions & 17 deletions authutils/auth_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ package authutils

import (
"github.com/ethereum/go-ethereum/common"
"math/big"
"testing"
"time"

"github.com/singnet/snet-daemon/v5/config"
"github.com/stretchr/testify/assert"
"math/big"
"testing"
)

func TestCompareWithLatestBlockNumber(t *testing.T) {
Expand All @@ -21,19 +19,6 @@ func TestCompareWithLatestBlockNumber(t *testing.T) {
currentBlockNum, _ = CurrentBlock()
err = CompareWithLatestBlockNumber(currentBlockNum.Add(currentBlockNum, big.NewInt(1)))
assert.Equal(t, nil, err)

}

func TestCheckAllowedBlockDifferenceForToken(t *testing.T) {
config.Vip().Set(config.BlockChainNetworkSelected, "sepolia")
config.Validate()
currentBlockNum, _ := CurrentBlock()
err := CheckIfTokenHasExpired(currentBlockNum.Sub(currentBlockNum, big.NewInt(20000)))
assert.Equal(t, err.Error(), "authentication failed as the Free Call Token passed has expired")
time.Sleep(250 * time.Millisecond) // because of HTTP 429 Too Many Requests
currentBlockNum, _ = CurrentBlock()
err = CheckIfTokenHasExpired(currentBlockNum.Add(currentBlockNum, big.NewInt(20)))
assert.Equal(t, nil, err)
}

func TestVerifyAddress(t *testing.T) {
Expand Down
40 changes: 27 additions & 13 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,14 @@ func NewProcessor(metadata *ServiceMetadata) (Processor, error) {
}

// Setup ethereum client

if ethHttpClients, ethWSClients, err := CreateEthereumClients(); err != nil {
if ethHttpClients, err := CreateEthereumClient(); err != nil {
return p, errors.Wrap(err, "error creating RPC client")
} else {
p.rawHttpClient = ethHttpClients.RawClient
p.ethHttpClient = ethHttpClients.EthClient
p.rawWSClient = ethWSClients.RawClient
p.ethWSClient = ethWSClients.EthClient
}

// TODO: if address is not in config, try to load it using network

//TODO: Read this from github

p.escrowContractAddress = metadata.GetMpeAddress()
Expand All @@ -92,6 +88,13 @@ func (processor *Processor) ReconnectToWsClient() error {

zap.L().Debug("Try to reconnect to websocket client")

return processor.ConnectToWsClient()
}

func (processor *Processor) ConnectToWsClient() error {

zap.L().Debug("Try to connect to websocket client")

newEthWSClients, err := CreateWSEthereumClient()
if err != nil {
return err
Expand Down Expand Up @@ -124,17 +127,24 @@ func (processor *Processor) GetEthWSClient() *ethclient.Client {
}

func (processor *Processor) CurrentBlock() (currentBlock *big.Int, err error) {
// We have to do a raw call because the standard method of ethClient.HeaderByNumber(ctx, nil) errors on
// unmarshaling the response currently. See https://github.com/ethereum/go-ethereum/issues/3230
var currentBlockHex string
if err = processor.rawHttpClient.CallContext(context.Background(), &currentBlockHex, "eth_blockNumber"); err != nil {
latestBlock, err := processor.ethHttpClient.BlockNumber(context.Background())
if err != nil {
zap.L().Error("error determining current block", zap.Error(err))
return nil, fmt.Errorf("error determining current block: %v", err)
}
return new(big.Int).SetUint64(latestBlock), nil
}

currentBlockBytes := common.FromHex(currentBlockHex)
currentBlock = new(big.Int).SetBytes(currentBlockBytes)
func (processor *Processor) CompareWithLatestBlockNumber(blockNumberPassed *big.Int, allowedBlockChainDifference uint64) (err error) {
latestBlockNumber, err := processor.CurrentBlock()
if err != nil {
return err
}

differenceInBlockNumber := blockNumberPassed.Sub(blockNumberPassed, latestBlockNumber)
if differenceInBlockNumber.Abs(differenceInBlockNumber).Uint64() > allowedBlockChainDifference {
return fmt.Errorf("authentication failed as the signature passed has expired")
}
return
}

Expand All @@ -145,6 +155,10 @@ func (processor *Processor) HasIdentity() bool {
func (processor *Processor) Close() {
processor.ethHttpClient.Close()
processor.rawHttpClient.Close()
processor.ethWSClient.Close()
processor.rawWSClient.Close()
if processor.ethWSClient != nil {
processor.ethWSClient.Close()
}
if processor.rawWSClient != nil {
processor.rawWSClient.Close()
}
}
64 changes: 64 additions & 0 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package blockchain

import (
"github.com/singnet/snet-daemon/v5/config"
"math/big"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

const metadataJson = "{\n \"version\": 1,\n \"display_name\": \"semyon_dev\",\n \"encoding\": \"proto\",\n \"service_type\": \"grpc\",\n \"service_api_source\": \"ipfs://QmV9bBsLAZfXGibdU3isPwDn8SxAPkqg6YzcKamSCxnBCR\",\n \"mpe_address\": \"0x7E0aF8988DF45B824b2E0e0A87c6196897744970\",\n \"groups\": [\n {\n \"group_name\": \"default_group\",\n \"endpoints\": [\n \"http://localhost:7000\"\n ],\n \"pricing\": [\n {\n \"price_model\": \"fixed_price\",\n \"price_in_cogs\": 1,\n \"default\": true\n }\n ],\n \"group_id\": \"FtNuizEOUsVCd5f2Fij9soehtRSb58LlTePgkVnsgVI=\",\n \"free_call_signer_address\": \"0x747155e03c892B8b311B7Cfbb920664E8c6792fA\",\n \"free_calls\": 25,\n \"daemon_addresses\": [\n \"0x747155e03c892B8b311B7Cfbb920664E8c6792fA\"\n ]\n },\n {\n \"group_name\": \"not_default\",\n \"endpoints\": [\n \"http://localhost:7000\"\n ],\n \"pricing\": [\n {\n \"price_model\": \"fixed_price\",\n \"price_in_cogs\": 1,\n \"default\": true\n }\n ],\n \"group_id\": \"udN0SLIvsDdvQQe3Ltv/NwqCh7sPKdz4scYmlI7AMdE=\",\n \"free_call_signer_address\": \"0x747155e03c892B8b311B7Cfbb920664E8c6792fA\",\n \"free_calls\": 35,\n \"daemon_addresses\": [\n \"0x747155e03c892B8b311B7Cfbb920664E8c6792fA\"\n ]\n }\n ],\n \"assets\": {},\n \"media\": [],\n \"tags\": [],\n \"service_description\": {\n \"description\": \"Test service with localhost endpoint!\",\n \"url\": \"\"\n }\n}"

// ProcessorTestSuite is a test suite for the Processor struct
type ProcessorTestSuite struct {
suite.Suite
processor *Processor
}

// SetupSuite initializes the Ethereum client before running the tests
func (suite *ProcessorTestSuite) SetupSuite() {
config.Vip().Set(config.BlockchainEnabledKey, true)
config.Vip().Set(config.BlockChainNetworkSelected, "sepolia")
config.Validate()
srv, err := InitServiceMetaDataFromJson([]byte(metadataJson))
if err != nil {
return
}
p, err := NewProcessor(srv)
assert.Nil(suite.T(), err)
suite.processor = &p
}

// ✅ Test: If the block number difference is within the allowed limit → no error
func (suite *ProcessorTestSuite) TestCompareWithLatestBlockNumber_WithinLimit() {
latestBlock, err := suite.processor.CurrentBlock()
suite.Require().NoError(err, "CurrentBlock() should not return an error")

// Simulate a block number within the allowed range (+2)
blockNumberPassed := new(big.Int).Add(latestBlock, big.NewInt(2))
err = suite.processor.CompareWithLatestBlockNumber(blockNumberPassed, 5)

// Expect no error
assert.NoError(suite.T(), err, "Expected no error when block difference is within the limit")
}

// ❌ Test: If the block number difference exceeds the allowed limit → return an error
func (suite *ProcessorTestSuite) TestCompareWithLatestBlockNumber_ExceedsLimit() {
latestBlock, err := suite.processor.CurrentBlock()
suite.Require().NoError(err, "CurrentBlock() should not return an error")

// Simulate a block number exceeding the allowed limit (+10)
blockNumberPassed := new(big.Int).Add(latestBlock, big.NewInt(10))
err = suite.processor.CompareWithLatestBlockNumber(blockNumberPassed, 5)

// Expect an error
assert.Error(suite.T(), err, "Expected an error when block difference exceeds the limit")
assert.Contains(suite.T(), err.Error(), "authentication failed", "Error message should indicate signature expiration")
}

// Run the test suite
func TestProcessorTestSuite(t *testing.T) {
suite.Run(t, new(ProcessorTestSuite))
}
12 changes: 3 additions & 9 deletions blockchain/ethereumClient.go → blockchain/ethereum_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,12 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth))
}

func CreateEthereumClients() (*EthereumClient, *EthereumClient, error) {
func CreateEthereumClient() (*EthereumClient, error) {
ethereumHttpClient, err := CreateHTTPEthereumClient()
if err != nil {
return nil, nil, err
return nil, err
}

ethereumWsClient, err := CreateWSEthereumClient()
if err != nil {
return nil, nil, err
}

return ethereumHttpClient, ethereumWsClient, nil
return ethereumHttpClient, nil
}

func CreateHTTPEthereumClient() (*EthereumClient, error) {
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,8 @@ func setDefaultPricing(metaData *ServiceMetadata) (err error) {
return nil
}
}
err = fmt.Errorf("MetaData does not have the default pricing set ")
zap.L().Warn("Error in set default pricing", zap.Error(err))
err = fmt.Errorf("metadata does not have the default pricing set")
zap.L().Warn("[setDefaultPricing] Error in set default pricing", zap.Error(err))
return err
}

Expand All @@ -432,13 +432,12 @@ func setMultiPartyEscrowAddress(metaData *ServiceMetadata) {
}

func setFreeCallData(metaData *ServiceMetadata) error {

if metaData.defaultGroup.FreeCalls > 0 {
metaData.isfreeCallAllowed = true
metaData.freeCallsAllowed = metaData.defaultGroup.FreeCalls
//If the signer address is not a valid address, then return back an error
if !common.IsHexAddress(metaData.defaultGroup.FreeCallSigner) {
return fmt.Errorf("MetaData does not have 'free_call_signer_address defined correctly" + errs.ErrDescURL(errs.InvalidMetadata))
return fmt.Errorf("metadata does not have 'free_call_signer_address defined correctly")
}
metaData.freeCallSignerAddress = common.HexToAddress(ToChecksumAddress(metaData.defaultGroup.FreeCallSigner))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ func TestInitServiceMetaDataFromJson(t *testing.T) {
//Parse Bad JSON
_, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "0x7DF35C98f41F3Af0df1dc4c7F7D4C19a71Dd059F", "", 1)))
if err != nil {
assert.Contains(t, err.Error(), "MetaData does not have 'free_call_signer_address defined correctly")
assert.Contains(t, err.Error(), "metadata does not have 'free_call_signer_address defined correctly")
}
_, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "default_pricing", "dummy", 1)))
if err != nil {
assert.Equal(t, err.Error(), "MetaData does not have the default pricing set ")
assert.Equal(t, err.Error(), "metadata does not have the default pricing set")
}

}
Expand All @@ -98,7 +98,7 @@ func Test_setDefaultPricing(t *testing.T) {
err := setDefaultPricing(&ServiceMetadata{})
assert.NotNil(t, err)
err = setDefaultPricing(&ServiceMetadata{Groups: []OrganizationGroup{{GroupName: "default_group"}}})
assert.Equal(t, err.Error(), "MetaData does not have the default pricing set ")
assert.Equal(t, err.Error(), "metadata does not have the default pricing set")
}

func Test_setGroup(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions config/blockchain_network_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ func setRegistryAddress() (err error) {
// fileName, GetString(BlockChainNetworkSelected), err)
//}

if err = deriveDatafromJSON(data); err != nil {
if err = deriveDataFromJSON(data); err != nil {
return err
}
return nil
}

func deriveDatafromJSON(data []byte) (err error) {
func deriveDataFromJSON(data []byte) (err error) {
m := map[string]any{}
err = json.Unmarshal(data, &m)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions config/blockchain_network_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func Test_setRegistryAddress(t *testing.T) {
wantErr bool
}{
{"11155111", false},
{"5", false},
{"1", false},
{"11155111_", true},
}

Expand All @@ -130,7 +130,6 @@ func Test_setRegistryAddress(t *testing.T) {
}
})
}

}

func Test_setBlockChainNetworkDetails(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const (
"payment_channel_storage_client": {
"connection_timeout": "0s",
"request_timeout": "0s",
"hot_reload": true
"hot_reload": false
},
"payment_channel_storage_server": {
"id": "storage-1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ func (l *ContractEventListener) ListenOrganizationMetadataChanging() {
}

ethWSClient := l.BlockchainProcessor.GetEthWSClient()
if ethWSClient == nil {
err := l.BlockchainProcessor.ConnectToWsClient()
if err != nil {
zap.L().Warn("[ListenOrganizationMetadataChanging]", zap.Error(err))
}
}

registryFilterer := blockchain.GetRegistryFilterer(ethWSClient)
orgIdFilter := blockchain.MakeTopicFilterer(l.CurrentOrganizationMetaData.OrgID)
Expand Down
Loading

0 comments on commit 67921df

Please sign in to comment.