mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47: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.
|
// 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
|
// 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.
|
// 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()
|
blockchain.Lock()
|
||||||
defer blockchain.Unlock()
|
defer blockchain.Unlock()
|
||||||
|
|
||||||
@@ -194,32 +194,83 @@ func (blockchain *Blockchain) IterateDeleteRecord(callback func(record *BlockRec
|
|||||||
return 0, 0, StatusCorruptBlock
|
return 0, 0, StatusCorruptBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through all records in this block
|
|
||||||
refactorBlock := false
|
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
|
var newRecordsRaw []BlockRecordRaw
|
||||||
|
|
||||||
for n := range block.RecordsRaw {
|
for n := range block.RecordsRaw {
|
||||||
switch callback(&block.RecordsRaw[n]) {
|
// File and Tag records were already handled in above loop.
|
||||||
case 0: // no action on record
|
if block.RecordsRaw[n].Type == RecordTypeFile || block.RecordsRaw[n].Type == RecordTypeTagData {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if callbackOther == nil {
|
||||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
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
|
case 1: // delete record
|
||||||
refactorBlock = true
|
refactorBlock = true
|
||||||
refactorBlockchain = true
|
refactorBlockchain = true
|
||||||
|
|
||||||
case 2: // replace record
|
case 2: // replace record
|
||||||
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
newRecordsRaw = append(newRecordsRaw, block.RecordsRaw[n])
|
||||||
refactorBlock = true
|
refactorBlock = true
|
||||||
refactorBlockchain = true
|
refactorBlockchain = true
|
||||||
|
|
||||||
case 3: // error blockchain corrupt
|
case 3: // error blockchain corrupt
|
||||||
return 0, 0, StatusCorruptBlockRecord
|
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.
|
// 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.
|
// Note: Deleting records may leave referenced records orphaned, such as RecordTypeTagData for deleted file records.
|
||||||
if refactorBlock {
|
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 {
|
if len(newRecordsRaw) > 0 {
|
||||||
blockchainNew = append(blockchainNew, Block{OwnerPublicKey: blockchain.publicKey, RecordsRaw: newRecordsRaw, BlockchainVersion: refactorVersion, Number: uint64(len(blockchainNew))})
|
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.
|
// DeleteFiles deletes files from the blockchain. Status is StatusX.
|
||||||
func (blockchain *Blockchain) DeleteFiles(IDs []uuid.UUID) (newHeight, newVersion uint64, deletedFiles []BlockRecordFile, status int) {
|
func (blockchain *Blockchain) DeleteFiles(IDs []uuid.UUID) (newHeight, newVersion uint64, deletedFiles []*BlockRecordFile, status int) {
|
||||||
newHeight, newVersion, status = blockchain.IterateDeleteRecord(func(record *BlockRecordRaw) (deleteAction int) {
|
newHeight, newVersion, status = blockchain.IterateDeleteRecord(func(file *BlockRecordFile) (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
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, id := range IDs {
|
for _, id := range IDs {
|
||||||
if id == filesDecoded[0].ID { // found a file ID to delete?
|
if file.ID == id { // found a file ID to delete?
|
||||||
deletedFiles = append(deletedFiles, filesDecoded[0])
|
deletedFiles = append(deletedFiles, file)
|
||||||
return 1 // delete record
|
return 1 // delete record
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0 // no action on record
|
return 0 // no action on record
|
||||||
})
|
}, nil)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (blockchain *Blockchain) ProfileWrite(fields []BlockRecordProfile) (newHeig
|
|||||||
|
|
||||||
// ProfileDelete deletes fields and blobs from the blockchain. Status is StatusX.
|
// ProfileDelete deletes fields and blobs from the blockchain. Status is StatusX.
|
||||||
func (blockchain *Blockchain) ProfileDelete(fields []uint16) (newHeight, newVersion uint64, status int) {
|
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 {
|
if record.Type != RecordTypeProfile {
|
||||||
return 0 // no action
|
return 0 // no action
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user