Skip to content

Commit

Permalink
(OraklNode) Cache abi (#1914)
Browse files Browse the repository at this point in the history
* wip

* fix: rename file and set visibility
  • Loading branch information
nick-bisonai authored Jul 29, 2024
1 parent 00fa9ba commit 23e8d53
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 21 deletions.
45 changes: 45 additions & 0 deletions node/pkg/chain/tests/cachedabi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package tests

import (
"strings"
"testing"

"bisonai.com/orakl/node/pkg/chain/utils"
errorsentinel "bisonai.com/orakl/node/pkg/error"
"github.com/klaytn/klaytn/accounts/abi"
"github.com/stretchr/testify/assert"
)

func TestAbiCache(t *testing.T) {
functionSignature := "testFunctionSignature"
functionName := "testFunctionName"
abiJSON := `[
{
"constant": true,
"inputs": [],
"name": "testFunctionName",
"outputs": [{"name": "", "type": "uint256"}],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]`
parsedAbi, err := abi.JSON(strings.NewReader(abiJSON))
assert.NoError(t, err)

// Test SetAbi
utils.SetAbi(functionSignature, &parsedAbi, functionName)

// Test GetAbi
retrievedAbi, retrievedFunctionName, err := utils.GetAbi(functionSignature)
assert.NoError(t, err)
assert.NotNil(t, retrievedAbi)
assert.Equal(t, functionName, retrievedFunctionName)

// Ensure the retrieved ABI matches the set ABI
assert.Equal(t, parsedAbi.Methods[functionName].Name, retrievedAbi.Methods[functionName].Name)

// Test GetAbi for non-existent entry
_, _, err = utils.GetAbi("nonExistentSignature")
assert.ErrorIs(t, err, errorsentinel.ErrChainCachedAbiNotFound)
}
55 changes: 55 additions & 0 deletions node/pkg/chain/utils/abicached.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package utils

import (
"sync"

errorsentinel "bisonai.com/orakl/node/pkg/error"
"github.com/klaytn/klaytn/accounts/abi"
)

type AbiWithFunctionName struct {
Abi *abi.ABI
FunctionName string
}

type AbiCache struct {
AbiMap map[string]*AbiWithFunctionName
mu sync.RWMutex
}

func newAbiCache() *AbiCache {
return &AbiCache{
AbiMap: make(map[string]*AbiWithFunctionName),
mu: sync.RWMutex{},
}
}

var AbiCacheInstance = newAbiCache()

func GetAbi(functionSignature string) (*abi.ABI, string, error) {
res, err := AbiCacheInstance.getAbi(functionSignature)
if err != nil {
return nil, "", err
}
return res.Abi, res.FunctionName, nil
}

func SetAbi(functionSignature string, abi *abi.ABI, functionName string) {
AbiCacheInstance.setAbi(functionSignature, &AbiWithFunctionName{Abi: abi, FunctionName: functionName})
}

func (c *AbiCache) getAbi(functionSignature string) (*AbiWithFunctionName, error) {
c.mu.RLock()
abi, ok := c.AbiMap[functionSignature]
c.mu.RUnlock()
if ok {
return abi, nil
}
return nil, errorsentinel.ErrChainCachedAbiNotFound
}

func (c *AbiCache) setAbi(functionSignature string, abiWithFunctionName *AbiWithFunctionName) {
c.mu.Lock()
c.AbiMap[functionSignature] = abiWithFunctionName
c.mu.Unlock()
}
60 changes: 39 additions & 21 deletions node/pkg/chain/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,21 @@ func MakeDirectTx(ctx context.Context, client ClientInterface, contractAddressHe
return nil, errorSentinel.ErrChainEmptyChainIdParam
}

functionName, inputs, outputs, err := ParseMethodSignature(functionString)
abi, functionName, err := GetAbi(functionString)
if err != nil {
return nil, err
}
var inputs, outputs string
functionName, inputs, outputs, err = ParseMethodSignature(functionString)
if err != nil {
return nil, err
}

abi, err := GenerateCallABI(functionName, inputs, outputs)
if err != nil {
log.Error().Err(err).Msg("failed to generate abi")
return nil, err
abi, err = GenerateCallABI(functionName, inputs, outputs)
if err != nil {
log.Error().Err(err).Msg("failed to generate abi")
return nil, err
}

SetAbi(functionString, abi, functionName)
}

packed, err := abi.Pack(functionName, args...)
Expand Down Expand Up @@ -244,16 +250,21 @@ func MakeFeeDelegatedTx(ctx context.Context, client ClientInterface, contractAdd
return nil, errorSentinel.ErrChainEmptyChainIdParam
}

functionName, inputs, outputs, err := ParseMethodSignature(functionString)
abi, functionName, err := GetAbi(functionString)
if err != nil {
log.Error().Err(err).Msg("failed to parse method signature")
return nil, err
}
var inputs, outputs string
functionName, inputs, outputs, err = ParseMethodSignature(functionString)
if err != nil {
return nil, err
}

abi, err := GenerateCallABI(functionName, inputs, outputs)
if err != nil {
log.Error().Err(err).Msg("failed to generate abi")
return nil, err
abi, err = GenerateCallABI(functionName, inputs, outputs)
if err != nil {
log.Error().Err(err).Msg("failed to generate abi")
return nil, err
}

SetAbi(functionString, abi, functionName)
}

packed, err := abi.Pack(functionName, args...)
Expand Down Expand Up @@ -420,14 +431,21 @@ func ReadContract(ctx context.Context, client ClientInterface, functionString st
return nil, errorSentinel.ErrChainEmptyFuncStringParam
}

functionName, inputs, outputs, err := ParseMethodSignature(functionString)
abi, functionName, err := GetAbi(functionString)
if err != nil {
return nil, err
}
var inputs, outputs string
functionName, inputs, outputs, err = ParseMethodSignature(functionString)
if err != nil {
return nil, err
}

abi, err := GenerateViewABI(functionName, inputs, outputs)
if err != nil {
return nil, err
abi, err = GenerateViewABI(functionName, inputs, outputs)
if err != nil {
log.Error().Err(err).Msg("failed to generate abi")
return nil, err
}

SetAbi(functionString, abi, functionName)
}

contractAddressHex := common.HexToAddress(contractAddress)
Expand Down
1 change: 1 addition & 0 deletions node/pkg/error/sentinel.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ var (
ErrChainWebsocketUrlNotProvided = &CustomError{Service: Others, Code: InvalidInputError, Message: "websocket url not provided"}
ErrChainSubmissionProxyContractNotFound = &CustomError{Service: Others, Code: InvalidInputError, Message: "submission proxy contract not found"}
ErrChainFailedToParseContractResult = &CustomError{Service: Others, Code: InvalidInputError, Message: "failed to parse contract result"}
ErrChainCachedAbiNotFound = &CustomError{Service: Others, Code: InvalidInputError, Message: "cached abi not found"}

ErrDbDatabaseUrlNotFound = &CustomError{Service: Others, Code: InternalError, Message: "DATABASE_URL not found"}
ErrDbEmptyTableNameParam = &CustomError{Service: Others, Code: InvalidInputError, Message: "empty table name"}
Expand Down

0 comments on commit 23e8d53

Please sign in to comment.