@@ -28,20 +28,30 @@ import (
2828// (for block ingestion) and core.Store (via the embedded *storage.Store, for API queries).
2929type Chain struct {
3030 * storage.Store
31- db * sql.DB
32- ts * trie.Store
33- prevHash common.Hash // Ethereum hash of last committed block; seeded from DB on startup
31+ db * sql.DB
32+ ts * trie.Store
33+ prevHash common.Hash // Ethereum hash of last committed block; seeded from DB on startup
34+ namespace string // Fabric namespace to filter; empty means accept all
3435}
3536
3637// NewChain opens the SQLite database and trie store, seeds state from the latest committed
3738// block, and returns a ready Chain. dbConnStr uses the modernc SQLite DSN format;
3839// triePath is the directory for the PebbleDB trie (empty string = in-memory).
40+ // namespace filters delivered blocks to only those containing transactions for that Fabric
41+ // namespace; pass an empty string to accept all namespaces.
3942// The caller must register the SQLite driver (e.g. _ "modernc.org/sqlite") before calling.
40- func NewChain (dbConnStr , triePath string , withTrie bool ) (* Chain , error ) {
43+ func NewChain (dbConnStr , triePath , namespace string , withTrie bool ) (* Chain , error ) {
4144 db , err := sqlite .Open (dbConnStr )
4245 if err != nil {
4346 return nil , fmt .Errorf ("open db: %w" , err )
4447 }
48+ // Store SQLite temp objects in memory. The release image is built from
49+ // scratch and has no /tmp, so file-based temp storage would fail with
50+ // SQLITE_IOERR_GETTEMPPATH (6410) during WAL operations like DELETE.
51+ if _ , err := db .Exec ("PRAGMA temp_store=MEMORY" ); err != nil {
52+ db .Close ()
53+ return nil , fmt .Errorf ("set temp_store pragma: %w" , err )
54+ }
4555
4656 blockStore := storage .NewStore (db )
4757 if err := blockStore .Init (); err != nil {
@@ -66,13 +76,31 @@ func NewChain(dbConnStr, triePath string, withTrie bool) (*Chain, error) {
6676 }
6777 }
6878
69- return & Chain {Store : blockStore , db : db , ts : ts , prevHash : prevHash }, nil
79+ return & Chain {Store : blockStore , db : db , ts : ts , prevHash : prevHash , namespace : namespace }, nil
80+ }
81+
82+ // convertToDomain applies namespace filtering then delegates to ConvertToDomain.
83+ func (c * Chain ) convertToDomain (b blocks.Block ) domain.Block {
84+ if c .namespace == "" {
85+ return ConvertToDomain (b )
86+ }
87+ filtered := b
88+ filtered .Transactions = filtered .Transactions [:0 :0 ]
89+ for _ , tx := range b .Transactions {
90+ for _ , nrws := range tx .NsRWS {
91+ if nrws .Namespace == c .namespace {
92+ filtered .Transactions = append (filtered .Transactions , tx )
93+ break
94+ }
95+ }
96+ }
97+ return ConvertToDomain (filtered )
7098}
7199
72100// Handle implements blocks.BlockHandler. It commits the block's write sets to the trie,
73101// then persists the block and its transactions to the database.
74102func (c * Chain ) Handle (ctx context.Context , b blocks.Block ) error {
75- ebl := ConvertToDomain (b )
103+ ebl := c . convertToDomain (b )
76104
77105 ebl .ParentHash = c .prevHash .Bytes ()
78106 if c .ts != nil {
@@ -90,6 +118,12 @@ func (c *Chain) Handle(ctx context.Context, b blocks.Block) error {
90118 return err
91119 }
92120
121+ if c .Store .BlockRetention > 0 && ebl .BlockNumber % 1000 == 0 {
122+ if err := c .Store .TruncateBlocks (ctx , c .Store .BlockRetention ); err != nil {
123+ logger .Warnf ("block DB truncation failed at block %d: %v" , ebl .BlockNumber , err )
124+ }
125+ }
126+
93127 return nil
94128}
95129
@@ -115,8 +149,6 @@ func ConvertToDomain(b blocks.Block) domain.Block {
115149
116150 logIndex := int64 (0 ) // logIndex is the index of the log in the block
117151 for _ , tx := range b .Transactions {
118- // TODO: filter on namespace?
119-
120152 // retrieve the Ethereum transaction from the chaincode invocation
121153 if len (tx .InputArgs ) < 2 || ! bytes .Equal (tx .InputArgs [0 ], []byte {byte (fc .ProposalTypeEVMTx )}) {
122154 // skip non-eth tx
@@ -129,7 +161,8 @@ func ConvertToDomain(b blocks.Block) domain.Block {
129161
130162 etx , err := convertTransaction (tx .InputArgs [1 ], b .Hash , b .Number , tx .Number , tx .ID , status , tx .Status , tx .Events , & logIndex )
131163 if err != nil {
132- panic (err ) // we surface this for now instead of swallowing it
164+ logger .Warnf ("skipping malformed tx %s in block %d: %v" , tx .ID , b .Number , err )
165+ continue
133166 }
134167
135168 ebl .Transactions = append (ebl .Transactions , etx )
0 commit comments