Skip to content

Commit

Permalink
Merge pull request #118 from SamMayWork/use-truncate
Browse files Browse the repository at this point in the history
feature: Support for Hedera EVM block identifiers
  • Loading branch information
EnriqueL8 authored May 20, 2024
2 parents 67fdd49 + bf4fe5c commit 684d91e
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 22 deletions.
38 changes: 19 additions & 19 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Run evmconnect",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/evmconnect/main.go",
"args": [
"-f",
"${workspaceFolder}/evmconnect_config.yml"
],
"env": {
"FIREFLY_PERSISTENCE_LEVELDB_PATH": "${workspaceFolder}/.leveldb"
}
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Run evmconnect",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/evmconnect/main.go",
"args": [
"-f",
"${workspaceFolder}/evmconnect_config.yml"
],
"env": {
"FIREFLY_PERSISTENCE_LEVELDB_PATH": "${workspaceFolder}/.leveldb"
}
]
}
]
}
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ For EVM connector to function properly, you should check the blockchain node sup
- `eth_getBalance`
- `eth_gasPrice`[^1]




### Transaction submission
- `eth_estimateGas`
- `eth_sendTransaction`
Expand Down
1 change: 1 addition & 0 deletions config.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
|expectContinueTimeout|See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)|[`time.Duration`](https://pkg.go.dev/time#Duration)|`1s`
|gasEstimationFactor|The factor to apply to the gas estimation to determine the gas limit|float|`1.5`
|headers|Adds custom headers to HTTP requests|`map[string]string`|`<nil>`
|hederaCompatibilityMode|Compatibility mode for Hedera, allowing non-standard block header hashes to be processed|`boolean`|`false`
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConcurrentRequests|Maximum of concurrent requests to be submitted to the blockchain|`int`|`50`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
Expand Down
18 changes: 18 additions & 0 deletions internal/ethereum/blocklistener.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type blockListener struct {
blockPollingInterval time.Duration
unstableHeadLength int
canonicalChain *list.List
hederaCompatibilityMode bool
}

type minimalBlockInfo struct {
Expand All @@ -67,6 +68,7 @@ func newBlockListener(ctx context.Context, c *ethConnector, conf config.Section)
blockPollingInterval: conf.GetDuration(BlockPollingInterval),
canonicalChain: list.New(),
unstableHeadLength: int(c.checkpointBlockGap),
hederaCompatibilityMode: conf.GetBool(HederaCompatibilityMode),
}
return bl
}
Expand Down Expand Up @@ -140,6 +142,22 @@ func (bl *blockListener) listenLoop() {
update := &ffcapi.BlockHashEvent{GapPotential: gapPotential}
var notifyPos *list.Element
for _, h := range blockHashes {
if len(h) != 32 {
if !bl.hederaCompatibilityMode {
log.L(bl.ctx).Errorf("Attempted to index block header with non-standard length: %d", len(h))
failCount++
continue
}

if len(h) < 32 {
log.L(bl.ctx).Errorf("Cannot index block header hash of length: %d", len(h))
failCount++
continue
}

h = h[0:32]
}

// Do a lookup of the block (which will then go into our cache).
bi, err := bl.c.getBlockInfoByHash(bl.ctx, h.String())
switch {
Expand Down
75 changes: 75 additions & 0 deletions internal/ethereum/blocklistener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,81 @@ func TestBlockListenerBlockHashFailed(t *testing.T) {

}

func TestBlockListenerProcessNonStandardHashRejectedWhenNotInHederaCompatibilityMode(t *testing.T) {

_, c, mRPC, done := newTestConnector(t)
bl := c.blockListener
bl.blockPollingInterval = 1 * time.Microsecond
bl.hederaCompatibilityMode = false

block1003Hash := ethtypes.MustNewHexBytes0xPrefix("0xef177df3b87beed681b1557e8ba7c3ecbd7e4db83d87b66c1e86aa484937ab93f1fae0eb6d4b24ca30aee13f29c83cc9")

mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_blockNumber").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*ethtypes.HexInteger)
*hbh = *ethtypes.NewHexInteger64(1000)
}).Once()
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_newBlockFilter").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*string)
*hbh = "filter_id1"
})
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_getFilterChanges", "filter_id1").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*[]ethtypes.HexBytes0xPrefix)
*hbh = []ethtypes.HexBytes0xPrefix{
block1003Hash,
}
}).Once()
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_getFilterChanges", mock.Anything).Return(nil).Run(func(args mock.Arguments) {
go done() // Close after we've processed the log
})

bl.checkStartedLocked()

c.WaitClosed()

mRPC.AssertExpectations(t)

}

func TestBlockListenerProcessNonStandardHashAcceptedWhenInHederaCompatbilityMode(t *testing.T) {

_, c, mRPC, done := newTestConnector(t)
bl := c.blockListener
bl.blockPollingInterval = 1 * time.Microsecond
bl.hederaCompatibilityMode = true

block1003Hash := ethtypes.MustNewHexBytes0xPrefix("0xef177df3b87beed681b1557e8ba7c3ecbd7e4db83d87b66c1e86aa484937ab93f1fae0eb6d4b24ca30aee13f29c83cc9")
truncatedBlock1003Hash := ethtypes.MustNewHexBytes0xPrefix("0xef177df3b87beed681b1557e8ba7c3ecbd7e4db83d87b66c1e86aa484937ab93")

mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_blockNumber").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*ethtypes.HexInteger)
*hbh = *ethtypes.NewHexInteger64(1000)
}).Once()
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_newBlockFilter").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*string)
*hbh = "filter_id1"
})
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_getFilterChanges", "filter_id1").Return(nil).Run(func(args mock.Arguments) {
hbh := args[1].(*[]ethtypes.HexBytes0xPrefix)
*hbh = []ethtypes.HexBytes0xPrefix{
block1003Hash,
}
}).Once()
mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_getFilterChanges", mock.Anything).Return(nil).Run(func(args mock.Arguments) {
go done() // Close after we've processed the log
})

mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_getBlockByHash", mock.MatchedBy(func(bh string) bool {
return bh == truncatedBlock1003Hash.String()
}), false).Return(&rpcbackend.RPCError{Message: "pop"})

bl.checkStartedLocked()

c.WaitClosed()

mRPC.AssertExpectations(t)

}

func TestBlockListenerReestablishBlockFilter(t *testing.T) {

_, c, mRPC, done := newTestConnector(t)
Expand Down
2 changes: 2 additions & 0 deletions internal/ethereum/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
RetryFactor = "retry.factor"
MaxConcurrentRequests = "maxConcurrentRequests"
TxCacheSize = "txCacheSize"
HederaCompatibilityMode = "hederaCompatibilityMode"
TraceTXForRevertReason = "traceTXForRevertReason"
)

Expand Down Expand Up @@ -71,5 +72,6 @@ func InitConfig(conf config.Section) {
conf.AddKnownKey(RetryMaxDelay, DefaultRetryMaxDelay)
conf.AddKnownKey(MaxConcurrentRequests, 50)
conf.AddKnownKey(TxCacheSize, 250)
conf.AddKnownKey(HederaCompatibilityMode, false)
conf.AddKnownKey(TraceTXForRevertReason, false)
}
1 change: 1 addition & 0 deletions internal/msgs/en_config_descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ var (
ConfigEventsFilterPollingInterval = ffc("config.connector.events.filterPollingInterval", "The interval between polling calls to a filter, when checking for newly arrived events", i18n.TimeDurationType)
ConfigTxCacheSize = ffc("config.connector.txCacheSize", "Maximum of transactions to hold in the transaction info cache", i18n.IntType)
ConfigMaxConcurrentRequests = ffc("config.connector.maxConcurrentRequests", "Maximum of concurrent requests to be submitted to the blockchain", i18n.IntType)
ConfigHederaCompatibilityMode = ffc("config.connector.hederaCompatibilityMode", "Compatibility mode for Hedera, allowing non-standard block header hashes to be processed", i18n.BooleanType)
ConfigTraceTXForRevertReason = ffc("config.connector.traceTXForRevertReason", "Enable the use of transaction trace functions (e.g. debug_traceTransaction) to obtain transaction revert reasons. This can place a high load on the EVM client.", i18n.BooleanType)
)

0 comments on commit 684d91e

Please sign in to comment.