mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-16 18:37:51 +01:00
Blockchain: blockchain.IterateDeleteRecord decode all records at once, fixing multiple issues with file tags that could result in corrupted or orphaned records. Fix #66, fix #37, fix #38
This commit is contained in:
@@ -171,7 +171,7 @@ func (blockchain *Blockchain) Iterate(callback func(block *Block) int) (status i
|
||||
// IterateDeleteRecord iterates over the blockchain to find records to delete. Status is StatusX.
|
||||
// deleteAction is 0 = no action on record, 1 = delete record, 2 = replace record, 3 = error blockchain corrupt
|
||||
// If the callback returns true, the record will be deleted. The blockchain will be automatically refactored and height and version updated.
|
||||
func (blockchain *Blockchain) IterateDeleteRecord(callback func(record *BlockRecordRaw) (deleteAction int)) (newHeight, newVersion uint64, status int) {
|
||||
func (blockchain *Blockchain) IterateDeleteRecord(callbackFile func(file *BlockRecordFile) (deleteAction int), callbackOther func(record *BlockRecordRaw) (deleteAction int)) (newHeight, newVersion uint64, status int) {
|
||||
blockchain.Lock()
|
||||
defer blockchain.Unlock()
|
||||
|
||||
@@ -194,32 +194,83 @@ func (blockchain *Blockchain) IterateDeleteRecord(callback func(record *BlockRec
|
||||
return 0, 0, StatusCorruptBlock
|
||||
}
|
||||
|
||||
// loop through all records in this block
|
||||
refactorBlock := false
|
||||
|
||||
// Decode all file records at once. This is needed due to potential referenced tags.
|
||||
// If a file is deleted or referenced tag data changed, it would corrupt the blockchain if the other records were not updated.
|
||||
filesD, err := decodeBlockRecordFiles(block.RecordsRaw, block.NodeID)
|
||||
if err != nil {
|
||||
return 0, 0, StatusCorruptBlock
|
||||
}
|
||||
|
||||
// loop through all file records in this block
|
||||
var newFileRecords []BlockRecordFile
|
||||
|
||||
if callbackFile == nil {
|
||||
newFileRecords = filesD
|
||||
} else {
|
||||
for n := range filesD {
|
||||
switch callbackFile(&filesD[n]) {
|
||||
case 0: // no action on record
|
||||
newFileRecords = append(newFileRecords, filesD[n])
|
||||
|
||||
case 1: // delete record
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
|
||||
case 2: // replace record
|
||||
newFileRecords = append(newFileRecords, filesD[n])
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
|
||||
case 3: // error blockchain corrupt
|
||||
return 0, 0, StatusCorruptBlockRecord
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop through all other (non-file) records in this block
|
||||
var newRecordsRaw []BlockRecordRaw
|
||||
|
||||
for n := range block.RecordsRaw {
|
||||
switch callback(&block.RecordsRaw[n]) {
|
||||
case 0: // no action on record
|
||||
// File and Tag records were already handled in above loop.
|
||||
if block.RecordsRaw[n].Type == RecordTypeFile || block.RecordsRaw[n].Type == RecordTypeTagData {
|
||||
continue
|
||||
}
|
||||
|
||||
if callbackOther == nil {
|
||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
||||
} else {
|
||||
switch callbackOther(&block.RecordsRaw[n]) {
|
||||
case 0: // no action on record
|
||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
||||
|
||||
case 1: // delete record
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
case 1: // delete record
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
|
||||
case 2: // replace record
|
||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
case 2: // replace record
|
||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
||||
refactorBlock = true
|
||||
refactorBlockchain = true
|
||||
|
||||
case 3: // error blockchain corrupt
|
||||
return 0, 0, StatusCorruptBlockRecord
|
||||
case 3: // error blockchain corrupt
|
||||
return 0, 0, StatusCorruptBlockRecord
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If refactor, re-calculate the block. All later blocks need to be re-encoded due to change of previous block hash. The version number needs to change.
|
||||
// Note: Deleting records may leave referenced records orphaned, such as RecordTypeTagData for deleted file records.
|
||||
if refactorBlock {
|
||||
// re-encode the block
|
||||
filesRecords, err := encodeBlockRecordFiles(newFileRecords)
|
||||
if err != nil {
|
||||
return 0, 0, StatusCorruptBlock
|
||||
}
|
||||
|
||||
newRecordsRaw = append(newRecordsRaw, filesRecords...)
|
||||
|
||||
if len(newRecordsRaw) > 0 {
|
||||
blockchainNew = append(blockchainNew, Block{OwnerPublicKey: blockchain.publicKey, RecordsRaw: newRecordsRaw, BlockchainVersion: refactorVersion, Number: uint64(len(blockchainNew))})
|
||||
}
|
||||
|
||||
@@ -62,26 +62,17 @@ func (blockchain *Blockchain) FileExists(hash []byte) (files []BlockRecordFile,
|
||||
}
|
||||
|
||||
// DeleteFiles deletes files from the blockchain. Status is StatusX.
|
||||
func (blockchain *Blockchain) DeleteFiles(IDs []uuid.UUID) (newHeight, newVersion uint64, deletedFiles []BlockRecordFile, status int) {
|
||||
newHeight, newVersion, status = blockchain.IterateDeleteRecord(func(record *BlockRecordRaw) (deleteAction int) {
|
||||
if record.Type != RecordTypeFile {
|
||||
return 0 // no action on record
|
||||
}
|
||||
|
||||
filesDecoded, err := decodeBlockRecordFiles([]BlockRecordRaw{*record}, nil)
|
||||
if err != nil || len(filesDecoded) != 1 {
|
||||
return 3 // error blockchain corrupt
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) DeleteFiles(IDs []uuid.UUID) (newHeight, newVersion uint64, deletedFiles []*BlockRecordFile, status int) {
|
||||
newHeight, newVersion, status = blockchain.IterateDeleteRecord(func(file *BlockRecordFile) (deleteAction int) {
|
||||
for _, id := range IDs {
|
||||
if id == filesDecoded[0].ID { // found a file ID to delete?
|
||||
deletedFiles = append(deletedFiles, filesDecoded[0])
|
||||
if file.ID == id { // found a file ID to delete?
|
||||
deletedFiles = append(deletedFiles, file)
|
||||
return 1 // delete record
|
||||
}
|
||||
}
|
||||
|
||||
return 0 // no action on record
|
||||
})
|
||||
}, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (blockchain *Blockchain) ProfileWrite(fields []BlockRecordProfile) (newHeig
|
||||
|
||||
// ProfileDelete deletes fields and blobs from the blockchain. Status is StatusX.
|
||||
func (blockchain *Blockchain) ProfileDelete(fields []uint16) (newHeight, newVersion uint64, status int) {
|
||||
return blockchain.IterateDeleteRecord(func(record *BlockRecordRaw) (deleteAction int) {
|
||||
return blockchain.IterateDeleteRecord(nil, func(record *BlockRecordRaw) (deleteAction int) {
|
||||
if record.Type != RecordTypeProfile {
|
||||
return 0 // no action
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user