@@ -538,7 +538,35 @@ func (h *blockHeaderStore) WriteHeaders(hdrs ...BlockHeader) error {
538538 headerLocs [i ] = header .toIndexEntry ()
539539 }
540540
541- return h .addHeaders (headerLocs )
541+ // Attempt to add the headers to the database. If this fails, we'll need
542+ // to roll back any changes to the header file to maintain consistency.
543+ // The rollback process bases on the number of header serialized. If
544+ // both the initial operation and the rollback fail, we return
545+ // a detailed error explaining both failures to aid in debugging.
546+ if err := h .addHeaders (headerLocs ); err != nil {
547+ // Since the probability of failing to write to the database is
548+ // very low, it is mostly worth the cost of file sync operation
549+ // to make sure truncate headers does it correctly.
550+ if err := h .file .Sync (); err != nil {
551+ return fmt .Errorf ("failed to sync block headers " +
552+ "file: %v" , err )
553+ }
554+
555+ headersToRollback := len (hdrs )
556+ truncateErr := h .truncateHeaders (
557+ uint32 (headersToRollback ), h .indexType ,
558+ )
559+ if truncateErr != nil {
560+ return fmt .Errorf ("failed to rollback block headers " +
561+ "from binary file to previous valid state: " +
562+ "%v, error writing to database: %v, headers " +
563+ "to rollback: %d" , truncateErr , err ,
564+ headersToRollback )
565+ }
566+ return fmt .Errorf ("failed to add block headers to db: %v" , err )
567+ }
568+
569+ return nil
542570}
543571
544572// blockLocatorFromHash takes a given block hash and then creates a block
@@ -1035,7 +1063,35 @@ func (f *filterHeaderStore) WriteHeaders(hdrs ...FilterHeader) error {
10351063 // As the block headers should already be written, we only need to
10361064 // update the tip pointer for this particular header type.
10371065 newTip := hdrs [len (hdrs )- 1 ].toIndexEntry ().hash
1038- return f .truncateIndices (& newTip , []* chainhash.Hash {}, false )
1066+
1067+ // Attempt to add the headers to the database. If this fails, we'll need
1068+ // to roll back any changes to the header file to maintain consistency.
1069+ // The rollback process bases on the number of header serialized. If
1070+ // both the initial operation and the rollback fail, we return
1071+ // a detailed error explaining both failures to aid in debugging.
1072+ if err := f .truncateIndices (& newTip , nil , false ); err != nil {
1073+ // Since the probability of failing to write to the database is
1074+ // very low, it is mostly worth the cost of file sync operation
1075+ // to make sure truncate headers does it correctly.
1076+ if err := f .file .Sync (); err != nil {
1077+ return fmt .Errorf ("failed to sync filter headers " +
1078+ "file: %v" , err )
1079+ }
1080+
1081+ headersToRollback := len (hdrs )
1082+ truncateErr := f .truncateHeaders (
1083+ uint32 (headersToRollback ), f .indexType ,
1084+ )
1085+ if truncateErr != nil {
1086+ return fmt .Errorf ("failed to rollback filter headers " +
1087+ "binary file to previous valid state: %v, " +
1088+ "error writing to database: %v" , truncateErr ,
1089+ err )
1090+ }
1091+ return fmt .Errorf ("failed to add filter headers to db: %v" , err )
1092+ }
1093+
1094+ return nil
10391095}
10401096
10411097// ChainTip returns the latest filter header and height known to the
0 commit comments