Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
0d752667
Commit
0d752667
authored
Oct 26, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add error handling in dylib
parent
bc5e060e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
106 additions
and
53 deletions
+106
-53
lib.rs
op-service/rethdb-reader/src/lib.rs
+89
-47
receipts.go
op-service/sources/receipts.go
+2
-2
reth_db.go
op-service/sources/reth_db.go
+15
-4
No files found.
op-service/rethdb-reader/src/lib.rs
View file @
0d752667
...
@@ -20,6 +20,38 @@ pub struct ByteArrays {
...
@@ -20,6 +20,38 @@ pub struct ByteArrays {
len
:
usize
,
len
:
usize
,
}
}
#[repr(C)]
pub
struct
ReceiptsResult
{
receipts
:
ByteArrays
,
error
:
bool
,
}
// Implement a default for ByteArrays to be used in error cases
impl
Default
for
ByteArrays
{
fn
default
()
->
Self
{
ByteArrays
{
data
:
std
::
ptr
::
null_mut
(),
len
:
0
,
}
}
}
impl
ReceiptsResult
{
pub
fn
success
(
receipts
:
ByteArrays
)
->
Self
{
Self
{
receipts
,
error
:
false
,
}
}
pub
fn
fail
()
->
Self
{
Self
{
receipts
:
ByteArrays
::
default
(),
error
:
true
,
}
}
}
/// Read the receipts for a blockhash from the RETH database directly.
/// Read the receipts for a blockhash from the RETH database directly.
///
///
/// WARNING: Will panic on error.
/// WARNING: Will panic on error.
...
@@ -29,72 +61,82 @@ pub extern "C" fn read_receipts(
...
@@ -29,72 +61,82 @@ pub extern "C" fn read_receipts(
block_hash
:
*
const
u8
,
block_hash
:
*
const
u8
,
block_hash_len
:
usize
,
block_hash_len
:
usize
,
db_path
:
*
const
c_char
,
db_path
:
*
const
c_char
,
)
->
ByteArrays
{
)
->
ReceiptsResult
{
// Convert the raw pointer and length back to a Rust slice
// Convert the raw pointer and length back to a Rust slice
let
block_hash
:
[
u8
;
32
]
=
unsafe
{
std
::
slice
::
from_raw_parts
(
block_hash
,
block_hash_len
)
}
let
Ok
(
block_hash
):
Result
<
[
u8
;
32
],
_
>
=
.try_into
()
unsafe
{
std
::
slice
::
from_raw_parts
(
block_hash
,
block_hash_len
)
}
.try_into
()
.expect
(
"Block hash must be 32 bytes long"
);
else
{
return
ReceiptsResult
::
fail
();
};
// Convert the *const c_char to a Rust &str
// Convert the *const c_char to a Rust &str
let
db_path_str
=
unsafe
{
let
Ok
(
db_path_str
)
=
unsafe
{
assert
!
(
!
db_path
.is_null
(),
"Null pointer for database path"
);
assert
!
(
!
db_path
.is_null
(),
"Null pointer for database path"
);
std
::
ffi
::
CStr
::
from_ptr
(
db_path
)
std
::
ffi
::
CStr
::
from_ptr
(
db_path
)
.to_str
()
}
.expect
(
"Invalid UTF-8 for database path"
)
.to_str
()
else
{
return
ReceiptsResult
::
fail
();
};
};
let
db
=
open_db_read_only
(
&
Path
::
new
(
db_path_str
),
None
)
.expect
(
"Could not open reth DB"
);
let
Ok
(
db
)
=
open_db_read_only
(
&
Path
::
new
(
db_path_str
),
None
)
else
{
return
ReceiptsResult
::
fail
();
};
let
spec
=
Arc
::
new
(
ChainSpecBuilder
::
mainnet
()
.build
());
let
spec
=
Arc
::
new
(
ChainSpecBuilder
::
mainnet
()
.build
());
let
factory
=
ProviderFactory
::
new
(
db
,
spec
.clone
());
let
factory
=
ProviderFactory
::
new
(
db
,
spec
.clone
());
// Create a read-only BlockChainProvider
// Create a read-only BlockChainProvider
let
provider
=
BlockchainProvider
::
new
(
factory
,
NoopBlockchainTree
::
default
())
let
Ok
(
provider
)
=
BlockchainProvider
::
new
(
factory
,
NoopBlockchainTree
::
default
())
else
{
.expect
(
"Failed to create blockchain provider."
);
return
ReceiptsResult
::
fail
();
let
receipts
=
provider
};
.receipts_by_block
(
BlockHashOrNumber
::
Hash
(
block_hash
.into
()))
.expect
(
"Could not fetch receipts for block"
)
let
Ok
(
receipts
)
=
provider
.receipts_by_block
(
BlockHashOrNumber
::
Hash
(
block_hash
.into
()))
.expect
(
"No receipts found for block"
);
else
{
return
ReceiptsResult
::
fail
();
// Serialize receipts to RLP for the FFI interface.
let
receipts_rlp
=
receipts
.into_iter
()
.map
(|
r
|
{
// todo - reduce alloc?
// RLP encode the receipt with a bloom filter.
let
mut
buf
=
Vec
::
default
();
r
.with_bloom
()
.encode
(
&
mut
buf
);
// Return a pointer to the `buf` and its length
let
res
=
ByteArray
{
data
:
buf
.as_mut_ptr
(),
len
:
buf
.len
(),
};
// Forget the `buf` so that its memory isn't freed by the
// borrow checker at the end of this scope
std
::
mem
::
forget
(
buf
);
res
})
.collect
::
<
Vec
<
_
>>
();
let
result
=
ByteArrays
{
data
:
receipts_rlp
.as_ptr
()
as
*
mut
ByteArray
,
len
:
receipts_rlp
.len
(),
};
};
// Forget the `receipts_rlp` arr so that its memory isn't freed by the
if
let
Some
(
receipts
)
=
receipts
{
// borrow checker at the end of this scope
let
receipts_rlp
=
receipts
std
::
mem
::
forget
(
receipts_rlp
);
// Prevent Rust from freeing the memory
.into_iter
()
.map
(|
r
|
{
// todo - reduce alloc?
// RLP encode the receipt with a bloom filter.
let
mut
buf
=
Vec
::
default
();
r
.with_bloom
()
.encode
(
&
mut
buf
);
result
// Return a pointer to the `buf` and its length
let
res
=
ByteArray
{
data
:
buf
.as_mut_ptr
(),
len
:
buf
.len
(),
};
// Forget the `buf` so that its memory isn't freed by the
// borrow checker at the end of this scope
std
::
mem
::
forget
(
buf
);
res
})
.collect
::
<
Vec
<
_
>>
();
let
result
=
ByteArrays
{
data
:
receipts_rlp
.as_ptr
()
as
*
mut
ByteArray
,
len
:
receipts_rlp
.len
(),
};
// Forget the `receipts_rlp` arr so that its memory isn't freed by the
// borrow checker at the end of this scope
std
::
mem
::
forget
(
receipts_rlp
);
// Prevent Rust from freeing the memory
ReceiptsResult
::
success
(
result
)
}
else
{
return
ReceiptsResult
::
fail
();
}
}
}
/// Free the [ByteArrays] data structure and its sub-components when they are no longer needed.
/// Free the [ByteArrays] data structure and its sub-components when they are no longer needed.
#[no_mangle]
#[no_mangle]
pub
extern
"C"
fn
free_byte_arrays
(
array
:
ByteArrays
)
{
pub
extern
"C"
fn
free_byte_arrays
(
array
s
:
ByteArrays
)
{
unsafe
{
unsafe
{
let
arrays
=
Vec
::
from_raw_parts
(
array
.data
,
array
.len
,
array
.len
);
let
arrays
=
Vec
::
from_raw_parts
(
array
s
.data
,
arrays
.len
,
arrays
.len
);
for
inner_array
in
arrays
{
for
inner_array
in
arrays
{
let
_
=
Vec
::
from_raw_parts
(
inner_array
.data
,
inner_array
.len
,
inner_array
.len
);
let
_
=
Vec
::
from_raw_parts
(
inner_array
.data
,
inner_array
.len
,
inner_array
.len
);
}
}
...
...
op-service/sources/receipts.go
View file @
0d752667
...
@@ -124,7 +124,7 @@ const (
...
@@ -124,7 +124,7 @@ const (
RPCKindBasic
RPCProviderKind
=
"basic"
// try only the standard most basic receipt fetching
RPCKindBasic
RPCProviderKind
=
"basic"
// try only the standard most basic receipt fetching
RPCKindAny
RPCProviderKind
=
"any"
// try any method available
RPCKindAny
RPCProviderKind
=
"any"
// try any method available
RPCKindStandard
RPCProviderKind
=
"standard"
// try standard methods, including newer optimized standard RPC methods
RPCKindStandard
RPCProviderKind
=
"standard"
// try standard methods, including newer optimized standard RPC methods
RPCKindRethDB
RPCProviderKind
=
"reth_db"
// read data directly from reth's
MDBX
database
RPCKindRethDB
RPCProviderKind
=
"reth_db"
// read data directly from reth's database
)
)
var
RPCProviderKinds
=
[]
RPCProviderKind
{
var
RPCProviderKinds
=
[]
RPCProviderKind
{
...
@@ -311,7 +311,7 @@ func AvailableReceiptsFetchingMethods(kind RPCProviderKind) ReceiptsFetchingMeth
...
@@ -311,7 +311,7 @@ func AvailableReceiptsFetchingMethods(kind RPCProviderKind) ReceiptsFetchingMeth
case
RPCKindBasic
:
case
RPCKindBasic
:
return
EthGetTransactionReceiptBatch
return
EthGetTransactionReceiptBatch
case
RPCKindAny
:
case
RPCKindAny
:
// if it's any kind of RPC provider, then try all methods (except for RethGetBlockReceipts
MDBX
)
// if it's any kind of RPC provider, then try all methods (except for RethGetBlockReceipts)
return
AlchemyGetTransactionReceipts
|
EthGetBlockReceipts
|
return
AlchemyGetTransactionReceipts
|
EthGetBlockReceipts
|
DebugGetRawReceipts
|
ErigonGetBlockReceiptsByBlockHash
|
DebugGetRawReceipts
|
ErigonGetBlockReceiptsByBlockHash
|
ParityGetBlockReceipts
|
EthGetTransactionReceiptBatch
ParityGetBlockReceipts
|
EthGetTransactionReceiptBatch
...
...
op-service/sources/reth_db.go
View file @
0d752667
...
@@ -11,6 +11,7 @@ import (
...
@@ -11,6 +11,7 @@ import (
#cgo LDFLAGS: -L../rethdb-reader/target/release -lrethdbreader
#cgo LDFLAGS: -L../rethdb-reader/target/release -lrethdbreader
#include <stdlib.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
typedef struct {
uint8_t* data;
uint8_t* data;
...
@@ -22,7 +23,13 @@ typedef struct {
...
@@ -22,7 +23,13 @@ typedef struct {
size_t len;
size_t len;
} ByteArrays;
} ByteArrays;
extern ByteArrays read_receipts(const uint8_t* block_hash, size_t block_hash_len, const char* db_path);
// Define ReceiptsResult with a bool for error
typedef struct {
ByteArrays receipts;
bool error;
} ReceiptsResult;
extern ReceiptsResult read_receipts(const uint8_t* block_hash, size_t block_hash_len, const char* db_path);
extern void free_byte_arrays(ByteArrays arrays);
extern void free_byte_arrays(ByteArrays arrays);
*/
*/
import
"C"
import
"C"
...
@@ -46,9 +53,13 @@ func FetchRethReceipts(dbPath string, blockHash *common.Hash) (types.Receipts, e
...
@@ -46,9 +53,13 @@ func FetchRethReceipts(dbPath string, blockHash *common.Hash) (types.Receipts, e
// Call the C function to fetch the receipts from the Reth Database
// Call the C function to fetch the receipts from the Reth Database
byteArrayStruct
:=
C
.
read_receipts
((
*
C
.
uint8_t
)(
cBlockHash
),
C
.
size_t
(
len
(
blockHash
)),
cDbPath
)
byteArrayStruct
:=
C
.
read_receipts
((
*
C
.
uint8_t
)(
cBlockHash
),
C
.
size_t
(
len
(
blockHash
)),
cDbPath
)
if
byteArrayStruct
.
error
{
return
nil
,
fmt
.
Errorf
(
"Error fetching receipts from Reth Database."
)
}
// Convert the returned receipt RLP byte arrays to decoded Receipts.
// Convert the returned receipt RLP byte arrays to decoded Receipts.
data
:=
make
(
types
.
Receipts
,
byteArrayStruct
.
len
)
data
:=
make
(
types
.
Receipts
,
byteArrayStruct
.
receipts
.
len
)
byteArraySlice
:=
(
*
[
1
<<
30
]
C
.
ByteArray
)(
unsafe
.
Pointer
(
byteArrayStruct
.
data
))[
:
byteArrayStruct
.
len
:
byteArrayStruct
.
len
]
byteArraySlice
:=
(
*
[
1
<<
30
]
C
.
ByteArray
)(
unsafe
.
Pointer
(
byteArrayStruct
.
receipts
.
data
))[
:
byteArrayStruct
.
receipts
.
len
:
byteArrayStruct
.
receipts
.
len
]
for
i
,
byteArray
:=
range
byteArraySlice
{
for
i
,
byteArray
:=
range
byteArraySlice
{
receipt
:=
types
.
Receipt
{}
receipt
:=
types
.
Receipt
{}
receipt
.
UnmarshalBinary
(
C
.
GoBytes
(
unsafe
.
Pointer
(
byteArray
.
data
),
C
.
int
(
byteArray
.
len
)))
receipt
.
UnmarshalBinary
(
C
.
GoBytes
(
unsafe
.
Pointer
(
byteArray
.
data
),
C
.
int
(
byteArray
.
len
)))
...
@@ -56,7 +67,7 @@ func FetchRethReceipts(dbPath string, blockHash *common.Hash) (types.Receipts, e
...
@@ -56,7 +67,7 @@ func FetchRethReceipts(dbPath string, blockHash *common.Hash) (types.Receipts, e
}
}
// Free the memory allocated by the C code
// Free the memory allocated by the C code
C
.
free_byte_arrays
(
byteArrayStruct
)
C
.
free_byte_arrays
(
byteArrayStruct
.
receipts
)
return
data
,
nil
return
data
,
nil
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment