From 3e2b5e81d170385be06647b89a7dda0ff873abfb Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 16:29:44 +0530 Subject: [PATCH 01/30] wm chain setup --- .../blobbercore/blobberhttp/response.go | 11 +- .../blobbercore/convert/response_creator.go | 6 +- .../blobbercore/convert/response_handler.go | 6 +- .../blobbercore/handler/handler_common.go | 7 + .../handler/handler_writemarker.go | 9 +- .../handler/object_operation_handler.go | 78 ++++--- .../blobbercore/handler/storage_handler.go | 14 ++ .../blobbercore/writemarker/entity.go | 100 +++++++-- .../blobbercore/writemarker/mutex.go | 4 + .../blobbercore/writemarker/protocol.go | 32 ++- .../blobbercore/writemarker/worker.go | 204 +++++++++++------- .../blobbercore/writemarker/writemarker.go | 18 +- .../storage/writemarker/entity.go | 8 +- 13 files changed, 340 insertions(+), 157 deletions(-) diff --git a/code/go/0chain.net/blobbercore/blobberhttp/response.go b/code/go/0chain.net/blobbercore/blobberhttp/response.go index b48fcdbd6..44415edf9 100644 --- a/code/go/0chain.net/blobbercore/blobberhttp/response.go +++ b/code/go/0chain.net/blobbercore/blobberhttp/response.go @@ -15,17 +15,18 @@ type ConnectionResult struct { // swagger:model CommitResult type CommitResult struct { - AllocationRoot string `json:"allocation_root"` - WriteMarker *writemarker.WriteMarker `json:"write_marker"` - Success bool `json:"success"` - ErrorMessage string `json:"error_msg,omitempty"` + AllocationRoot string `json:"allocation_root"` + WriteMarker *writemarker.WriteMarkerEntity `json:"write_marker"` + Success bool `json:"success"` + ErrorMessage string `json:"error_msg,omitempty"` //Result []*UploadResult `json:"result"` } // swagger:model ReferencePathResult type ReferencePathResult struct { *reference.ReferencePath - LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` + LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` + ChainData []byte `json:"chain_data"` } // swagger:model RefResult diff --git a/code/go/0chain.net/blobbercore/convert/response_creator.go b/code/go/0chain.net/blobbercore/convert/response_creator.go index 39748dbdd..828bd2bcb 100644 --- a/code/go/0chain.net/blobbercore/convert/response_creator.go +++ b/code/go/0chain.net/blobbercore/convert/response_creator.go @@ -129,9 +129,9 @@ func CommitWriteResponseCreator(r interface{}) *blobbergrpc.CommitResponse { return &blobbergrpc.CommitResponse{ AllocationRoot: httpResp.AllocationRoot, - WriteMarker: WriteMarkerToWriteMarkerGRPC(httpResp.WriteMarker), - ErrorMessage: httpResp.ErrorMessage, - Success: httpResp.Success, + // WriteMarker: WriteMarkerToWriteMarkerGRPC(httpResp.WriteMarker), + ErrorMessage: httpResp.ErrorMessage, + Success: httpResp.Success, } } diff --git a/code/go/0chain.net/blobbercore/convert/response_handler.go b/code/go/0chain.net/blobbercore/convert/response_handler.go index ba4dc171e..3092c6b6d 100644 --- a/code/go/0chain.net/blobbercore/convert/response_handler.go +++ b/code/go/0chain.net/blobbercore/convert/response_handler.go @@ -87,9 +87,9 @@ func GetObjectTreeResponseHandler(getObjectTreeResponse *blobbergrpc.GetObjectTr func CommitWriteResponseHandler(resp *blobbergrpc.CommitResponse) *blobberhttp.CommitResult { return &blobberhttp.CommitResult{ AllocationRoot: resp.AllocationRoot, - WriteMarker: WriteMarkerGRPCToWriteMarker(resp.WriteMarker), - Success: resp.Success, - ErrorMessage: resp.ErrorMessage, + // WriteMarker: WriteMarkerGRPCToWriteMarker(resp.WriteMarker), + Success: resp.Success, + ErrorMessage: resp.ErrorMessage, } } diff --git a/code/go/0chain.net/blobbercore/handler/handler_common.go b/code/go/0chain.net/blobbercore/handler/handler_common.go index 3c3e19460..b8cdf4571 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_common.go +++ b/code/go/0chain.net/blobbercore/handler/handler_common.go @@ -8,6 +8,8 @@ import ( "time" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" + "github.com/0chain/blobber/code/go/0chain.net/blobbercore/blobberhttp" + "github.com/0chain/blobber/code/go/0chain.net/blobbercore/writemarker" "github.com/0chain/blobber/code/go/0chain.net/core/build" "github.com/0chain/blobber/code/go/0chain.net/core/chain" "github.com/0chain/blobber/code/go/0chain.net/core/common" @@ -153,6 +155,11 @@ func WithStatusConnectionForWM(handler common.StatusCodeResponderF) common.Statu return resp, statusCode, common.NewErrorf("commit_error", "error committing to meta store: %v", err) } + + if blobberRes, ok := resp.(*blobberhttp.CommitResult); ok { + writemarker.SaveMarkerData(allocationID, blobberRes.WriteMarker.WM.Timestamp, blobberRes.WriteMarker.WM.ChainLength) + } + return } } diff --git a/code/go/0chain.net/blobbercore/handler/handler_writemarker.go b/code/go/0chain.net/blobbercore/handler/handler_writemarker.go index 5704862a8..392811c1f 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_writemarker.go +++ b/code/go/0chain.net/blobbercore/handler/handler_writemarker.go @@ -2,20 +2,15 @@ package handler import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/writemarker" - "github.com/0chain/blobber/code/go/0chain.net/core/common" . "github.com/0chain/blobber/code/go/0chain.net/core/logging" "go.uber.org/zap" ) -var WriteMarkerMutext = &writemarker.Mutex{ - ML: common.GetNewLocker(), -} - // LockWriteMarker try to lock writemarker for specified allocation id, and return latest RefTree func LockWriteMarker(ctx *Context) (interface{}, error) { connectionID, _ := ctx.FormValue("connection_id") - result, err := WriteMarkerMutext.Lock(ctx, ctx.AllocationId, connectionID) + result, err := writemarker.WriteMarkerMutext.Lock(ctx, ctx.AllocationId, connectionID) Logger.Info("Lock write marker result", zap.Any("result", result), zap.Error(err)) if err != nil { return nil, err @@ -28,7 +23,7 @@ func LockWriteMarker(ctx *Context) (interface{}, error) { func UnlockWriteMarker(ctx *Context) (interface{}, error) { connectionID := ctx.Vars["connection"] - err := WriteMarkerMutext.Unlock(ctx, ctx.AllocationId, connectionID) + err := writemarker.WriteMarkerMutext.Unlock(ctx, ctx.AllocationId, connectionID) if err != nil { return nil, err } diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index f7b9217e5..4439f3ca0 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -89,18 +89,10 @@ func readPreRedeem( } func checkPendingMarkers(ctx context.Context, allocationID string) error { - - mut := writemarker.GetLock(allocationID) - if mut == nil { - return nil - } - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - err := mut.Acquire(ctx, 1) - if err != nil { - return common.NewError("check_pending_markers", "write marker is still not redeemed") + pending := writemarker.CheckProcessingMarker(allocationID) + if pending { + return common.NewError("pending_markers", "previous marker is still pending to be redeemed") } - mut.Release(1) return nil } @@ -584,6 +576,22 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return nil, common.NewErrorf("latest_write_marker_read_error", "Error reading the latest write marker for allocation: %v", err) } + if latestWriteMarkerEntity.Status == writemarker.Failed { + return nil, common.NewError("latest_write_marker_failed", + "Latest write marker is in failed state") + } + if latestWriteMarkerEntity.Status != writemarker.Committed { + if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { + return nil, common.NewErrorf("invalid_chain_size", + "Invalid chain size. expected:%v got %v", latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size, writeMarker.ChainSize) + } + writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength + } else { + if writeMarker.ChainSize != connectionObj.Size { + return nil, common.NewErrorf("invalid_chain_size", + "Invalid chain size. expected:%v got %v", connectionObj.Size, writeMarker.ChainSize) + } + } } writemarkerEntity := &writemarker.WriteMarkerEntity{} @@ -595,7 +603,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b result.ErrorMessage = "Verification of write marker failed: " + err.Error() result.Success = false if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM + result.WriteMarker = latestWriteMarkerEntity } Logger.Error("verify_writemarker_failed", zap.Error(err)) return &result, common.NewError("write_marker_verification_failed", result.ErrorMessage) @@ -649,7 +657,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if allocationRoot != writeMarker.AllocationRoot { result.AllocationRoot = allocationObj.AllocationRoot if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM + result.WriteMarker = latestWriteMarkerEntity } result.Success = false result.ErrorMessage = "Allocation root in the write marker does not match the calculated allocation root." + @@ -657,10 +665,18 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) + if err != nil { + return nil, common.NewError("chain_hash_error", "Error calculating chain hash") + } + if chainHash != writeMarker.ChainHash { + return nil, common.NewError("chain_hash_mismatch", "Chain hash in the write marker does not match the calculated chain hash") + } + if fileMetaRoot != writeMarker.FileMetaRoot { // result.AllocationRoot = allocationObj.AllocationRoot if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM + result.WriteMarker = latestWriteMarkerEntity } result.Success = false result.ErrorMessage = "File meta root in the write marker does not match the calculated file meta root." + @@ -670,6 +686,10 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b writemarkerEntity.ConnectionID = connectionObj.ID writemarkerEntity.ClientPublicKey = clientKey + writemarkerEntity.WM.ChainLength += 1 + if writemarkerEntity.WM.ChainLength > writemarker.MAX_CHAIN_LENGTH { + return nil, common.NewError("chain_length_exceeded", "Chain length exceeded") + } db := datastore.GetStore().GetTransaction(ctx) writemarkerEntity.Latest = true @@ -716,7 +736,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b db.Model(connectionObj).Updates(allocation.AllocationChangeCollector{Status: allocation.CommittedConnection}) result.AllocationRoot = allocationObj.AllocationRoot - result.WriteMarker = &writeMarker + result.WriteMarker = writemarkerEntity result.Success = true result.ErrorMessage = "" commitOperation := connectionObj.Changes[0].Operation @@ -725,10 +745,6 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b //Delete connection object and its changes db.Delete(connectionObj) - err = writemarkerEntity.SendToChan(ctx) - if err != nil { - return nil, common.NewError("write_marker_error", "Error redeeming the write marker") - } go allocation.DeleteConnectionObjEntry(connectionID) go AddWriteMarkerCount(clientID, connectionObj.Size <= 0) @@ -1359,6 +1375,10 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return nil, common.NewError("write_marker_verification_failed", "Verification of the write marker failed: "+err.Error()) } + if writemarkerEntity.WM.ChainLength > writemarker.MAX_CHAIN_LENGTH { + return nil, common.NewError("chain_length_exceeded", "Chain length exceeded") + } + elapsedVerifyWM := time.Since(startTime) - elapsedAllocation - elapsedGetLock var clientIDForWriteRedeem = writeMarker.ClientID @@ -1395,7 +1415,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob if allocationRoot != writeMarker.AllocationRoot { result.AllocationRoot = allocationObj.AllocationRoot if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM + result.WriteMarker = latestWriteMarkerEntity } result.Success = false result.ErrorMessage = "Allocation root in the write marker does not match the calculated allocation root." + @@ -1404,9 +1424,19 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) + if err != nil { + txn.Rollback() + return nil, common.NewError("chain_hash_error", "Error calculating chain hash "+err.Error()) + } + if chainHash != writeMarker.ChainHash { + txn.Rollback() + return nil, common.NewError("chain_hash_mismatch", "Chain hash in the write marker does not match the calculated chain hash") + } + if fileMetaRoot != writeMarker.FileMetaRoot { if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM + result.WriteMarker = latestWriteMarkerEntity } result.Success = false result.ErrorMessage = "File meta root in the write marker does not match the calculated file meta root." + @@ -1461,10 +1491,6 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob if err != nil { return &result, common.NewError("allocation_commit_error", "Error committing the transaction "+err.Error()) } - err = writemarkerEntity.SendToChan(ctx) - if err != nil { - return nil, common.NewError("write_marker_error", "Error redeeming the write marker") - } err = allocation.CommitRollback(allocationID) if err != nil { Logger.Error("Error committing the rollback for allocation", zap.Error(err)) @@ -1472,7 +1498,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob elapsedCommitRollback := time.Since(startTime) - elapsedAllocation - elapsedGetLock - elapsedVerifyWM - elapsedWritePreRedeem result.AllocationRoot = allocationObj.AllocationRoot - result.WriteMarker = &writeMarker + result.WriteMarker = writemarkerEntity result.Success = true result.ErrorMessage = "" commitOperation := "rollback" diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 736fb5c07..b5b2d9d49 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -461,6 +461,9 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req var result blobberhttp.LatestWriteMarkerResult if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainSize = 0 // start a new chain + } result.LatestWM = &latestWM.WM } if prevWM != nil { @@ -557,6 +560,9 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainSize = 0 // start a new chain + } refPathResult.LatestWM = &latestWM.WM } @@ -624,8 +630,16 @@ func (fsh *StorageHandler) GetObjectTree(ctx context.Context, r *http.Request) ( var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainSize = 0 // start a new chain + } refPathResult.LatestWM = &latestWM.WM } + chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) + if err != nil { + return nil, common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) + } + refPathResult.ChainData = chainData return &refPathResult, nil } diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index bac666ef9..25449e9a6 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -2,6 +2,7 @@ package writemarker import ( "context" + "encoding/hex" "encoding/json" "fmt" "time" @@ -9,6 +10,7 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/common" + "github.com/0chain/blobber/code/go/0chain.net/core/encryption" "github.com/0chain/blobber/code/go/0chain.net/core/logging" "go.uber.org/zap" "gorm.io/gorm" @@ -20,6 +22,9 @@ type WriteMarker struct { FileMetaRoot string `gorm:"column:file_meta_root;size:64" json:"file_meta_root"` AllocationID string `gorm:"column:allocation_id;size:64;index:idx_seq,unique,priority:1" json:"allocation_id"` Size int64 `gorm:"column:size" json:"size"` + ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` + ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` + ChainLength int `gorm:"column:chain_length" json:"-"` BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` ClientID string `gorm:"column:client_id;size:64" json:"client_id"` @@ -27,10 +32,10 @@ type WriteMarker struct { } func (wm *WriteMarker) GetHashData() string { - hashData := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%d:%d", + hashData := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%d:%d:%d", wm.AllocationRoot, wm.PreviousAllocationRoot, - wm.FileMetaRoot, wm.AllocationID, wm.BlobberID, - wm.ClientID, wm.Size, wm.Timestamp) + wm.FileMetaRoot, wm.ChainHash, wm.AllocationID, wm.BlobberID, + wm.ClientID, wm.Size, wm.ChainSize, wm.Timestamp) return hashData } @@ -43,6 +48,12 @@ const ( Rollbacked WriteMarkerStatus = 3 ) +const ( + MAX_CHAIN_LENGTH = 3 + MAX_TIMESTAMP_GAP = 60 * 30 // 30 minutes + MARKER_CONNECTION = "marker_connection" +) + type WriteMarkerEntity struct { // WM new WriteMarker from client WM WriteMarker `gorm:"embedded"` @@ -100,11 +111,6 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke return err } - err = db.Exec("UPDATE write_markers SET latest = false WHERE allocation_id = ? AND allocation_root = ? AND sequence < ?", wm.WM.AllocationID, wm.WM.PreviousAllocationRoot, wm.Sequence).Error - if err != nil { - return err - } - // TODO (sfxdx): what about failed write markers ? if status != Committed || wm.WM.Size <= 0 { return err // not committed or a deleting marker @@ -136,6 +142,9 @@ func GetWriteMarkerEntity(ctx context.Context, allocation_root string) (*WriteMa if err != nil { return nil, err } + if wm.Status == Committed { + wm.WM.ChainLength = 0 + } return wm, nil } @@ -219,16 +228,75 @@ func (wm *WriteMarkerEntity) Create(ctx context.Context) error { return err } -func (wm *WriteMarkerEntity) SendToChan(ctx context.Context) error { +func GetUncommittedWriteMarkers(ctx context.Context, allocationID string) ([]*WriteMarkerEntity, error) { + db := datastore.GetStore().GetTransaction(ctx) - sem := GetLock(wm.WM.AllocationID) - if sem == nil { - sem = SetLock(wm.WM.AllocationID) + unCommittedMarkers := make([]*WriteMarkerEntity, 0) + err := db.Table((WriteMarkerEntity{}).TableName()). + Where("allocation_id=? AND status=0", allocationID). + Order("sequence asc"). + Find(&unCommittedMarkers).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err } - err := sem.Acquire(context.TODO(), 1) + return unCommittedMarkers, nil +} + +func GetLatestCommittedWriteMarker(ctx context.Context, allocationID string) (*WriteMarkerEntity, error) { + db := datastore.GetStore().GetTransaction(ctx) + wm := &WriteMarkerEntity{} + err := db.Table((WriteMarkerEntity{}).TableName()). + Where("allocation_id=? AND status=1", allocationID). + Order("sequence desc"). + Take(wm).Error if err != nil { - return err + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, err } - writeMarkerChan <- wm - return nil + return wm, nil } + +func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error) { + commitedMarker, err := GetLatestCommittedWriteMarker(ctx, allocationID) + if err != nil { + return nil, err + } + unComittedMarkers, err := GetUncommittedWriteMarkers(ctx, allocationID) + if err != nil { + return nil, err + } + markers := make([]byte, 0, len(unComittedMarkers)+1) + if commitedMarker != nil { + decodedHash, err := hex.DecodeString(commitedMarker.WM.AllocationRoot) + if err != nil { + return nil, err + } + markers = append(markers, decodedHash...) + } + for _, marker := range unComittedMarkers { + decodedHash, err := hex.DecodeString(marker.WM.AllocationRoot) + if err != nil { + return nil, err + } + markers = append(markers, decodedHash...) + } + return markers, nil +} + +func CalculateChainHash(ctx context.Context, allocationID, newRoot string) (string, error) { + prevRoots, err := GetMarkersForChain(ctx, allocationID) + if err != nil { + return "", err + } + decodedHash, err := hex.DecodeString(newRoot) + if err != nil { + return "", err + } + prevRoots = append(prevRoots, decodedHash...) + return encryption.Hash(prevRoots), nil +} + +// client lock alloc -> commitMarker -> unlock alloc +// don't want the worker to kick in between these steps, once alloc is unlocked, worker can pick it up diff --git a/code/go/0chain.net/blobbercore/writemarker/mutex.go b/code/go/0chain.net/blobbercore/writemarker/mutex.go index a497aba88..be11a510b 100644 --- a/code/go/0chain.net/blobbercore/writemarker/mutex.go +++ b/code/go/0chain.net/blobbercore/writemarker/mutex.go @@ -38,6 +38,10 @@ type Mutex struct { ML *common.MapLocker } +var WriteMarkerMutext = &Mutex{ + ML: common.GetNewLocker(), +} + // Lock will create/update lock in postgres. // If no lock exists for an allocation then new lock is created. // If lock exists and is of same connection ID then lock's createdAt is updated diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index 07279be5f..d091af7fe 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -6,6 +6,7 @@ import ( "time" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" + "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/chain" "github.com/0chain/blobber/code/go/0chain.net/core/common" "github.com/0chain/blobber/code/go/0chain.net/core/encryption" @@ -21,6 +22,7 @@ type CommitConnection struct { AllocationRoot string `json:"allocation_root"` PrevAllocationRoot string `json:"prev_allocation_root"` WriteMarker *WriteMarker `json:"write_marker"` + ChainData []byte `json:"chain_data"` } // VerifyMarker verify WriteMarker's hash and check allocation_root if it is unique @@ -116,8 +118,8 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { wme.Status = Committed wme.StatusMessage = t.TransactionOutput wme.CloseTxnID = t.Hash - _ = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) - return nil + err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) + return err } } @@ -134,6 +136,17 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { sn.AllocationRoot = wme.WM.AllocationRoot sn.PrevAllocationRoot = wme.WM.PreviousAllocationRoot sn.WriteMarker = &wme.WM + err = datastore.GetStore().WithNewTransaction(func(ctx context.Context) error { + sn.ChainData, err = GetMarkersForChain(ctx, wme.WM.AllocationID) + return err + }) + if err != nil { + wme.StatusMessage = "Error getting chain data. " + err.Error() + if err := wme.UpdateStatus(ctx, Failed, "Error getting chain data. "+err.Error(), ""); err != nil { + Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) + } + return err + } if sn.AllocationRoot == sn.PrevAllocationRoot { // get nonce of prev WM @@ -176,8 +189,8 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { } wme.Status = Committed wme.StatusMessage = t.TransactionOutput - _ = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) - return nil + err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) + return err } func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAllocation *allocation.Allocation, latestWM *WriteMarkerEntity) error { @@ -196,10 +209,17 @@ func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAlloca return common.NewError("write_marker_validation_failed", "Write Marker is not for the same allocation transaction") } - if wme.WM.Size != 0 { + if wme.WM.Size != -latestWM.WM.Size { return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) } + if latestWM.Status != Committed { + if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { + return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) + } + wme.WM.ChainLength = latestWM.WM.ChainLength + } + if wme.WM.AllocationRoot == dbAllocation.AllocationRoot { return common.NewError("write_marker_validation_failed", "Write Marker allocation root is the same as the allocation root on record") } @@ -231,6 +251,6 @@ func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAlloca if !sigOK { return common.NewError("write_marker_validation_failed", "Write marker signature is not valid") } - + wme.WM.ChainLength += 1 return nil } diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index be0670620..10ff7d391 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -8,18 +8,63 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" + "github.com/0chain/blobber/code/go/0chain.net/core/common" + "github.com/0chain/blobber/code/go/0chain.net/core/lock" "github.com/0chain/blobber/code/go/0chain.net/core/logging" "go.uber.org/zap" - "golang.org/x/sync/semaphore" "gorm.io/gorm" ) var ( - writeMarkerChan chan *WriteMarkerEntity - writeMarkerMap map[string]*semaphore.Weighted - mut sync.RWMutex + writeMarkerChan chan *markerData + markerDataMap map[string]*markerData + markerDataMut sync.Mutex ) +type markerData struct { + firstMarkerTimestamp common.Timestamp + allocationID string + retries int + chainLength int + processing bool +} + +func SaveMarkerData(allocationID string, timestamp common.Timestamp, chainLength int) { + markerDataMut.Lock() + defer markerDataMut.Unlock() + if data, ok := markerDataMap[allocationID]; !ok { + markerDataMap[allocationID] = &markerData{ + firstMarkerTimestamp: timestamp, + allocationID: allocationID, + chainLength: 1, + } + } else { + data.chainLength = chainLength + if data.chainLength == 1 { + data.firstMarkerTimestamp = timestamp + } + if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + data.processing = true + writeMarkerChan <- data + } + } +} + +func CheckProcessingMarker(allocationID string) bool { + markerDataMut.Lock() + defer markerDataMut.Unlock() + if data, ok := markerDataMap[allocationID]; ok { + return data.processing + } + return false +} + +func deleteMarkerData(allocationID string) { + markerDataMut.Lock() + delete(markerDataMap, allocationID) + markerDataMut.Unlock() +} + // const ( // timestampGap = 30 * 24 * 60 * 60 // 30 days // cleanupWorkerInterval = 24 * 7 * time.Hour // 7 days @@ -37,33 +82,15 @@ func SetupWorkers(ctx context.Context) { zap.Any("error", err)) } - writeMarkerMap = make(map[string]*semaphore.Weighted) - - for _, r := range res { - writeMarkerMap[r.ID] = semaphore.NewWeighted(1) - } - - go startRedeem(ctx) + startRedeem(ctx, res) + go startCollector(ctx) // go startCleanupWorker(ctx) } -func GetLock(allocationID string) *semaphore.Weighted { - mut.RLock() - defer mut.RUnlock() - return writeMarkerMap[allocationID] -} - -func SetLock(allocationID string) *semaphore.Weighted { - mut.Lock() - defer mut.Unlock() - writeMarkerMap[allocationID] = semaphore.NewWeighted(1) - return writeMarkerMap[allocationID] -} - -func redeemWriteMarker(wm *WriteMarkerEntity) error { +func redeemWriteMarker(md *markerData) error { ctx := datastore.GetStore().CreateTransaction(context.TODO()) db := datastore.GetStore().GetTransaction(ctx) - allocationID := wm.WM.AllocationID + allocationID := md.allocationID shouldRollback := false start := time.Now() defer func() { @@ -71,42 +98,54 @@ func redeemWriteMarker(wm *WriteMarkerEntity) error { if rollbackErr := db.Rollback().Error; rollbackErr != nil { logging.Logger.Error("Error rollback on redeeming the write marker.", zap.Any("allocation", allocationID), - zap.Any("wm", wm.WM.AllocationID), zap.Error(rollbackErr)) + zap.Error(rollbackErr)) } + + } else { + deleteMarkerData(allocationID) } }() - alloc, err := allocation.Repo.GetByIdAndLock(ctx, allocationID) + + res, _ := WriteMarkerMutext.Lock(ctx, allocationID, MARKER_CONNECTION) + if res.Status != LockStatusOK { + if common.Now()-md.firstMarkerTimestamp < 2*MAX_TIMESTAMP_GAP { + md.retries++ + go tryAgain(md) + shouldRollback = true + return nil + } + //Exceeded twice of max timestamp gap, can be a malicious client keeping the lock forever to block the redeem + } else { + defer WriteMarkerMutext.Unlock(ctx, allocationID, MARKER_CONNECTION) + } + allocMu := lock.GetMutex(allocation.Allocation{}.TableName(), allocationID) + allocMu.RLock() + defer allocMu.RUnlock() + + alloc, err := allocation.Repo.GetAllocationFromDB(ctx, allocationID) if err != nil { - logging.Logger.Error("Error redeeming the write marker.", zap.Any("allocation", allocationID), zap.Any("wm", wm.WM.AllocationID), zap.Any("error", err)) + logging.Logger.Error("Error redeeming the write marker.", zap.Any("allocation", allocationID), zap.Any("wm", allocationID), zap.Any("error", err)) if err != gorm.ErrRecordNotFound { - go tryAgain(wm) + go tryAgain(md) } shouldRollback = true return err } if alloc.Finalized { - logging.Logger.Info("Allocation is finalized. Skipping redeeming the write marker.", zap.Any("allocation", allocationID), zap.Any("wm", wm.WM.AllocationID)) + logging.Logger.Info("Allocation is finalized. Skipping redeeming the write marker.", zap.Any("allocation", allocationID)) + deleteMarkerData(allocationID) shouldRollback = true return nil } - if alloc.AllocationRoot != wm.WM.AllocationRoot { - logging.Logger.Info("Stale write marker. Allocation root mismatch", - zap.Any("allocation", allocationID), - zap.Any("wm", wm.WM.AllocationRoot), zap.Any("alloc_root", alloc.AllocationRoot)) - if wm.ReedeemRetries == 0 && !alloc.IsRedeemRequired { - wm.ReedeemRetries++ - go tryAgain(wm) - shouldRollback = true - return nil - } - _ = wm.UpdateStatus(ctx, Rollbacked, "rollbacked", "") - err = db.Commit().Error - mut := GetLock(allocationID) - if mut != nil { - mut.Release(1) + wm, err := GetWriteMarkerEntity(ctx, alloc.AllocationRoot) + if err != nil { + logging.Logger.Error("Error redeeming the write marker.", zap.Any("allocation", allocationID), zap.Any("wm", alloc.AllocationRoot), zap.Any("error", err)) + if err != gorm.ErrRecordNotFound { + go tryAgain(md) } + shouldRollback = true return err } @@ -117,23 +156,13 @@ func redeemWriteMarker(wm *WriteMarkerEntity) error { zap.Any("allocation", allocationID), zap.Any("wm", wm), zap.Any("error", err), zap.Any("elapsedTime", elapsedTime)) if retryRedeem(err.Error()) { - go tryAgain(wm) - } else { - mut := GetLock(allocationID) - if mut != nil { - mut.Release(1) - } + go tryAgain(md) } shouldRollback = true - return err } - defer func() { - mut := GetLock(allocationID) - if mut != nil { - mut.Release(1) - } - }() + deleteMarkerData(allocationID) + err = allocation.Repo.UpdateAllocationRedeem(ctx, allocationID, wm.WM.AllocationRoot, alloc) if err != nil { logging.Logger.Error("Error redeeming the write marker. Allocation latest wm redeemed update failed", @@ -159,15 +188,27 @@ func redeemWriteMarker(wm *WriteMarkerEntity) error { return nil } -func startRedeem(ctx context.Context) { +func startRedeem(ctx context.Context, res []allocation.Res) { logging.Logger.Info("Start redeeming writemarkers") - writeMarkerChan = make(chan *WriteMarkerEntity, 200) + writeMarkerChan = make(chan *markerData, 200) go startRedeemWorker(ctx) var writemarkers []*WriteMarkerEntity err := datastore.GetStore().WithNewTransaction(func(ctx context.Context) error { tx := datastore.GetStore().GetTransaction(ctx) - return tx.Not(WriteMarkerEntity{Status: Committed}).Find(&writemarkers).Error + for _, r := range res { + wm := WriteMarkerEntity{} + err := tx.Where("allocation_id = ?", r.ID). + Order("sequence desc"). + Take(&wm).Error + if err != nil && err != gorm.ErrRecordNotFound { + return err + } + if wm.WM.AllocationID != "" && wm.Status == Accepted { + writemarkers = append(writemarkers, &wm) + } + } + return nil }) if err != nil && err != gorm.ErrRecordNotFound { logging.Logger.Error("Error redeeming the write marker. failed to load allocation's writemarker ", @@ -175,24 +216,11 @@ func startRedeem(ctx context.Context) { return } - for _, wm := range writemarkers { - mut := GetLock(wm.WM.AllocationID) - if mut == nil { - mut = SetLock(wm.WM.AllocationID) - } - err := mut.Acquire(ctx, 1) - if err != nil { - logging.Logger.Error("Error acquiring semaphore", zap.Error(err)) - continue - } - writeMarkerChan <- wm - } - } -func tryAgain(wm *WriteMarkerEntity) { - time.Sleep(time.Duration(wm.ReedeemRetries) * 5 * time.Second) - writeMarkerChan <- wm +func tryAgain(md *markerData) { + time.Sleep(time.Duration(md.retries) * 5 * time.Second) + writeMarkerChan <- md } // Can add more cases where we don't want to retry @@ -200,6 +228,26 @@ func retryRedeem(errString string) bool { return !strings.Contains(errString, "value not present") } +func startCollector(ctx context.Context) { + ticker := time.NewTicker(10 * time.Minute) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + markerDataMut.Lock() + for _, data := range markerDataMap { + if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + data.processing = true + writeMarkerChan <- data + } + } + markerDataMut.Unlock() + } + } +} + // TODO: don't delete prev WM // func startCleanupWorker(ctx context.Context) { // for { diff --git a/code/go/0chain.net/blobbercore/writemarker/writemarker.go b/code/go/0chain.net/blobbercore/writemarker/writemarker.go index fbdf97efe..dff2a364e 100644 --- a/code/go/0chain.net/blobbercore/writemarker/writemarker.go +++ b/code/go/0chain.net/blobbercore/writemarker/writemarker.go @@ -5,25 +5,23 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/config" "github.com/0chain/blobber/code/go/0chain.net/core/logging" - "golang.org/x/sync/semaphore" ) func startRedeemWorker(ctx context.Context) { logging.Logger.Info("Starting redeem worker") - sem := semaphore.NewWeighted(int64(config.Configuration.WMRedeemNumWorkers)) + for i := 0; i < config.Configuration.WMRedeemNumWorkers; i++ { + go redeemWorker(ctx) + } +} + +func redeemWorker(ctx context.Context) { for { select { case <-ctx.Done(): logging.Logger.Info("Stopping redeem worker") return - case wm := <-writeMarkerChan: - err := sem.Acquire(ctx, 1) - if err == nil { - go func() { - _ = redeemWriteMarker(wm) - sem.Release(1) - }() - } + case dm := <-writeMarkerChan: + _ = redeemWriteMarker(dm) } } } diff --git a/code/go/0chain.net/validatorcore/storage/writemarker/entity.go b/code/go/0chain.net/validatorcore/storage/writemarker/entity.go index e232eb0c3..2942b1561 100644 --- a/code/go/0chain.net/validatorcore/storage/writemarker/entity.go +++ b/code/go/0chain.net/validatorcore/storage/writemarker/entity.go @@ -19,6 +19,8 @@ type WriteMarker struct { FileMetaRoot string `json:"file_meta_root"` AllocationID string `json:"allocation_id"` Size int64 `json:"size"` + ChainSize int64 `json:"chain_size"` + ChainHash string `json:"chain_hash"` BlobberID string `json:"blobber_id"` Timestamp common.Timestamp `json:"timestamp"` ClientID string `json:"client_id"` @@ -26,10 +28,10 @@ type WriteMarker struct { } func (wm *WriteMarker) GetHashData() string { - hashData := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%d:%d", + hashData := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%d:%d:%d", wm.AllocationRoot, wm.PreviousAllocationRoot, - wm.FileMetaRoot, wm.AllocationID, wm.BlobberID, - wm.ClientID, wm.Size, wm.Timestamp) + wm.FileMetaRoot, wm.ChainHash, wm.AllocationID, wm.BlobberID, + wm.ClientID, wm.Size, wm.ChainSize, wm.Timestamp) return hashData } From b9f4d18f1c8215badfeb17d25bf574c52053b60b Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 16:35:13 +0530 Subject: [PATCH 02/30] fix lint --- code/go/0chain.net/blobbercore/writemarker/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 10ff7d391..419c91cf3 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -116,7 +116,7 @@ func redeemWriteMarker(md *markerData) error { } //Exceeded twice of max timestamp gap, can be a malicious client keeping the lock forever to block the redeem } else { - defer WriteMarkerMutext.Unlock(ctx, allocationID, MARKER_CONNECTION) + defer WriteMarkerMutext.Unlock(ctx, allocationID, MARKER_CONNECTION) //nolint:errcheck } allocMu := lock.GetMutex(allocation.Allocation{}.TableName(), allocationID) allocMu.RLock() From 1d5d87e833317fc349fc7e68b0bbd56db8772403 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 17:04:10 +0530 Subject: [PATCH 03/30] add sql migration --- goose/migrations/1707996797_chain_wm.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 goose/migrations/1707996797_chain_wm.sql diff --git a/goose/migrations/1707996797_chain_wm.sql b/goose/migrations/1707996797_chain_wm.sql new file mode 100644 index 000000000..bd6b9b186 --- /dev/null +++ b/goose/migrations/1707996797_chain_wm.sql @@ -0,0 +1,7 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE write_markers +ADD COLUMN chain_hash character varying(64); +ADD COLUMN chain_size BIGINT; +ADD COLUMN chain_length integer; +-- +goose StatementEnd \ No newline at end of file From b51a8c54dbd2bdcbe3af4b7569b27bbc26a28a6b Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 17:58:10 +0530 Subject: [PATCH 04/30] fix migration --- goose/migrations/1707996797_chain_wm.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/goose/migrations/1707996797_chain_wm.sql b/goose/migrations/1707996797_chain_wm.sql index bd6b9b186..fa2e8e180 100644 --- a/goose/migrations/1707996797_chain_wm.sql +++ b/goose/migrations/1707996797_chain_wm.sql @@ -1,7 +1,7 @@ -- +goose Up -- +goose StatementBegin ALTER TABLE write_markers -ADD COLUMN chain_hash character varying(64); -ADD COLUMN chain_size BIGINT; +ADD COLUMN chain_hash character varying(64), +ADD COLUMN chain_size BIGINT, ADD COLUMN chain_length integer; -- +goose StatementEnd \ No newline at end of file From 7d50fa5f4e743d9486d0498f8201294facfb72b2 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 18:29:36 +0530 Subject: [PATCH 05/30] add chain data in refpath --- .../0chain.net/blobbercore/handler/storage_handler.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index d02240436..4ba10d787 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -568,6 +568,12 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request } refPathResult.LatestWM = &latestWM.WM } + chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) + if err != nil { + errCh <- common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) + return + } + refPathResult.ChainData = chainData resCh <- &refPathResult } @@ -639,11 +645,6 @@ func (fsh *StorageHandler) GetObjectTree(ctx context.Context, r *http.Request) ( } refPathResult.LatestWM = &latestWM.WM } - chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) - if err != nil { - return nil, common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) - } - refPathResult.ChainData = chainData return &refPathResult, nil } From 72d2603fc4c1dc04997c959bd2d58f2b322663f0 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 19:31:35 +0530 Subject: [PATCH 06/30] add save logs --- code/go/0chain.net/blobbercore/handler/handler_common.go | 3 +++ code/go/0chain.net/blobbercore/writemarker/worker.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/code/go/0chain.net/blobbercore/handler/handler_common.go b/code/go/0chain.net/blobbercore/handler/handler_common.go index b8cdf4571..134d2e4d1 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_common.go +++ b/code/go/0chain.net/blobbercore/handler/handler_common.go @@ -157,7 +157,10 @@ func WithStatusConnectionForWM(handler common.StatusCodeResponderF) common.Statu } if blobberRes, ok := resp.(*blobberhttp.CommitResult); ok { + // Save the write marker data writemarker.SaveMarkerData(allocationID, blobberRes.WriteMarker.WM.Timestamp, blobberRes.WriteMarker.WM.ChainLength) + } else { + Logger.Error("Invalid response type for commit handler") } return diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 419c91cf3..1a221bf1f 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -30,6 +30,7 @@ type markerData struct { } func SaveMarkerData(allocationID string, timestamp common.Timestamp, chainLength int) { + logging.Logger.Info("SaveMarkerData", zap.Any("allocationID", allocationID), zap.Any("timestamp", timestamp), zap.Any("chainLength", chainLength)) markerDataMut.Lock() defer markerDataMut.Unlock() if data, ok := markerDataMap[allocationID]; !ok { @@ -44,6 +45,7 @@ func SaveMarkerData(allocationID string, timestamp common.Timestamp, chainLength data.firstMarkerTimestamp = timestamp } if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + logging.Logger.Info("ProcessMarkerData", zap.Any("allocationID", allocationID), zap.Any("timestamp", timestamp), zap.Any("chainLength", chainLength)) data.processing = true writeMarkerChan <- data } @@ -93,6 +95,7 @@ func redeemWriteMarker(md *markerData) error { allocationID := md.allocationID shouldRollback := false start := time.Now() + logging.Logger.Info("Redeeming the write marker", zap.String("allocationID", allocationID)) defer func() { if shouldRollback { if rollbackErr := db.Rollback().Error; rollbackErr != nil { @@ -239,6 +242,7 @@ func startCollector(ctx context.Context) { markerDataMut.Lock() for _, data := range markerDataMap { if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + logging.Logger.Info("ProcessMarkerData", zap.Any("allocationID", data.allocationID), zap.Any("timestamp", data.firstMarkerTimestamp), zap.Any("chainLength", data.chainLength)) data.processing = true writeMarkerChan <- data } From 8435fea27a241fdb9fafa97c2eee6291ce7420e3 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 20:30:38 +0530 Subject: [PATCH 07/30] add query param chain data --- .../blobbercore/blobberhttp/response.go | 5 +++-- .../blobbercore/handler/storage_handler.go | 8 ++++++++ .../blobbercore/writemarker/worker.go | 19 +++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/code/go/0chain.net/blobbercore/blobberhttp/response.go b/code/go/0chain.net/blobbercore/blobberhttp/response.go index 44415edf9..1790259e6 100644 --- a/code/go/0chain.net/blobbercore/blobberhttp/response.go +++ b/code/go/0chain.net/blobbercore/blobberhttp/response.go @@ -64,6 +64,7 @@ type DownloadResponse struct { } type LatestWriteMarkerResult struct { - LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` - PrevWM *writemarker.WriteMarker `json:"prev_write_marker"` + LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` + PrevWM *writemarker.WriteMarker `json:"prev_write_marker"` + ChainData []byte `json:"chain_data"` } diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 4ba10d787..0d51c1785 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -472,6 +472,14 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req result.PrevWM = &prevWM.WM } + if _, ok := common.GetField(r, "chain_data"); ok { + chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) + if err != nil { + return nil, common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) + } + result.ChainData = chainData + } + return &result, nil } diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 1a221bf1f..9330e12fd 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -17,7 +17,7 @@ import ( var ( writeMarkerChan chan *markerData - markerDataMap map[string]*markerData + markerDataMap = make(map[string]*markerData) markerDataMut sync.Mutex ) @@ -95,7 +95,7 @@ func redeemWriteMarker(md *markerData) error { allocationID := md.allocationID shouldRollback := false start := time.Now() - logging.Logger.Info("Redeeming the write marker", zap.String("allocationID", allocationID)) + logging.Logger.Info("redeeming_write_marker", zap.String("allocationID", allocationID)) defer func() { if shouldRollback { if rollbackErr := db.Rollback().Error; rollbackErr != nil { @@ -195,8 +195,8 @@ func startRedeem(ctx context.Context, res []allocation.Res) { logging.Logger.Info("Start redeeming writemarkers") writeMarkerChan = make(chan *markerData, 200) go startRedeemWorker(ctx) - - var writemarkers []*WriteMarkerEntity + markerDataMut.Lock() + defer markerDataMut.Unlock() err := datastore.GetStore().WithNewTransaction(func(ctx context.Context) error { tx := datastore.GetStore().GetTransaction(ctx) for _, r := range res { @@ -208,7 +208,15 @@ func startRedeem(ctx context.Context, res []allocation.Res) { return err } if wm.WM.AllocationID != "" && wm.Status == Accepted { - writemarkers = append(writemarkers, &wm) + md := &markerData{ + firstMarkerTimestamp: wm.WM.Timestamp, + allocationID: wm.WM.AllocationID, + chainLength: wm.WM.ChainLength, + processing: true, + retries: int(wm.ReedeemRetries), + } + markerDataMap[wm.WM.AllocationID] = md + writeMarkerChan <- md } } return nil @@ -218,7 +226,6 @@ func startRedeem(ctx context.Context, res []allocation.Res) { zap.Any("error", err)) return } - } func tryAgain(md *markerData) { From 8dc720cb74628a63ecf528c86c0358246d9ae8c4 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 21:14:39 +0530 Subject: [PATCH 08/30] unlock wm on commit --- .../0chain.net/blobbercore/handler/handler_common.go | 3 ++- .../blobbercore/handler/handler_writemarker.go | 2 +- .../blobbercore/handler/storage_handler.go | 12 +++++++----- code/go/0chain.net/blobbercore/writemarker/mutex.go | 2 +- code/go/0chain.net/blobbercore/writemarker/worker.go | 3 ++- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/handler_common.go b/code/go/0chain.net/blobbercore/handler/handler_common.go index 134d2e4d1..29010db82 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_common.go +++ b/code/go/0chain.net/blobbercore/handler/handler_common.go @@ -162,7 +162,8 @@ func WithStatusConnectionForWM(handler common.StatusCodeResponderF) common.Statu } else { Logger.Error("Invalid response type for commit handler") } - + connectionID, _ := common.GetField(r, "connection_id") + writemarker.WriteMarkerMutext.Unlock(allocationID, connectionID) //nolint:errcheck return } } diff --git a/code/go/0chain.net/blobbercore/handler/handler_writemarker.go b/code/go/0chain.net/blobbercore/handler/handler_writemarker.go index 392811c1f..966306613 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_writemarker.go +++ b/code/go/0chain.net/blobbercore/handler/handler_writemarker.go @@ -23,7 +23,7 @@ func LockWriteMarker(ctx *Context) (interface{}, error) { func UnlockWriteMarker(ctx *Context) (interface{}, error) { connectionID := ctx.Vars["connection"] - err := writemarker.WriteMarkerMutext.Unlock(ctx, ctx.AllocationId, connectionID) + err := writemarker.WriteMarkerMutext.Unlock(ctx.AllocationId, connectionID) if err != nil { return nil, err } diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 0d51c1785..b6ea2c90d 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -576,12 +576,14 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request } refPathResult.LatestWM = &latestWM.WM } - chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) - if err != nil { - errCh <- common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) - return + if _, ok := common.GetField(r, "chain_data"); ok { + chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) + if err != nil { + errCh <- common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) + return + } + refPathResult.ChainData = chainData } - refPathResult.ChainData = chainData resCh <- &refPathResult } diff --git a/code/go/0chain.net/blobbercore/writemarker/mutex.go b/code/go/0chain.net/blobbercore/writemarker/mutex.go index be11a510b..a5a24ecf3 100644 --- a/code/go/0chain.net/blobbercore/writemarker/mutex.go +++ b/code/go/0chain.net/blobbercore/writemarker/mutex.go @@ -101,7 +101,7 @@ func (m *Mutex) Lock(ctx context.Context, allocationID, connectionID string) (*L }, nil } -func (*Mutex) Unlock(ctx context.Context, allocationID string, connectionID string) error { +func (*Mutex) Unlock(allocationID string, connectionID string) error { if allocationID == "" || connectionID == "" { return nil } diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 9330e12fd..e3630f58e 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -111,6 +111,7 @@ func redeemWriteMarker(md *markerData) error { res, _ := WriteMarkerMutext.Lock(ctx, allocationID, MARKER_CONNECTION) if res.Status != LockStatusOK { + logging.Logger.Error("Error redeeming the write marker. Lock failed", zap.String("allocationID", allocationID), zap.Any("status", res.Status)) if common.Now()-md.firstMarkerTimestamp < 2*MAX_TIMESTAMP_GAP { md.retries++ go tryAgain(md) @@ -119,7 +120,7 @@ func redeemWriteMarker(md *markerData) error { } //Exceeded twice of max timestamp gap, can be a malicious client keeping the lock forever to block the redeem } else { - defer WriteMarkerMutext.Unlock(ctx, allocationID, MARKER_CONNECTION) //nolint:errcheck + defer WriteMarkerMutext.Unlock(allocationID, MARKER_CONNECTION) //nolint:errcheck } allocMu := lock.GetMutex(allocation.Allocation{}.TableName(), allocationID) allocMu.RLock() From b4b7a56f0788d1f2f89fba4d5031e71595968b3a Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 22:30:03 +0530 Subject: [PATCH 09/30] export chain length --- code/go/0chain.net/blobbercore/handler/storage_handler.go | 6 +++--- code/go/0chain.net/blobbercore/writemarker/entity.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index b6ea2c90d..306e9925c 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -464,7 +464,7 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req var result blobberhttp.LatestWriteMarkerResult if latestWM != nil { if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainSize = 0 // start a new chain + latestWM.WM.ChainLength = 0 // start a new chain } result.LatestWM = &latestWM.WM } @@ -572,7 +572,7 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request refPathResult.ReferencePath = refPath if latestWM != nil { if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainSize = 0 // start a new chain + latestWM.WM.ChainLength = 0 // start a new chain } refPathResult.LatestWM = &latestWM.WM } @@ -651,7 +651,7 @@ func (fsh *StorageHandler) GetObjectTree(ctx context.Context, r *http.Request) ( refPathResult.ReferencePath = refPath if latestWM != nil { if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainSize = 0 // start a new chain + latestWM.WM.ChainLength = 0 // start a new chain } refPathResult.LatestWM = &latestWM.WM } diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 25449e9a6..fd897a555 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -24,7 +24,7 @@ type WriteMarker struct { Size int64 `gorm:"column:size" json:"size"` ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` - ChainLength int `gorm:"column:chain_length" json:"-"` + ChainLength int `gorm:"column:chain_length" json:"chain_length"` BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` ClientID string `gorm:"column:client_id;size:64" json:"client_id"` From 42e0ced2d737ded480acb3ab0205270a02e7a3c7 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 23:05:03 +0530 Subject: [PATCH 10/30] fix uncommitted markers --- .../go/0chain.net/blobbercore/writemarker/entity.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index fd897a555..a7fae2b74 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -228,12 +228,12 @@ func (wm *WriteMarkerEntity) Create(ctx context.Context) error { return err } -func GetUncommittedWriteMarkers(ctx context.Context, allocationID string) ([]*WriteMarkerEntity, error) { +func GetUncommittedWriteMarkers(ctx context.Context, allocationID string, seq int64) ([]*WriteMarkerEntity, error) { db := datastore.GetStore().GetTransaction(ctx) unCommittedMarkers := make([]*WriteMarkerEntity, 0) err := db.Table((WriteMarkerEntity{}).TableName()). - Where("allocation_id=? AND status=0", allocationID). + Where("allocation_id=? AND status=0 AND sequence > ?", allocationID, seq). Order("sequence asc"). Find(&unCommittedMarkers).Error if err != nil && err != gorm.ErrRecordNotFound { @@ -263,9 +263,12 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error if err != nil { return nil, err } - unComittedMarkers, err := GetUncommittedWriteMarkers(ctx, allocationID) - if err != nil { - return nil, err + var unComittedMarkers []*WriteMarkerEntity + if commitedMarker != nil { + unComittedMarkers, err = GetUncommittedWriteMarkers(ctx, allocationID, commitedMarker.Sequence) + if err != nil { + return nil, err + } } markers := make([]byte, 0, len(unComittedMarkers)+1) if commitedMarker != nil { From 9189ecf8f7d85bfe81531f7ab3119b5e6a8dc81b Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 15 Feb 2024 23:56:08 +0530 Subject: [PATCH 11/30] fix sequence --- code/go/0chain.net/blobbercore/writemarker/entity.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index a7fae2b74..ff06c9bfa 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -263,12 +263,13 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error if err != nil { return nil, err } - var unComittedMarkers []*WriteMarkerEntity + var seq int64 if commitedMarker != nil { - unComittedMarkers, err = GetUncommittedWriteMarkers(ctx, allocationID, commitedMarker.Sequence) - if err != nil { - return nil, err - } + seq = commitedMarker.Sequence + } + unComittedMarkers, err := GetUncommittedWriteMarkers(ctx, allocationID, seq) + if err != nil { + return nil, err } markers := make([]byte, 0, len(unComittedMarkers)+1) if commitedMarker != nil { From b2772c77faf5012064c3a5150285ddde0a1b81ec Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Fri, 16 Feb 2024 19:08:41 +0530 Subject: [PATCH 12/30] change chainhash verify --- .../handler/object_operation_handler.go | 28 +++++++---------- .../blobbercore/handler/storage_handler.go | 9 ------ .../blobbercore/writemarker/entity.go | 30 ++++++++++++------- .../blobbercore/writemarker/protocol.go | 17 ++++++++--- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index 758df8f11..b91c73c1f 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -501,7 +501,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if r.Method == "GET" { return nil, common.NewError("invalid_method", "Invalid method used for the upload URL. Use POST instead") } - + var prevChainHash string allocationId := ctx.Value(constants.ContextKeyAllocationID).(string) allocationTx := ctx.Value(constants.ContextKeyAllocation).(string) clientID := ctx.Value(constants.ContextKeyClient).(string) @@ -593,19 +593,15 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if latestWriteMarkerEntity.Status == writemarker.Failed { return nil, common.NewError("latest_write_marker_failed", "Latest write marker is in failed state") - } - if latestWriteMarkerEntity.Status != writemarker.Committed { - if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { - return nil, common.NewErrorf("invalid_chain_size", - "Invalid chain size. expected:%v got %v", latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size, writeMarker.ChainSize) - } + } else if latestWriteMarkerEntity.Status == writemarker.Committed { writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength - } else { - if writeMarker.ChainSize != connectionObj.Size { - return nil, common.NewErrorf("invalid_chain_size", - "Invalid chain size. expected:%v got %v", connectionObj.Size, writeMarker.ChainSize) - } } + + if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { + return nil, common.NewError("invalid_chain_size", + "Invalid chain size") + } + prevChainHash = latestWriteMarkerEntity.WM.ChainHash } writemarkerEntity := &writemarker.WriteMarkerEntity{} @@ -679,7 +675,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot, prevChainHash) if err != nil { return nil, common.NewError("chain_hash_error", "Error calculating chain hash") } @@ -1426,9 +1422,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob if allocationRoot != writeMarker.AllocationRoot { result.AllocationRoot = allocationObj.AllocationRoot - if latestWriteMarkerEntity != nil { - result.WriteMarker = latestWriteMarkerEntity - } + result.WriteMarker = latestWriteMarkerEntity result.Success = false result.ErrorMessage = "Allocation root in the write marker does not match the calculated allocation root." + " Expected hash: " + allocationRoot @@ -1436,7 +1430,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot, latestWriteMarkerEntity.WM.ChainHash) if err != nil { txn.Rollback() return nil, common.NewError("chain_hash_error", "Error calculating chain hash "+err.Error()) diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 306e9925c..14e478279 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -463,9 +463,6 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req var result blobberhttp.LatestWriteMarkerResult if latestWM != nil { - if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainLength = 0 // start a new chain - } result.LatestWM = &latestWM.WM } if prevWM != nil { @@ -571,9 +568,6 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { - if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainLength = 0 // start a new chain - } refPathResult.LatestWM = &latestWM.WM } if _, ok := common.GetField(r, "chain_data"); ok { @@ -650,9 +644,6 @@ func (fsh *StorageHandler) GetObjectTree(ctx context.Context, r *http.Request) ( var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { - if latestWM.Status == writemarker.Committed { - latestWM.WM.ChainLength = 0 // start a new chain - } refPathResult.LatestWM = &latestWM.WM } return &refPathResult, nil diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index ff06c9bfa..115b62056 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -2,6 +2,7 @@ package writemarker import ( "context" + "crypto/sha256" "encoding/hex" "encoding/json" "fmt" @@ -10,7 +11,6 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/common" - "github.com/0chain/blobber/code/go/0chain.net/core/encryption" "github.com/0chain/blobber/code/go/0chain.net/core/logging" "go.uber.org/zap" "gorm.io/gorm" @@ -24,7 +24,7 @@ type WriteMarker struct { Size int64 `gorm:"column:size" json:"size"` ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` - ChainLength int `gorm:"column:chain_length" json:"chain_length"` + ChainLength int `gorm:"column:chain_length" json:"-"` BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` ClientID string `gorm:"column:client_id;size:64" json:"client_id"` @@ -272,13 +272,6 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error return nil, err } markers := make([]byte, 0, len(unComittedMarkers)+1) - if commitedMarker != nil { - decodedHash, err := hex.DecodeString(commitedMarker.WM.AllocationRoot) - if err != nil { - return nil, err - } - markers = append(markers, decodedHash...) - } for _, marker := range unComittedMarkers { decodedHash, err := hex.DecodeString(marker.WM.AllocationRoot) if err != nil { @@ -289,7 +282,7 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error return markers, nil } -func CalculateChainHash(ctx context.Context, allocationID, newRoot string) (string, error) { +func CalculateChainHash(ctx context.Context, allocationID, newRoot, prevChainHash string) (string, error) { prevRoots, err := GetMarkersForChain(ctx, allocationID) if err != nil { return "", err @@ -298,8 +291,23 @@ func CalculateChainHash(ctx context.Context, allocationID, newRoot string) (stri if err != nil { return "", err } + prevChainBytes, err := hex.DecodeString(prevChainHash) + if err != nil { + return "", err + } + hasher := sha256.New() + if prevChainHash != "" { + _, err = hasher.Write(prevChainBytes) + if err != nil { + return "", err + } + } prevRoots = append(prevRoots, decodedHash...) - return encryption.Hash(prevRoots), nil + _, err = hasher.Write(prevRoots) + if err != nil { + return "", err + } + return hex.EncodeToString(hasher.Sum(nil)), nil } // client lock alloc -> commitMarker -> unlock alloc diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index d091af7fe..a726a9340 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -78,6 +78,10 @@ func (wme *WriteMarkerEntity) VerifyMarker(ctx context.Context, dbAllocation *al return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker size %v does not match the connection size %v", wme.WM.Size, co.Size)) } + if wme.WM.ChainSize < 0 { + return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size %v is negative", wme.WM.ChainSize)) + } + clientPublicKey := ctx.Value(constants.ContextKeyClientKey).(string) if clientPublicKey == "" { return common.NewError("write_marker_validation_failed", "Could not get the public key of the client") @@ -210,16 +214,21 @@ func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAlloca } if wme.WM.Size != -latestWM.WM.Size { - return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) + return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) } if latestWM.Status != Committed { - if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { - return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) - } wme.WM.ChainLength = latestWM.WM.ChainLength } + if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { + return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) + } + + if wme.WM.ChainSize < 0 { + return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size %v is negative", wme.WM.ChainSize)) + } + if wme.WM.AllocationRoot == dbAllocation.AllocationRoot { return common.NewError("write_marker_validation_failed", "Write Marker allocation root is the same as the allocation root on record") } From 1491cb121ee1ced0a5d5a7381df3ee94a1f52389 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Fri, 16 Feb 2024 20:53:04 +0530 Subject: [PATCH 13/30] Revert "change chainhash verify" This reverts commit b2772c77faf5012064c3a5150285ddde0a1b81ec. --- .../handler/object_operation_handler.go | 28 ++++++++++------- .../blobbercore/handler/storage_handler.go | 9 ++++++ .../blobbercore/writemarker/entity.go | 30 +++++++------------ .../blobbercore/writemarker/protocol.go | 17 +++-------- 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index b91c73c1f..758df8f11 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -501,7 +501,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if r.Method == "GET" { return nil, common.NewError("invalid_method", "Invalid method used for the upload URL. Use POST instead") } - var prevChainHash string + allocationId := ctx.Value(constants.ContextKeyAllocationID).(string) allocationTx := ctx.Value(constants.ContextKeyAllocation).(string) clientID := ctx.Value(constants.ContextKeyClient).(string) @@ -593,15 +593,19 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if latestWriteMarkerEntity.Status == writemarker.Failed { return nil, common.NewError("latest_write_marker_failed", "Latest write marker is in failed state") - } else if latestWriteMarkerEntity.Status == writemarker.Committed { - writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength } - - if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { - return nil, common.NewError("invalid_chain_size", - "Invalid chain size") + if latestWriteMarkerEntity.Status != writemarker.Committed { + if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { + return nil, common.NewErrorf("invalid_chain_size", + "Invalid chain size. expected:%v got %v", latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size, writeMarker.ChainSize) + } + writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength + } else { + if writeMarker.ChainSize != connectionObj.Size { + return nil, common.NewErrorf("invalid_chain_size", + "Invalid chain size. expected:%v got %v", connectionObj.Size, writeMarker.ChainSize) + } } - prevChainHash = latestWriteMarkerEntity.WM.ChainHash } writemarkerEntity := &writemarker.WriteMarkerEntity{} @@ -675,7 +679,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot, prevChainHash) + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) if err != nil { return nil, common.NewError("chain_hash_error", "Error calculating chain hash") } @@ -1422,7 +1426,9 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob if allocationRoot != writeMarker.AllocationRoot { result.AllocationRoot = allocationObj.AllocationRoot - result.WriteMarker = latestWriteMarkerEntity + if latestWriteMarkerEntity != nil { + result.WriteMarker = latestWriteMarkerEntity + } result.Success = false result.ErrorMessage = "Allocation root in the write marker does not match the calculated allocation root." + " Expected hash: " + allocationRoot @@ -1430,7 +1436,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot, latestWriteMarkerEntity.WM.ChainHash) + chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) if err != nil { txn.Rollback() return nil, common.NewError("chain_hash_error", "Error calculating chain hash "+err.Error()) diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 14e478279..306e9925c 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -463,6 +463,9 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req var result blobberhttp.LatestWriteMarkerResult if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainLength = 0 // start a new chain + } result.LatestWM = &latestWM.WM } if prevWM != nil { @@ -568,6 +571,9 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainLength = 0 // start a new chain + } refPathResult.LatestWM = &latestWM.WM } if _, ok := common.GetField(r, "chain_data"); ok { @@ -644,6 +650,9 @@ func (fsh *StorageHandler) GetObjectTree(ctx context.Context, r *http.Request) ( var refPathResult blobberhttp.ReferencePathResult refPathResult.ReferencePath = refPath if latestWM != nil { + if latestWM.Status == writemarker.Committed { + latestWM.WM.ChainLength = 0 // start a new chain + } refPathResult.LatestWM = &latestWM.WM } return &refPathResult, nil diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 115b62056..ff06c9bfa 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -2,7 +2,6 @@ package writemarker import ( "context" - "crypto/sha256" "encoding/hex" "encoding/json" "fmt" @@ -11,6 +10,7 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/common" + "github.com/0chain/blobber/code/go/0chain.net/core/encryption" "github.com/0chain/blobber/code/go/0chain.net/core/logging" "go.uber.org/zap" "gorm.io/gorm" @@ -24,7 +24,7 @@ type WriteMarker struct { Size int64 `gorm:"column:size" json:"size"` ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` - ChainLength int `gorm:"column:chain_length" json:"-"` + ChainLength int `gorm:"column:chain_length" json:"chain_length"` BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` ClientID string `gorm:"column:client_id;size:64" json:"client_id"` @@ -272,6 +272,13 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error return nil, err } markers := make([]byte, 0, len(unComittedMarkers)+1) + if commitedMarker != nil { + decodedHash, err := hex.DecodeString(commitedMarker.WM.AllocationRoot) + if err != nil { + return nil, err + } + markers = append(markers, decodedHash...) + } for _, marker := range unComittedMarkers { decodedHash, err := hex.DecodeString(marker.WM.AllocationRoot) if err != nil { @@ -282,7 +289,7 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error return markers, nil } -func CalculateChainHash(ctx context.Context, allocationID, newRoot, prevChainHash string) (string, error) { +func CalculateChainHash(ctx context.Context, allocationID, newRoot string) (string, error) { prevRoots, err := GetMarkersForChain(ctx, allocationID) if err != nil { return "", err @@ -291,23 +298,8 @@ func CalculateChainHash(ctx context.Context, allocationID, newRoot, prevChainHas if err != nil { return "", err } - prevChainBytes, err := hex.DecodeString(prevChainHash) - if err != nil { - return "", err - } - hasher := sha256.New() - if prevChainHash != "" { - _, err = hasher.Write(prevChainBytes) - if err != nil { - return "", err - } - } prevRoots = append(prevRoots, decodedHash...) - _, err = hasher.Write(prevRoots) - if err != nil { - return "", err - } - return hex.EncodeToString(hasher.Sum(nil)), nil + return encryption.Hash(prevRoots), nil } // client lock alloc -> commitMarker -> unlock alloc diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index a726a9340..d091af7fe 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -78,10 +78,6 @@ func (wme *WriteMarkerEntity) VerifyMarker(ctx context.Context, dbAllocation *al return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker size %v does not match the connection size %v", wme.WM.Size, co.Size)) } - if wme.WM.ChainSize < 0 { - return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size %v is negative", wme.WM.ChainSize)) - } - clientPublicKey := ctx.Value(constants.ContextKeyClientKey).(string) if clientPublicKey == "" { return common.NewError("write_marker_validation_failed", "Could not get the public key of the client") @@ -214,21 +210,16 @@ func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAlloca } if wme.WM.Size != -latestWM.WM.Size { - return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) + return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) } if latestWM.Status != Committed { + if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { + return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) + } wme.WM.ChainLength = latestWM.WM.ChainLength } - if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { - return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) - } - - if wme.WM.ChainSize < 0 { - return common.NewError("write_marker_validation_failed", fmt.Sprintf("Write Marker chain size %v is negative", wme.WM.ChainSize)) - } - if wme.WM.AllocationRoot == dbAllocation.AllocationRoot { return common.NewError("write_marker_validation_failed", "Write Marker allocation root is the same as the allocation root on record") } From 157ee28fd63ce16d87230b3ca2c9fc9229da0439 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Fri, 16 Feb 2024 21:44:43 +0530 Subject: [PATCH 14/30] fix chain size --- .../blobbercore/handler/object_operation_handler.go | 10 ++++++---- code/go/0chain.net/blobbercore/writemarker/protocol.go | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index 758df8f11..70d17d568 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -594,11 +594,13 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return nil, common.NewError("latest_write_marker_failed", "Latest write marker is in failed state") } + + if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { + return nil, common.NewErrorf("invalid_chain_size", + "Invalid chain size. expected:%v got %v", latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size, writeMarker.ChainSize) + } + if latestWriteMarkerEntity.Status != writemarker.Committed { - if latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size != writeMarker.ChainSize { - return nil, common.NewErrorf("invalid_chain_size", - "Invalid chain size. expected:%v got %v", latestWriteMarkerEntity.WM.ChainSize+connectionObj.Size, writeMarker.ChainSize) - } writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength } else { if writeMarker.ChainSize != connectionObj.Size { diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index d091af7fe..d4e49a38e 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -213,10 +213,11 @@ func (wme *WriteMarkerEntity) VerifyRollbackMarker(ctx context.Context, dbAlloca return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker size is %v but should be 0", wme.WM.Size)) } + if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { + return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) + } + if latestWM.Status != Committed { - if wme.WM.ChainSize != latestWM.WM.ChainSize+wme.WM.Size { - return common.NewError("empty write_marker_validation_failed", fmt.Sprintf("Write Marker chain size is %v but should be %v", wme.WM.ChainSize, latestWM.WM.ChainSize+wme.WM.Size)) - } wme.WM.ChainLength = latestWM.WM.ChainLength } From 87b19216e5ceb6dcdfd8b2e381397cc8f58f177c Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sat, 17 Feb 2024 17:06:52 +0530 Subject: [PATCH 15/30] calculate chain hash --- .../blobbercore/allocation/entity.go | 1 + .../blobbercore/allocation/repository.go | 5 +- .../blobbercore/blobberhttp/response.go | 8 +- .../blobbercore/handler/handler_common.go | 2 - .../handler/object_operation_handler.go | 18 +--- .../blobbercore/handler/storage_handler.go | 16 ---- .../blobbercore/writemarker/entity.go | 85 +++++++++---------- .../blobbercore/writemarker/protocol.go | 18 ++-- .../blobbercore/writemarker/protocol_main.go | 4 +- .../blobbercore/writemarker/worker.go | 20 +---- goose/migrations/1707996797_chain_wm.sql | 2 + 11 files changed, 70 insertions(+), 109 deletions(-) diff --git a/code/go/0chain.net/blobbercore/allocation/entity.go b/code/go/0chain.net/blobbercore/allocation/entity.go index 4022e813f..5d11b9d9a 100644 --- a/code/go/0chain.net/blobbercore/allocation/entity.go +++ b/code/go/0chain.net/blobbercore/allocation/entity.go @@ -53,6 +53,7 @@ type Allocation struct { BlobberSize int64 `gorm:"column:blobber_size;not null;default:0"` BlobberSizeUsed int64 `gorm:"column:blobber_size_used;not null;default:0"` LatestRedeemedWM string `gorm:"column:latest_redeemed_write_marker;size:64"` + LastRedeemedSeq int64 `gorm:"column:last_redeemed_sequence;default:0"` IsRedeemRequired bool `gorm:"column:is_redeem_required"` TimeUnit time.Duration `gorm:"column:time_unit;not null;default:172800000000000"` StartTime common.Timestamp `gorm:"column:start_time;not null"` diff --git a/code/go/0chain.net/blobbercore/allocation/repository.go b/code/go/0chain.net/blobbercore/allocation/repository.go index 52d2f1253..e793b3a13 100644 --- a/code/go/0chain.net/blobbercore/allocation/repository.go +++ b/code/go/0chain.net/blobbercore/allocation/repository.go @@ -191,7 +191,7 @@ func (r *Repository) GetAllocationIds(ctx context.Context) []Res { } -func (r *Repository) UpdateAllocationRedeem(ctx context.Context, allocationID, AllocationRoot string, allocationObj *Allocation) error { +func (r *Repository) UpdateAllocationRedeem(ctx context.Context, allocationID, AllocationRoot string, allocationObj *Allocation, redeemSeq int64) error { var tx = datastore.GetStore().GetTransaction(ctx) if tx == nil { logging.Logger.Panic("no transaction in the context") @@ -205,17 +205,20 @@ func (r *Repository) UpdateAllocationRedeem(ctx context.Context, allocationID, A allocationUpdates := make(map[string]interface{}) allocationUpdates["latest_redeemed_write_marker"] = AllocationRoot allocationUpdates["is_redeem_required"] = false + allocationUpdates["last_redeemed_sequence"] = redeemSeq err = tx.Model(allocationObj).Updates(allocationUpdates).Error if err != nil { return err } allocationObj.LatestRedeemedWM = AllocationRoot allocationObj.IsRedeemRequired = false + allocationObj.LastRedeemedSeq = redeemSeq txnCache := cache[allocationID] txnCache.Allocation = allocationObj updateAlloc := func(a *Allocation) { a.LatestRedeemedWM = AllocationRoot a.IsRedeemRequired = false + a.LastRedeemedSeq = redeemSeq } txnCache.AllocationUpdates = append(txnCache.AllocationUpdates, updateAlloc) cache[allocationID] = txnCache diff --git a/code/go/0chain.net/blobbercore/blobberhttp/response.go b/code/go/0chain.net/blobbercore/blobberhttp/response.go index 1790259e6..7bb0a707e 100644 --- a/code/go/0chain.net/blobbercore/blobberhttp/response.go +++ b/code/go/0chain.net/blobbercore/blobberhttp/response.go @@ -25,8 +25,7 @@ type CommitResult struct { // swagger:model ReferencePathResult type ReferencePathResult struct { *reference.ReferencePath - LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` - ChainData []byte `json:"chain_data"` + LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` } // swagger:model RefResult @@ -64,7 +63,6 @@ type DownloadResponse struct { } type LatestWriteMarkerResult struct { - LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` - PrevWM *writemarker.WriteMarker `json:"prev_write_marker"` - ChainData []byte `json:"chain_data"` + LatestWM *writemarker.WriteMarker `json:"latest_write_marker"` + PrevWM *writemarker.WriteMarker `json:"prev_write_marker"` } diff --git a/code/go/0chain.net/blobbercore/handler/handler_common.go b/code/go/0chain.net/blobbercore/handler/handler_common.go index 29010db82..16d5bd590 100644 --- a/code/go/0chain.net/blobbercore/handler/handler_common.go +++ b/code/go/0chain.net/blobbercore/handler/handler_common.go @@ -162,8 +162,6 @@ func WithStatusConnectionForWM(handler common.StatusCodeResponderF) common.Statu } else { Logger.Error("Invalid response type for commit handler") } - connectionID, _ := common.GetField(r, "connection_id") - writemarker.WriteMarkerMutext.Unlock(allocationID, connectionID) //nolint:errcheck return } } diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index 70d17d568..547155a16 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -497,6 +497,7 @@ func (fsh *StorageHandler) CreateConnection(ctx context.Context, r *http.Request } func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*blobberhttp.CommitResult, error) { + var prevChainHash string startTime := time.Now() if r.Method == "GET" { return nil, common.NewError("invalid_method", "Invalid method used for the upload URL. Use POST instead") @@ -602,12 +603,8 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b if latestWriteMarkerEntity.Status != writemarker.Committed { writeMarker.ChainLength = latestWriteMarkerEntity.WM.ChainLength - } else { - if writeMarker.ChainSize != connectionObj.Size { - return nil, common.NewErrorf("invalid_chain_size", - "Invalid chain size. expected:%v got %v", connectionObj.Size, writeMarker.ChainSize) - } } + prevChainHash = latestWriteMarkerEntity.WM.ChainHash } writemarkerEntity := &writemarker.WriteMarkerEntity{} @@ -681,10 +678,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) - if err != nil { - return nil, common.NewError("chain_hash_error", "Error calculating chain hash") - } + chainHash := writemarker.CalculateChainHash(prevChainHash, allocationRoot) if chainHash != writeMarker.ChainHash { return nil, common.NewError("chain_hash_mismatch", "Chain hash in the write marker does not match the calculated chain hash") } @@ -1438,11 +1432,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return &result, common.NewError("allocation_root_mismatch", result.ErrorMessage) } - chainHash, err := writemarker.CalculateChainHash(ctx, allocationObj.ID, allocationRoot) - if err != nil { - txn.Rollback() - return nil, common.NewError("chain_hash_error", "Error calculating chain hash "+err.Error()) - } + chainHash := writemarker.CalculateChainHash(latestWriteMarkerEntity.WM.ChainHash, allocationRoot) if chainHash != writeMarker.ChainHash { txn.Rollback() return nil, common.NewError("chain_hash_mismatch", "Chain hash in the write marker does not match the calculated chain hash") diff --git a/code/go/0chain.net/blobbercore/handler/storage_handler.go b/code/go/0chain.net/blobbercore/handler/storage_handler.go index 306e9925c..b49c9064b 100644 --- a/code/go/0chain.net/blobbercore/handler/storage_handler.go +++ b/code/go/0chain.net/blobbercore/handler/storage_handler.go @@ -472,14 +472,6 @@ func (fsh *StorageHandler) GetLatestWriteMarker(ctx context.Context, r *http.Req result.PrevWM = &prevWM.WM } - if _, ok := common.GetField(r, "chain_data"); ok { - chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) - if err != nil { - return nil, common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) - } - result.ChainData = chainData - } - return &result, nil } @@ -576,14 +568,6 @@ func (fsh *StorageHandler) getReferencePath(ctx context.Context, r *http.Request } refPathResult.LatestWM = &latestWM.WM } - if _, ok := common.GetField(r, "chain_data"); ok { - chainData, err := writemarker.GetMarkersForChain(ctx, allocationObj.ID) - if err != nil { - errCh <- common.NewError("markers_for_chain", "Error reading the chain data for allocation."+err.Error()) - return - } - refPathResult.ChainData = chainData - } resCh <- &refPathResult } diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index ff06c9bfa..776c08e61 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -10,25 +10,26 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/common" - "github.com/0chain/blobber/code/go/0chain.net/core/encryption" "github.com/0chain/blobber/code/go/0chain.net/core/logging" + "github.com/minio/sha256-simd" "go.uber.org/zap" "gorm.io/gorm" ) type WriteMarker struct { - AllocationRoot string `gorm:"column:allocation_root;size:64;primaryKey" json:"allocation_root"` - PreviousAllocationRoot string `gorm:"column:prev_allocation_root;size:64" json:"prev_allocation_root"` - FileMetaRoot string `gorm:"column:file_meta_root;size:64" json:"file_meta_root"` - AllocationID string `gorm:"column:allocation_id;size:64;index:idx_seq,unique,priority:1" json:"allocation_id"` - Size int64 `gorm:"column:size" json:"size"` - ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` - ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` - ChainLength int `gorm:"column:chain_length" json:"chain_length"` - BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` - Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` - ClientID string `gorm:"column:client_id;size:64" json:"client_id"` - Signature string `gorm:"column:signature;size:64" json:"signature"` + AllocationRoot string `gorm:"column:allocation_root;size:64;primaryKey" json:"allocation_root"` + PreviousAllocationRoot string `gorm:"column:prev_allocation_root;size:64" json:"prev_allocation_root"` + FileMetaRoot string `gorm:"column:file_meta_root;size:64" json:"file_meta_root"` + AllocationID string `gorm:"column:allocation_id;size:64;index:idx_seq,unique,priority:1" json:"allocation_id"` + Size int64 `gorm:"column:size" json:"size"` + ChainSize int64 `gorm:"column:chain_size" json:"chain_size"` + // ChainHash is the sha256 hash of the previous chain hash and the current allocation root + ChainHash string `gorm:"column:chain_hash;size:64" json:"chain_hash"` + ChainLength int `gorm:"column:chain_length" json:"chain_length"` + BlobberID string `gorm:"column:blobber_id;size:64" json:"blobber_id"` + Timestamp common.Timestamp `gorm:"column:timestamp;primaryKey" json:"timestamp"` + ClientID string `gorm:"column:client_id;size:64" json:"client_id"` + Signature string `gorm:"column:signature;size:64" json:"signature"` } func (wm *WriteMarker) GetHashData() string { @@ -84,7 +85,7 @@ func (w *WriteMarkerEntity) BeforeSave(tx *gorm.DB) error { return nil } -func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarkerStatus, statusMessage, redeemTxn string) (err error) { +func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarkerStatus, statusMessage, redeemTxn string, startSeq, endSeq int64) (err error) { err = datastore.GetStore().WithNewTransaction(func(ctx context.Context) error { db := datastore.GetStore().GetTransaction(ctx) statusBytes, _ := json.Marshal(statusMessage) @@ -111,6 +112,13 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke return err } + if status == Committed { + err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq).Error + if err != nil { + return err + } + } + // TODO (sfxdx): what about failed write markers ? if status != Committed || wm.WM.Size <= 0 { return err // not committed or a deleting marker @@ -258,28 +266,19 @@ func GetLatestCommittedWriteMarker(ctx context.Context, allocationID string) (*W return wm, nil } -func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error) { - commitedMarker, err := GetLatestCommittedWriteMarker(ctx, allocationID) - if err != nil { - return nil, err - } - var seq int64 - if commitedMarker != nil { - seq = commitedMarker.Sequence - } - unComittedMarkers, err := GetUncommittedWriteMarkers(ctx, allocationID, seq) - if err != nil { +func GetMarkersForChain(ctx context.Context, allocationID string, startSeq, endSeq int64) ([]byte, error) { + db := datastore.GetStore().GetTransaction(ctx) + + unCommittedMarkers := make([]*WriteMarkerEntity, 0) + err := db.Table((WriteMarkerEntity{}).TableName()). + Where("allocation_id=? AND status=0 AND sequence BETWEEN ? AND ?", allocationID, startSeq, endSeq). + Order("sequence asc"). + Find(&unCommittedMarkers).Error + if err != nil && err != gorm.ErrRecordNotFound { return nil, err } - markers := make([]byte, 0, len(unComittedMarkers)+1) - if commitedMarker != nil { - decodedHash, err := hex.DecodeString(commitedMarker.WM.AllocationRoot) - if err != nil { - return nil, err - } - markers = append(markers, decodedHash...) - } - for _, marker := range unComittedMarkers { + markers := make([]byte, 0, len(unCommittedMarkers)) + for _, marker := range unCommittedMarkers { decodedHash, err := hex.DecodeString(marker.WM.AllocationRoot) if err != nil { return nil, err @@ -289,17 +288,15 @@ func GetMarkersForChain(ctx context.Context, allocationID string) ([]byte, error return markers, nil } -func CalculateChainHash(ctx context.Context, allocationID, newRoot string) (string, error) { - prevRoots, err := GetMarkersForChain(ctx, allocationID) - if err != nil { - return "", err - } - decodedHash, err := hex.DecodeString(newRoot) - if err != nil { - return "", err +func CalculateChainHash(prevChainHash, newRoot string) string { + hasher := sha256.New() + if prevChainHash != "" { + prevBytes, _ := hex.DecodeString(prevChainHash) + hasher.Write(prevBytes) //nolint:errcheck } - prevRoots = append(prevRoots, decodedHash...) - return encryption.Hash(prevRoots), nil + newBytes, _ := hex.DecodeString(newRoot) + hasher.Write(newBytes) //nolint:errcheck + return hex.EncodeToString(hasher.Sum(nil)) } // client lock alloc -> commitMarker -> unlock alloc diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index d4e49a38e..819ccb249 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -111,14 +111,14 @@ func (wme *WriteMarkerEntity) VerifyMarker(ctx context.Context, dbAllocation *al return nil } -func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { +func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) error { if len(wme.CloseTxnID) > 0 { t, err := transaction.VerifyTransaction(wme.CloseTxnID, chain.GetServerChain()) if err == nil { wme.Status = Committed wme.StatusMessage = t.TransactionOutput wme.CloseTxnID = t.Hash - err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) + err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash, startSeq, wme.Sequence) return err } } @@ -126,7 +126,7 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { txn, err := transaction.NewTransactionEntity() if err != nil { wme.StatusMessage = "Error creating transaction entity. " + err.Error() - if err := wme.UpdateStatus(ctx, Failed, "Error creating transaction entity. "+err.Error(), ""); err != nil { + if err := wme.UpdateStatus(ctx, Failed, "Error creating transaction entity. "+err.Error(), "", startSeq, wme.Sequence); err != nil { Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) } return err @@ -137,12 +137,12 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { sn.PrevAllocationRoot = wme.WM.PreviousAllocationRoot sn.WriteMarker = &wme.WM err = datastore.GetStore().WithNewTransaction(func(ctx context.Context) error { - sn.ChainData, err = GetMarkersForChain(ctx, wme.WM.AllocationID) + sn.ChainData, err = GetMarkersForChain(ctx, wme.WM.AllocationID, startSeq, wme.Sequence-1) return err }) if err != nil { wme.StatusMessage = "Error getting chain data. " + err.Error() - if err := wme.UpdateStatus(ctx, Failed, "Error getting chain data. "+err.Error(), ""); err != nil { + if err := wme.UpdateStatus(ctx, Failed, "Error getting chain data. "+err.Error(), "", startSeq, wme.Sequence); err != nil { Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) } return err @@ -154,7 +154,7 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { prevWM, err = GetPreviousWM(ctx, sn.AllocationRoot, wme.WM.Timestamp) if err != nil { wme.StatusMessage = "Error getting previous write marker. " + err.Error() - if err := wme.UpdateStatus(ctx, Failed, "Error getting previous write marker. "+err.Error(), ""); err != nil { + if err := wme.UpdateStatus(ctx, Failed, "Error getting previous write marker. "+err.Error(), "", startSeq, wme.Sequence); err != nil { Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) } return err @@ -167,7 +167,7 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { Logger.Error("Failed during sending close connection to the miner. ", zap.String("err:", err.Error())) wme.Status = Failed wme.StatusMessage = "Failed during sending close connection to the miner. " + err.Error() - if err := wme.UpdateStatus(ctx, Failed, "Failed during sending close connection to the miner. "+err.Error(), ""); err != nil { + if err := wme.UpdateStatus(ctx, Failed, "Failed during sending close connection to the miner. "+err.Error(), "", startSeq, wme.Sequence); err != nil { Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) } return err @@ -182,14 +182,14 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error { wme.Status = Failed wme.StatusMessage = "Error verifying the close connection transaction." + err.Error() // TODO Is this single try? - if err := wme.UpdateStatus(ctx, Failed, "Error verifying the close connection transaction."+err.Error(), txn.Hash); err != nil { + if err := wme.UpdateStatus(ctx, Failed, "Error verifying the close connection transaction."+err.Error(), txn.Hash, startSeq, wme.Sequence); err != nil { Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) } return err } wme.Status = Committed wme.StatusMessage = t.TransactionOutput - err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash) + err = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash, startSeq, wme.Sequence) return err } diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol_main.go b/code/go/0chain.net/blobbercore/writemarker/protocol_main.go index 77b2ebcbb..3ba3db585 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol_main.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol_main.go @@ -5,6 +5,6 @@ package writemarker import "context" -func (wme *WriteMarkerEntity) RedeemMarker(ctx context.Context) error { - return wme.redeemMarker(ctx) +func (wme *WriteMarkerEntity) RedeemMarker(ctx context.Context, startSeq int64) error { + return wme.redeemMarker(ctx, startSeq) } diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index e3630f58e..309f36be2 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -109,19 +109,6 @@ func redeemWriteMarker(md *markerData) error { } }() - res, _ := WriteMarkerMutext.Lock(ctx, allocationID, MARKER_CONNECTION) - if res.Status != LockStatusOK { - logging.Logger.Error("Error redeeming the write marker. Lock failed", zap.String("allocationID", allocationID), zap.Any("status", res.Status)) - if common.Now()-md.firstMarkerTimestamp < 2*MAX_TIMESTAMP_GAP { - md.retries++ - go tryAgain(md) - shouldRollback = true - return nil - } - //Exceeded twice of max timestamp gap, can be a malicious client keeping the lock forever to block the redeem - } else { - defer WriteMarkerMutext.Unlock(allocationID, MARKER_CONNECTION) //nolint:errcheck - } allocMu := lock.GetMutex(allocation.Allocation{}.TableName(), allocationID) allocMu.RLock() defer allocMu.RUnlock() @@ -153,7 +140,7 @@ func redeemWriteMarker(md *markerData) error { return err } - err = wm.RedeemMarker(ctx) + err = wm.RedeemMarker(ctx, alloc.LastRedeemedSeq+1) if err != nil { elapsedTime := time.Since(start) logging.Logger.Error("Error redeeming the write marker.", @@ -165,14 +152,14 @@ func redeemWriteMarker(md *markerData) error { shouldRollback = true return err } - deleteMarkerData(allocationID) - err = allocation.Repo.UpdateAllocationRedeem(ctx, allocationID, wm.WM.AllocationRoot, alloc) + err = allocation.Repo.UpdateAllocationRedeem(ctx, allocationID, wm.WM.AllocationRoot, alloc, wm.Sequence) if err != nil { logging.Logger.Error("Error redeeming the write marker. Allocation latest wm redeemed update failed", zap.Any("allocation", allocationID), zap.Any("wm", wm.WM.AllocationRoot), zap.Any("error", err)) shouldRollback = true + go tryAgain(md) return err } @@ -182,6 +169,7 @@ func redeemWriteMarker(md *markerData) error { zap.Any("allocation", allocationID), zap.Any("wm", wm.WM.AllocationRoot), zap.Error(err)) shouldRollback = true + go tryAgain(md) return err } elapsedTime := time.Since(start) diff --git a/goose/migrations/1707996797_chain_wm.sql b/goose/migrations/1707996797_chain_wm.sql index fa2e8e180..f76f4a00b 100644 --- a/goose/migrations/1707996797_chain_wm.sql +++ b/goose/migrations/1707996797_chain_wm.sql @@ -4,4 +4,6 @@ ALTER TABLE write_markers ADD COLUMN chain_hash character varying(64), ADD COLUMN chain_size BIGINT, ADD COLUMN chain_length integer; + +ALTER TABLE allocations ADD COLUMN last_redeemed_sequence BIGINT DEFAULT 0; -- +goose StatementEnd \ No newline at end of file From be1740c812884f7f687bfb0911b1abe83b785c70 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sat, 17 Feb 2024 17:39:43 +0530 Subject: [PATCH 16/30] fix wm update --- code/go/0chain.net/blobbercore/writemarker/entity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 776c08e61..5578335cf 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -113,7 +113,7 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke } if status == Committed { - err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq).Error + err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq, wm.WM.AllocationID).Error if err != nil { return err } From 92ae4a2c48fee6d6aac3319fd8801f20b2e10078 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sun, 18 Feb 2024 15:29:13 +0530 Subject: [PATCH 17/30] add chain hash logs --- .../blobbercore/writemarker/protocol.go | 29 +++++++++++++++++++ .../blobbercore/writemarker/worker.go | 5 +++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index 819ccb249..ec63b138b 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -2,6 +2,7 @@ package writemarker import ( "context" + "encoding/hex" "fmt" "time" @@ -14,6 +15,7 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/core/node" "github.com/0chain/blobber/code/go/0chain.net/core/transaction" "github.com/0chain/gosdk/constants" + "github.com/minio/sha256-simd" "go.uber.org/zap" ) @@ -148,6 +150,33 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) return err } + commitedMarker, err := GetLatestCommittedWriteMarker(ctx, wme.WM.AllocationID) + if err != nil { + return err + } + if commitedMarker != nil { + hasher := sha256.New() + prevChainHash, _ := hex.DecodeString(commitedMarker.WM.ChainHash) + hasher.Write(prevChainHash) + for i := 0; i < len(sn.ChainData); i += 32 { + hasher.Write(sn.ChainData[i : i+32]) + sum := hasher.Sum(nil) + hasher.Reset() + hasher.Write(sum) + } + rootBytes, _ := hex.DecodeString(wme.WM.AllocationRoot) + hasher.Write(rootBytes) + hash := hex.EncodeToString(hasher.Sum(nil)) + if hash != wme.WM.ChainHash { + Logger.Error("chain_hash_mismatch", zap.String("hash", hash), zap.String("wm_chain_hash", wme.WM.ChainHash)) + wme.StatusMessage = "Chain hash does not match. " + err.Error() + if err := wme.UpdateStatus(ctx, Failed, "Chain hash does not match. "+err.Error(), "", startSeq, wme.Sequence); err != nil { + Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) + } + return common.NewError("chain_hash_mismatch", "Chain hash does not match") + } + } + if sn.AllocationRoot == sn.PrevAllocationRoot { // get nonce of prev WM var prevWM *WriteMarkerEntity diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 309f36be2..7991837ea 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -148,6 +148,8 @@ func redeemWriteMarker(md *markerData) error { zap.Any("wm", wm), zap.Any("error", err), zap.Any("elapsedTime", elapsedTime)) if retryRedeem(err.Error()) { go tryAgain(md) + } else { + deleteMarkerData(allocationID) } shouldRollback = true return err @@ -218,13 +220,14 @@ func startRedeem(ctx context.Context, res []allocation.Res) { } func tryAgain(md *markerData) { + md.retries++ time.Sleep(time.Duration(md.retries) * 5 * time.Second) writeMarkerChan <- md } // Can add more cases where we don't want to retry func retryRedeem(errString string) bool { - return !strings.Contains(errString, "value not present") + return !strings.Contains(errString, "value not present") || !strings.Contains(errString, "Blobber is not part of the allocation") } func startCollector(ctx context.Context) { From 734ff94b2a0ec39849ef5b90fafc33fa40b1fe81 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sun, 18 Feb 2024 15:50:35 +0530 Subject: [PATCH 18/30] add chain lenght logs --- code/go/0chain.net/blobbercore/writemarker/protocol.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index ec63b138b..6c0f3882f 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -150,6 +150,8 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) return err } + Logger.Info("redeem_marker_chain", zap.String("allocation_id", wme.WM.AllocationID), zap.Int("chain_data_length", len(sn.ChainData)), zap.Int("chain_length", wme.WM.ChainLength)) + commitedMarker, err := GetLatestCommittedWriteMarker(ctx, wme.WM.AllocationID) if err != nil { return err @@ -175,6 +177,8 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) } return common.NewError("chain_hash_mismatch", "Chain hash does not match") } + } else { + Logger.Info("no_committed_marker", zap.String("allocation_id", wme.WM.AllocationID)) } if sn.AllocationRoot == sn.PrevAllocationRoot { From 861f741e35cf11d166c3f3d8aefc7551c2c0dfc3 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Mon, 19 Feb 2024 13:07:35 +0530 Subject: [PATCH 19/30] add commit log --- code/go/0chain.net/blobbercore/writemarker/protocol.go | 1 + 1 file changed, 1 insertion(+) diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index 6c0f3882f..1db671005 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -157,6 +157,7 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) return err } if commitedMarker != nil { + Logger.Info("committed_marker", zap.String("allocation_id", wme.WM.AllocationID), zap.String("chain_hash", commitedMarker.WM.ChainHash)) hasher := sha256.New() prevChainHash, _ := hex.DecodeString(commitedMarker.WM.ChainHash) hasher.Write(prevChainHash) From 6a4a4c8ce7330d8755bf26021415c7281622066d Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Mon, 19 Feb 2024 19:17:12 +0530 Subject: [PATCH 20/30] Revert "fix wm update" This reverts commit be1740c812884f7f687bfb0911b1abe83b785c70. --- code/go/0chain.net/blobbercore/writemarker/entity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 5578335cf..776c08e61 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -113,7 +113,7 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke } if status == Committed { - err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq, wm.WM.AllocationID).Error + err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq).Error if err != nil { return err } From fc1c11f5e0b925321e752ba06b411c0556cbb4dc Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Mon, 19 Feb 2024 19:19:41 +0530 Subject: [PATCH 21/30] revert commit marker logs --- .../blobbercore/writemarker/entity.go | 2 +- .../blobbercore/writemarker/protocol.go | 34 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 776c08e61..5578335cf 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -113,7 +113,7 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke } if status == Committed { - err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq).Error + err = db.Exec("UPDATE write_markers SET status=1 WHERE sequence BETWEEN ? AND ? AND allocation_id = ?", startSeq, endSeq, wm.WM.AllocationID).Error if err != nil { return err } diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol.go b/code/go/0chain.net/blobbercore/writemarker/protocol.go index 1db671005..819ccb249 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol.go @@ -2,7 +2,6 @@ package writemarker import ( "context" - "encoding/hex" "fmt" "time" @@ -15,7 +14,6 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/core/node" "github.com/0chain/blobber/code/go/0chain.net/core/transaction" "github.com/0chain/gosdk/constants" - "github.com/minio/sha256-simd" "go.uber.org/zap" ) @@ -150,38 +148,6 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context, startSeq int64) return err } - Logger.Info("redeem_marker_chain", zap.String("allocation_id", wme.WM.AllocationID), zap.Int("chain_data_length", len(sn.ChainData)), zap.Int("chain_length", wme.WM.ChainLength)) - - commitedMarker, err := GetLatestCommittedWriteMarker(ctx, wme.WM.AllocationID) - if err != nil { - return err - } - if commitedMarker != nil { - Logger.Info("committed_marker", zap.String("allocation_id", wme.WM.AllocationID), zap.String("chain_hash", commitedMarker.WM.ChainHash)) - hasher := sha256.New() - prevChainHash, _ := hex.DecodeString(commitedMarker.WM.ChainHash) - hasher.Write(prevChainHash) - for i := 0; i < len(sn.ChainData); i += 32 { - hasher.Write(sn.ChainData[i : i+32]) - sum := hasher.Sum(nil) - hasher.Reset() - hasher.Write(sum) - } - rootBytes, _ := hex.DecodeString(wme.WM.AllocationRoot) - hasher.Write(rootBytes) - hash := hex.EncodeToString(hasher.Sum(nil)) - if hash != wme.WM.ChainHash { - Logger.Error("chain_hash_mismatch", zap.String("hash", hash), zap.String("wm_chain_hash", wme.WM.ChainHash)) - wme.StatusMessage = "Chain hash does not match. " + err.Error() - if err := wme.UpdateStatus(ctx, Failed, "Chain hash does not match. "+err.Error(), "", startSeq, wme.Sequence); err != nil { - Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err)) - } - return common.NewError("chain_hash_mismatch", "Chain hash does not match") - } - } else { - Logger.Info("no_committed_marker", zap.String("allocation_id", wme.WM.AllocationID)) - } - if sn.AllocationRoot == sn.PrevAllocationRoot { // get nonce of prev WM var prevWM *WriteMarkerEntity From f88bf2ab75a1e44133e3e6876875da94d123a3b0 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Tue, 20 Feb 2024 00:42:55 +0530 Subject: [PATCH 22/30] move chain values to config --- code/go/0chain.net/blobbercore/config/config.go | 9 +++++++++ .../handler/object_operation_handler.go | 4 ++-- .../blobbercore/writemarker/entity.go | 6 ------ .../writemarker/protocol_integration_tests.go | 4 ++-- .../blobbercore/writemarker/worker.go | 17 +++++++++++++---- .../storage/writemarker/entity_test.go | 4 +++- config/0chain_blobber.yaml | 3 +++ 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/code/go/0chain.net/blobbercore/config/config.go b/code/go/0chain.net/blobbercore/config/config.go index 71fa74014..3cef13b2d 100644 --- a/code/go/0chain.net/blobbercore/config/config.go +++ b/code/go/0chain.net/blobbercore/config/config.go @@ -19,6 +19,9 @@ func SetupDefaultConfig() { viper.SetDefault("openconnection_cleaner.frequency", 30) viper.SetDefault("writemarker_redeem.frequency", 10) viper.SetDefault("writemarker_redeem.num_workers", 5) + viper.SetDefault("writemarker_redeem.max_chain_length", 32) + viper.SetDefault("writemarker_redeem.max_timestamp_gap", 1800) + viper.SetDefault("writemarker_redeem.marker_redeem_interval", time.Minute*10) viper.SetDefault("readmarker_redeem.frequency", 10) viper.SetDefault("readmarker_redeem.num_workers", 5) viper.SetDefault("challenge_response.frequency", 10) @@ -100,6 +103,9 @@ type Config struct { OpenConnectionWorkerTolerance int64 WMRedeemFreq int64 WMRedeemNumWorkers int + MaxChainLength int + MaxTimestampGap int64 + MarkerRedeemInterval time.Duration RMRedeemFreq int64 RMRedeemNumWorkers int ChallengeResolveFreq int64 @@ -218,6 +224,9 @@ func ReadConfig(deploymentMode int) { Configuration.WMRedeemFreq = viper.GetInt64("writemarker_redeem.frequency") Configuration.WMRedeemNumWorkers = viper.GetInt("writemarker_redeem.num_workers") + Configuration.MaxChainLength = viper.GetInt("writemarker_redeem.max_chain_length") + Configuration.MaxTimestampGap = viper.GetInt64("writemarker_redeem.max_timestamp_gap") + Configuration.MarkerRedeemInterval = viper.GetDuration("writemarker_redeem.marker_redeem_interval") Configuration.RMRedeemFreq = viper.GetInt64("readmarker_redeem.frequency") Configuration.RMRedeemNumWorkers = viper.GetInt("readmarker_redeem.num_workers") diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index 547155a16..ae3be725e 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -697,7 +697,7 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b writemarkerEntity.ConnectionID = connectionObj.ID writemarkerEntity.ClientPublicKey = clientKey writemarkerEntity.WM.ChainLength += 1 - if writemarkerEntity.WM.ChainLength > writemarker.MAX_CHAIN_LENGTH { + if writemarkerEntity.WM.ChainLength > config.Configuration.MaxChainLength { return nil, common.NewError("chain_length_exceeded", "Chain length exceeded") } @@ -1383,7 +1383,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob return nil, common.NewError("write_marker_verification_failed", "Verification of the write marker failed: "+err.Error()) } - if writemarkerEntity.WM.ChainLength > writemarker.MAX_CHAIN_LENGTH { + if writemarkerEntity.WM.ChainLength > config.Configuration.MaxChainLength { return nil, common.NewError("chain_length_exceeded", "Chain length exceeded") } diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 5578335cf..8cdab2031 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -49,12 +49,6 @@ const ( Rollbacked WriteMarkerStatus = 3 ) -const ( - MAX_CHAIN_LENGTH = 3 - MAX_TIMESTAMP_GAP = 60 * 30 // 30 minutes - MARKER_CONNECTION = "marker_connection" -) - type WriteMarkerEntity struct { // WM new WriteMarker from client WM WriteMarker `gorm:"embedded"` diff --git a/code/go/0chain.net/blobbercore/writemarker/protocol_integration_tests.go b/code/go/0chain.net/blobbercore/writemarker/protocol_integration_tests.go index 7f284eb49..79e70e74d 100644 --- a/code/go/0chain.net/blobbercore/writemarker/protocol_integration_tests.go +++ b/code/go/0chain.net/blobbercore/writemarker/protocol_integration_tests.go @@ -11,7 +11,7 @@ import ( "github.com/0chain/blobber/code/go/0chain.net/core/node" ) -func (wme *WriteMarkerEntity) RedeemMarker(ctx context.Context) error { +func (wme *WriteMarkerEntity) RedeemMarker(ctx context.Context, startSeq int64) error { for { state := conductrpc.Client().State() if state.StopWMCommit != nil && *state.StopWMCommit { @@ -20,7 +20,7 @@ func (wme *WriteMarkerEntity) RedeemMarker(ctx context.Context) error { } break } - err := wme.redeemMarker(ctx) + err := wme.redeemMarker(ctx, startSeq) if err == nil { // send state to conductor server conductrpc.Client().BlobberCommitted(node.Self.ID) diff --git a/code/go/0chain.net/blobbercore/writemarker/worker.go b/code/go/0chain.net/blobbercore/writemarker/worker.go index 7991837ea..4c8a63ae9 100644 --- a/code/go/0chain.net/blobbercore/writemarker/worker.go +++ b/code/go/0chain.net/blobbercore/writemarker/worker.go @@ -7,6 +7,7 @@ import ( "time" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation" + "github.com/0chain/blobber/code/go/0chain.net/blobbercore/config" "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" "github.com/0chain/blobber/code/go/0chain.net/core/common" "github.com/0chain/blobber/code/go/0chain.net/core/lock" @@ -44,7 +45,7 @@ func SaveMarkerData(allocationID string, timestamp common.Timestamp, chainLength if data.chainLength == 1 { data.firstMarkerTimestamp = timestamp } - if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + if data.processMarker() { logging.Logger.Info("ProcessMarkerData", zap.Any("allocationID", allocationID), zap.Any("timestamp", timestamp), zap.Any("chainLength", chainLength)) data.processing = true writeMarkerChan <- data @@ -184,7 +185,11 @@ func redeemWriteMarker(md *markerData) error { func startRedeem(ctx context.Context, res []allocation.Res) { logging.Logger.Info("Start redeeming writemarkers") - writeMarkerChan = make(chan *markerData, 200) + chanSize := 200 + if len(res) > chanSize { + chanSize = len(res) + } + writeMarkerChan = make(chan *markerData, chanSize) go startRedeemWorker(ctx) markerDataMut.Lock() defer markerDataMut.Unlock() @@ -231,7 +236,7 @@ func retryRedeem(errString string) bool { } func startCollector(ctx context.Context) { - ticker := time.NewTicker(10 * time.Minute) + ticker := time.NewTicker(config.Configuration.MarkerRedeemInterval) defer ticker.Stop() for { select { @@ -240,7 +245,7 @@ func startCollector(ctx context.Context) { case <-ticker.C: markerDataMut.Lock() for _, data := range markerDataMap { - if !data.processing && (data.chainLength == MAX_CHAIN_LENGTH || common.Now()-data.firstMarkerTimestamp > MAX_TIMESTAMP_GAP) { + if data.processMarker() { logging.Logger.Info("ProcessMarkerData", zap.Any("allocationID", data.allocationID), zap.Any("timestamp", data.firstMarkerTimestamp), zap.Any("chainLength", data.chainLength)) data.processing = true writeMarkerChan <- data @@ -251,6 +256,10 @@ func startCollector(ctx context.Context) { } } +func (md *markerData) processMarker() bool { + return !md.processing && (md.chainLength >= config.Configuration.MaxChainLength || common.Now()-md.firstMarkerTimestamp > common.Timestamp(config.Configuration.MaxTimestampGap)) +} + // TODO: don't delete prev WM // func startCleanupWorker(ctx context.Context) { // for { diff --git a/code/go/0chain.net/validatorcore/storage/writemarker/entity_test.go b/code/go/0chain.net/validatorcore/storage/writemarker/entity_test.go index 7b3248c1e..7f02f46a1 100644 --- a/code/go/0chain.net/validatorcore/storage/writemarker/entity_test.go +++ b/code/go/0chain.net/validatorcore/storage/writemarker/entity_test.go @@ -18,7 +18,7 @@ func TestWriteMarker_GetHashData(t *testing.T) { wm, wallet, err := setupEntityTest(t) require.NoError(t, err) - want := fmt.Sprintf("%v:%v:%v:%v:%v:%v:%v:%v", "alloc_root", "prev_alloc_root", "file_meta_root", "alloc_id", "blobber_id", wallet.ClientID, 1, wm.Timestamp) + want := fmt.Sprintf("%v:%v:%v:%v:%v:%v:%v:%v:%v:%v", "alloc_root", "prev_alloc_root", "file_meta_root", "chain_hash", "alloc_id", "blobber_id", wallet.ClientID, 1, 1, wm.Timestamp) got := wm.GetHashData() t.Logf("Want: %s. Got: %s", want, got) assert.Equal(t, want, got) @@ -120,6 +120,8 @@ func setupEntityTest(t *testing.T) (*writemarker.WriteMarker, *zcncrypto.Wallet, Size: int64(1), BlobberID: "blobber_id", Timestamp: common.Now(), + ChainHash: "chain_hash", + ChainSize: int64(1), } // TODO: why the config param is not used here? diff --git a/config/0chain_blobber.yaml b/config/0chain_blobber.yaml index 1fc371fd5..eac82db9c 100755 --- a/config/0chain_blobber.yaml +++ b/config/0chain_blobber.yaml @@ -96,6 +96,9 @@ openconnection_cleaner: writemarker_redeem: frequency: 10 num_workers: 5 + max_chain_length: 32 + max_timestamp_gap: 1800 # max timestamp gap to redeem write marker in seconds + marker_redeem_interval: 10m # interval to check for write markers which are ready to redeem readmarker_redeem: frequency: 10 num_workers: 5 From 09eddac252be75638d17bd1e6aa65c6e60ca55e0 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Fri, 23 Feb 2024 12:34:15 +0530 Subject: [PATCH 23/30] add support for old wm in validators --- .../0chain.net/blobbercore/writemarker/entity.go | 3 --- .../validatorcore/storage/writemarker/entity.go | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/code/go/0chain.net/blobbercore/writemarker/entity.go b/code/go/0chain.net/blobbercore/writemarker/entity.go index 8cdab2031..b8495b64b 100644 --- a/code/go/0chain.net/blobbercore/writemarker/entity.go +++ b/code/go/0chain.net/blobbercore/writemarker/entity.go @@ -292,6 +292,3 @@ func CalculateChainHash(prevChainHash, newRoot string) string { hasher.Write(newBytes) //nolint:errcheck return hex.EncodeToString(hasher.Sum(nil)) } - -// client lock alloc -> commitMarker -> unlock alloc -// don't want the worker to kick in between these steps, once alloc is unlocked, worker can pick it up diff --git a/code/go/0chain.net/validatorcore/storage/writemarker/entity.go b/code/go/0chain.net/validatorcore/storage/writemarker/entity.go index 2942b1561..22de899a2 100644 --- a/code/go/0chain.net/validatorcore/storage/writemarker/entity.go +++ b/code/go/0chain.net/validatorcore/storage/writemarker/entity.go @@ -28,10 +28,18 @@ type WriteMarker struct { } func (wm *WriteMarker) GetHashData() string { - hashData := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%d:%d:%d", - wm.AllocationRoot, wm.PreviousAllocationRoot, - wm.FileMetaRoot, wm.ChainHash, wm.AllocationID, wm.BlobberID, - wm.ClientID, wm.Size, wm.ChainSize, wm.Timestamp) + var hashData string + if wm.ChainHash != "" { + hashData = fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%d:%d:%d", + wm.AllocationRoot, wm.PreviousAllocationRoot, + wm.FileMetaRoot, wm.ChainHash, wm.AllocationID, wm.BlobberID, + wm.ClientID, wm.Size, wm.ChainSize, wm.Timestamp) + } else { + hashData = fmt.Sprintf("%s:%s:%s:%s:%s:%s:%d:%d", + wm.AllocationRoot, wm.PreviousAllocationRoot, + wm.FileMetaRoot, wm.AllocationID, wm.BlobberID, + wm.ClientID, wm.Size, wm.Timestamp) + } return hashData } From 9799a55b00a796e3b44cb4d67668dd5c2802cd5b Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sat, 24 Feb 2024 01:44:01 +0530 Subject: [PATCH 24/30] make data size optional --- .../blobbercore/filestore/tree_validation.go | 2 +- .../handler/file_command_update.go | 4 - .../handler/file_command_upload.go | 3 - .../object_operation_handler_bench_test.go | 382 +++++++++--------- .../seqpriorityqueue/seqpriorityqueue.go | 4 +- go.mod | 10 +- go.sum | 26 +- 7 files changed, 220 insertions(+), 211 deletions(-) diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation.go b/code/go/0chain.net/blobbercore/filestore/tree_validation.go index e1e667144..84e86876f 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation.go @@ -443,7 +443,7 @@ func (c *CommitHasher) Start(ctx context.Context, connID, allocID, fileName, fil default: } pq := seqPQ.Popup() - if pq.Offset+pq.DataBytes == c.dataSize { + if pq.Offset+pq.DataBytes == c.dataSize || pq.IsFinal { // If dataBytes and offset is equal to data size then it is the last data to be read from the file or context is cancelled // Check if ctx is done select { diff --git a/code/go/0chain.net/blobbercore/handler/file_command_update.go b/code/go/0chain.net/blobbercore/handler/file_command_update.go index b0676cac0..2f90992b5 100644 --- a/code/go/0chain.net/blobbercore/handler/file_command_update.go +++ b/code/go/0chain.net/blobbercore/handler/file_command_update.go @@ -112,10 +112,6 @@ func (cmd *UpdateFileCommand) ProcessContent(allocationObj *allocation.Allocatio result.Filename = cmd.fileChanger.Filename defer cmd.contentFile.Close() - if cmd.fileChanger.Size == 0 { - return result, common.NewError("invalid_parameters", "Invalid parameters. Size cannot be zero") - } - filePathHash := cmd.fileChanger.PathHash connID := cmd.fileChanger.ConnectionID diff --git a/code/go/0chain.net/blobbercore/handler/file_command_upload.go b/code/go/0chain.net/blobbercore/handler/file_command_upload.go index 100893af4..ac8e254a0 100644 --- a/code/go/0chain.net/blobbercore/handler/file_command_upload.go +++ b/code/go/0chain.net/blobbercore/handler/file_command_upload.go @@ -127,9 +127,6 @@ func (cmd *UploadFileCommand) ProcessContent(allocationObj *allocation.Allocatio defer cmd.contentFile.Close() connectionID := cmd.fileChanger.ConnectionID - if cmd.fileChanger.Size == 0 { - return result, common.NewError("invalid_parameters", "Invalid parameters. Size cannot be zero") - } fileInputData := &filestore.FileInputData{ Name: cmd.fileChanger.Filename, diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler_bench_test.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler_bench_test.go index dfef4f0f1..adcb74109 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler_bench_test.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler_bench_test.go @@ -1,193 +1,193 @@ package handler -import ( - "context" - "net/http" - "strconv" - "strings" - "testing" - "time" - - "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" - "github.com/0chain/blobber/code/go/0chain.net/blobbercore/filestore" - "github.com/0chain/blobber/code/go/0chain.net/blobbercore/mock" - "github.com/0chain/gosdk/zboxcore/sdk" -) - -func BenchmarkUploadFileWithDisk(b *testing.B) { - KB := 1024 - MB := 1024 * KB - //GB := 1024 * MB - - datastore.UseMocket(false) - blobber := mock.NewBlobberClient() - - allocationID := "benchmark_uploadfile" - - allocation := map[string]interface{}{ - "id": allocationID, - "tx": allocationID, - "size": 1024 * 1024 * 100, - "blobber_size": 1024 * 1024 * 1000, - "owner_id": blobber.ClientID, - "owner_public_key": blobber.Wallet.Keys[0].PublicKey, - "expiration_date": time.Now().Add(24 * time.Hour).Unix(), - } - - mock.MockGetAllocationByID(allocationID, allocation) - - formBuilder := sdk.CreateChunkedUploadFormBuilder() - - var storageHandler StorageHandler - - benchmarks := []struct { - Name string - // Size int - ChunkSize int - }{ - {Name: "64K", ChunkSize: 64 * KB}, - {Name: "640K", ChunkSize: 640 * KB}, - {Name: "6M", ChunkSize: 6 * MB}, - {Name: "60M", ChunkSize: 60 * MB}, - } - - for _, bm := range benchmarks { - b.Run(bm.Name, func(b *testing.B) { - fileName := strings.Replace(bm.Name, " ", "_", -1) + ".txt" - chunkBytes := mock.GenerateRandomBytes(bm.ChunkSize) - fileMeta := &sdk.FileMeta{ - Path: "/tmp/" + fileName, - ActualSize: int64(bm.ChunkSize), - - MimeType: "plain/text", - RemoteName: fileName, - RemotePath: "/" + fileName, - } - - hasher := sdk.CreateHasher(int64(bm.ChunkSize)) - isFinal := false - - body, formData, _ := formBuilder.Build(fileMeta, hasher, strconv.FormatInt(time.Now().UnixNano(), 10), int64(bm.ChunkSize), 0, 0, isFinal, "", "", [][]byte{chunkBytes}, nil, 0) - - req, err := blobber.NewRequest(http.MethodPost, "http://127.0.0.1:5051/v1/file/upload/benchmark_upload", body) - - if err != nil { - b.Fatal(err) - return - } - - req.Header.Set("Content-Type", formData.ContentType) - err = blobber.SignRequest(req, allocationID) - if err != nil { - b.Fatal(err) - return - } - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - ctx := GetMetaDataStore().CreateTransaction(context.TODO()) - ctx = mock.SetupHandlerContext(ctx, req, allocationID) - _, err := storageHandler.WriteFile(ctx, req) - - if err != nil { - b.Fatal(err) - return - } - } - }) - } -} - -func BenchmarkUploadFileWithNoDisk(b *testing.B) { - KB := 1024 - MB := 1024 * KB - //GB := 1024 * MB - - datastore.UseMocket(false) - // filestore.UseMock(nil) - fs := &filestore.MockStore{} - err := fs.Initialize() - if err != nil { - b.Fatal("Failed to initialize mock store") - } - filestore.SetFileStore(fs) - - blobber := mock.NewBlobberClient() - - allocationID := "benchmark_uploadfile" - - allocation := map[string]interface{}{ - "id": allocationID, - "tx": allocationID, - "size": 1024 * 1024 * 100, - "blobber_size": 1024 * 1024 * 1000, - "owner_id": blobber.ClientID, - "owner_public_key": blobber.Wallet.Keys[0].PublicKey, - "expiration_date": time.Now().Add(24 * time.Hour).Unix(), - } - - mock.MockGetAllocationByID(allocationID, allocation) - - formBuilder := sdk.CreateChunkedUploadFormBuilder() - - var storageHandler StorageHandler - - benchmarks := []struct { - Name string - // Size int - ChunkSize int - }{ - {Name: "64K", ChunkSize: 64 * KB}, - {Name: "640K", ChunkSize: 640 * KB}, - {Name: "6M", ChunkSize: 6 * MB}, - {Name: "60M", ChunkSize: 60 * MB}, - } - - for _, bm := range benchmarks { - b.Run(bm.Name, func(b *testing.B) { - fileName := strings.Replace(bm.Name, " ", "_", -1) + ".txt" - chunkBytes := mock.GenerateRandomBytes(bm.ChunkSize) - fileMeta := &sdk.FileMeta{ - Path: "/tmp/" + fileName, - ActualSize: int64(bm.ChunkSize), - - MimeType: "plain/text", - RemoteName: fileName, - RemotePath: "/" + fileName, - } - - hasher := sdk.CreateHasher(int64(bm.ChunkSize)) - isFinal := false - - body, formData, _ := formBuilder.Build(fileMeta, hasher, strconv.FormatInt(time.Now().UnixNano(), 10), int64(bm.ChunkSize), 0, 0, isFinal, "", "", [][]byte{chunkBytes}, nil, 0) - - req, err := blobber.NewRequest(http.MethodPost, "http://127.0.0.1:5051/v1/file/upload/benchmark_upload", body) - - if err != nil { - b.Fatal(err) - return - } - - req.Header.Set("Content-Type", formData.ContentType) - err = blobber.SignRequest(req, allocationID) - if err != nil { - b.Fatal(err) - return - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ctx := GetMetaDataStore().CreateTransaction(context.TODO()) - - ctx = mock.SetupHandlerContext(ctx, req, allocationID) - _, err := storageHandler.WriteFile(ctx, req) - - if err != nil { - b.Fatal(err) - return - } - } - }) - } -} +// import ( +// "context" +// "net/http" +// "strconv" +// "strings" +// "testing" +// "time" + +// "github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore" +// "github.com/0chain/blobber/code/go/0chain.net/blobbercore/filestore" +// "github.com/0chain/blobber/code/go/0chain.net/blobbercore/mock" +// "github.com/0chain/gosdk/zboxcore/sdk" +// ) + +// func BenchmarkUploadFileWithDisk(b *testing.B) { +// KB := 1024 +// MB := 1024 * KB +// //GB := 1024 * MB + +// datastore.UseMocket(false) +// blobber := mock.NewBlobberClient() + +// allocationID := "benchmark_uploadfile" + +// allocation := map[string]interface{}{ +// "id": allocationID, +// "tx": allocationID, +// "size": 1024 * 1024 * 100, +// "blobber_size": 1024 * 1024 * 1000, +// "owner_id": blobber.ClientID, +// "owner_public_key": blobber.Wallet.Keys[0].PublicKey, +// "expiration_date": time.Now().Add(24 * time.Hour).Unix(), +// } + +// mock.MockGetAllocationByID(allocationID, allocation) + +// formBuilder := sdk.CreateChunkedUploadFormBuilder() + +// var storageHandler StorageHandler + +// benchmarks := []struct { +// Name string +// // Size int +// ChunkSize int +// }{ +// {Name: "64K", ChunkSize: 64 * KB}, +// {Name: "640K", ChunkSize: 640 * KB}, +// {Name: "6M", ChunkSize: 6 * MB}, +// {Name: "60M", ChunkSize: 60 * MB}, +// } + +// for _, bm := range benchmarks { +// b.Run(bm.Name, func(b *testing.B) { +// fileName := strings.Replace(bm.Name, " ", "_", -1) + ".txt" +// chunkBytes := mock.GenerateRandomBytes(bm.ChunkSize) +// fileMeta := &sdk.FileMeta{ +// Path: "/tmp/" + fileName, +// ActualSize: int64(bm.ChunkSize), + +// MimeType: "plain/text", +// RemoteName: fileName, +// RemotePath: "/" + fileName, +// } + +// hasher := sdk.CreateHasher(int64(bm.ChunkSize)) +// isFinal := false + +// body, formData, _ := formBuilder.Build(fileMeta, hasher, strconv.FormatInt(time.Now().UnixNano(), 10), int64(bm.ChunkSize), 0, 0, isFinal, "", "", [][]byte{chunkBytes}, nil, 0) + +// req, err := blobber.NewRequest(http.MethodPost, "http://127.0.0.1:5051/v1/file/upload/benchmark_upload", body) + +// if err != nil { +// b.Fatal(err) +// return +// } + +// req.Header.Set("Content-Type", formData.ContentType) +// err = blobber.SignRequest(req, allocationID) +// if err != nil { +// b.Fatal(err) +// return +// } + +// b.ResetTimer() + +// for i := 0; i < b.N; i++ { +// ctx := GetMetaDataStore().CreateTransaction(context.TODO()) +// ctx = mock.SetupHandlerContext(ctx, req, allocationID) +// _, err := storageHandler.WriteFile(ctx, req) + +// if err != nil { +// b.Fatal(err) +// return +// } +// } +// }) +// } +// } + +// func BenchmarkUploadFileWithNoDisk(b *testing.B) { +// KB := 1024 +// MB := 1024 * KB +// //GB := 1024 * MB + +// datastore.UseMocket(false) +// // filestore.UseMock(nil) +// fs := &filestore.MockStore{} +// err := fs.Initialize() +// if err != nil { +// b.Fatal("Failed to initialize mock store") +// } +// filestore.SetFileStore(fs) + +// blobber := mock.NewBlobberClient() + +// allocationID := "benchmark_uploadfile" + +// allocation := map[string]interface{}{ +// "id": allocationID, +// "tx": allocationID, +// "size": 1024 * 1024 * 100, +// "blobber_size": 1024 * 1024 * 1000, +// "owner_id": blobber.ClientID, +// "owner_public_key": blobber.Wallet.Keys[0].PublicKey, +// "expiration_date": time.Now().Add(24 * time.Hour).Unix(), +// } + +// mock.MockGetAllocationByID(allocationID, allocation) + +// formBuilder := sdk.CreateChunkedUploadFormBuilder() + +// var storageHandler StorageHandler + +// benchmarks := []struct { +// Name string +// // Size int +// ChunkSize int +// }{ +// {Name: "64K", ChunkSize: 64 * KB}, +// {Name: "640K", ChunkSize: 640 * KB}, +// {Name: "6M", ChunkSize: 6 * MB}, +// {Name: "60M", ChunkSize: 60 * MB}, +// } + +// for _, bm := range benchmarks { +// b.Run(bm.Name, func(b *testing.B) { +// fileName := strings.Replace(bm.Name, " ", "_", -1) + ".txt" +// chunkBytes := mock.GenerateRandomBytes(bm.ChunkSize) +// fileMeta := &sdk.FileMeta{ +// Path: "/tmp/" + fileName, +// ActualSize: int64(bm.ChunkSize), + +// MimeType: "plain/text", +// RemoteName: fileName, +// RemotePath: "/" + fileName, +// } + +// hasher := sdk.CreateHasher(int64(bm.ChunkSize)) +// isFinal := false + +// body, formData, _ := formBuilder.Build(fileMeta, hasher, strconv.FormatInt(time.Now().UnixNano(), 10), int64(bm.ChunkSize), 0, 0, isFinal, "", "", [][]byte{chunkBytes}, nil, 0) + +// req, err := blobber.NewRequest(http.MethodPost, "http://127.0.0.1:5051/v1/file/upload/benchmark_upload", body) + +// if err != nil { +// b.Fatal(err) +// return +// } + +// req.Header.Set("Content-Type", formData.ContentType) +// err = blobber.SignRequest(req, allocationID) +// if err != nil { +// b.Fatal(err) +// return +// } + +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// ctx := GetMetaDataStore().CreateTransaction(context.TODO()) + +// ctx = mock.SetupHandlerContext(ctx, req, allocationID) +// _, err := storageHandler.WriteFile(ctx, req) + +// if err != nil { +// b.Fatal(err) +// return +// } +// } +// }) +// } +// } diff --git a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go index 84727979e..9d13374c6 100644 --- a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go +++ b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go @@ -8,6 +8,7 @@ import ( type UploadData struct { Offset int64 DataBytes int64 + IsFinal bool } type queue []UploadData @@ -81,7 +82,7 @@ func (pq *SeqPriorityQueue) Popup() UploadData { for pq.queue.Len() == 0 && !pq.done || (pq.queue.Len() > 0 && pq.queue[0].Offset != pq.next) { pq.cv.Wait() } - if pq.done { + if pq.done && pq.dataSize > 0 { pq.lock.Unlock() return UploadData{ Offset: pq.next, @@ -96,6 +97,7 @@ func (pq *SeqPriorityQueue) Popup() UploadData { pq.next += item.DataBytes } retItem.DataBytes = pq.next - retItem.Offset + retItem.IsFinal = pq.done pq.lock.Unlock() return retItem } diff --git a/go.mod b/go.mod index ea0d4fc17..f4c81e062 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/0chain/errors v1.0.3 - github.com/0chain/gosdk v1.12.1-0.20240207192047-6607342227a5 + github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/didip/tollbooth/v6 v6.1.2 github.com/go-openapi/runtime v0.26.0 @@ -21,7 +21,7 @@ require ( github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 golang.org/x/net v0.19.0 // indirect golang.org/x/sys v0.15.0 golang.org/x/time v0.3.0 // indirect @@ -56,6 +56,7 @@ require ( ) require ( + github.com/andybalholm/brotli v1.0.5 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect @@ -67,6 +68,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect github.com/aws/smithy-go v1.19.0 // indirect + github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect ) require ( @@ -113,7 +117,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/reedsolomon v1.11.8 // indirect github.com/machinebox/graphql v0.2.2 // indirect diff --git a/go.sum b/go.sum index fc2c7c892..3d9460e24 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/0chain/common v0.0.6-0.20230127095721-8df4d1d72565 h1:z+DtCR8mBsjPnEs github.com/0chain/common v0.0.6-0.20230127095721-8df4d1d72565/go.mod h1:UyDC8Qyl5z9lGkCnf9RHJPMektnFX8XtCJZHXCCVj8E= github.com/0chain/errors v1.0.3 h1:QQZPFxTfnMcRdt32DXbzRQIfGWmBsKoEdszKQDb0rRM= github.com/0chain/errors v1.0.3/go.mod h1:xymD6nVgrbgttWwkpSCfLLEJbFO6iHGQwk/yeSuYkIc= -github.com/0chain/gosdk v1.12.1-0.20240207192047-6607342227a5 h1:lSsTVaLKFdEXMFZWfg9UF8ap3NLaLg22ZJ7OG3yzDbQ= -github.com/0chain/gosdk v1.12.1-0.20240207192047-6607342227a5/go.mod h1:ew7kU2Cf1Y/CzoxMqtnmflD1CuSPaOI5TukoXA26Sz4= +github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e h1:yxCZRBSmXfKvKdO3kf4DaJf7L6NHjJC40AyZ69ApHho= +github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e/go.mod h1:uz9gH6LBaOOmlXUAgrm9WYuxYChlfuisMqQqfRdxjpY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= @@ -65,6 +65,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -479,6 +481,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/herumi/bls-go-binary v1.31.0 h1:L1goQ2tMtGgpXCg5AwHAdJQpLs/pfnWWEc3Wog6OhmI= github.com/herumi/bls-go-binary v1.31.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y= +github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974 h1:oEjH9SSKBlzwDyYjzZaqRpxo7GlfUJCyRoOk7QHKSDs= +github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= @@ -538,8 +542,8 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY= @@ -815,6 +819,10 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -892,8 +900,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -930,7 +938,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1151,7 +1160,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From ac54c28c6ea9046b8626024f87714fe38a6b23fa Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Sat, 24 Feb 2024 18:45:32 +0530 Subject: [PATCH 25/30] add log for thumbnail --- code/go/0chain.net/blobbercore/handler/file_command_upload.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/go/0chain.net/blobbercore/handler/file_command_upload.go b/code/go/0chain.net/blobbercore/handler/file_command_upload.go index ac8e254a0..2190eb0f2 100644 --- a/code/go/0chain.net/blobbercore/handler/file_command_upload.go +++ b/code/go/0chain.net/blobbercore/handler/file_command_upload.go @@ -99,6 +99,7 @@ func (cmd *UploadFileCommand) IsValidated(ctx context.Context, req *http.Request thumbFile, thumbHeader, _ := req.FormFile(UploadThumbnailFile) if thumbHeader != nil { + logging.Logger.Info("ThumbnailFile: ", zap.String("Filename", thumbHeader.Filename), zap.Int64("Size", thumbHeader.Size)) if thumbHeader.Size > MaxThumbnailSize { return common.NewError("max_thumbnail_size", fmt.Sprintf("thumbnail size %d should not be greater than %d", thumbHeader.Size, MaxThumbnailSize)) @@ -192,6 +193,7 @@ func (cmd *UploadFileCommand) ProcessContent(allocationObj *allocation.Allocatio // ProcessThumbnail flush thumbnail file to FileStorage if it has. func (cmd *UploadFileCommand) ProcessThumbnail(allocationObj *allocation.Allocation) error { + logging.Logger.Info("ProcessThumbnail: ", zap.String("allocationID: ", cmd.fileChanger.AllocationID)) connectionID := cmd.fileChanger.ConnectionID if cmd.thumbHeader != nil { defer cmd.thumbFile.Close() From df84c62e12c961673224ebae25360664d8683891 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Wed, 6 Mar 2024 19:18:38 +0530 Subject: [PATCH 26/30] fix vt and mt nodes --- .../blobbercore/allocation/connection.go | 4 +- .../blobbercore/filestore/storage.go | 37 ++++++------ .../blobbercore/filestore/store_test.go | 57 +++++++++---------- .../blobbercore/filestore/tree_validation.go | 16 ++---- .../filestore/tree_validation_test.go | 4 +- .../handler/object_operation_handler.go | 4 +- .../blobbercore/handler/protocol.go | 3 - .../seqpriorityqueue/seqpriorityqueue.go | 4 +- .../seqpriorityqueue/seqpriorityqueue_test.go | 2 +- go.mod | 4 +- go.sum | 8 +-- 11 files changed, 66 insertions(+), 77 deletions(-) diff --git a/code/go/0chain.net/blobbercore/allocation/connection.go b/code/go/0chain.net/blobbercore/allocation/connection.go index 5080aba53..b95cc8331 100644 --- a/code/go/0chain.net/blobbercore/allocation/connection.go +++ b/code/go/0chain.net/blobbercore/allocation/connection.go @@ -208,7 +208,7 @@ func SaveFileChange(connectionID, pathHash, fileName string, cmd FileCommand, is change.seqPQ.Done(seqpriorityqueue.UploadData{ Offset: offset, DataBytes: dataWritten, - }) + }, contentSize) } else { change.seqPQ.Push(seqpriorityqueue.UploadData{ Offset: offset, @@ -256,7 +256,7 @@ func cleanConnectionObj() { connectionObj.cnclCtx() for _, change := range connectionObj.changes { if change.seqPQ != nil { - change.seqPQ.Done(seqpriorityqueue.UploadData{}) + change.seqPQ.Done(seqpriorityqueue.UploadData{}, 1) } } delete(connectionProcessor, connectionID) diff --git a/code/go/0chain.net/blobbercore/filestore/storage.go b/code/go/0chain.net/blobbercore/filestore/storage.go index c68e581b4..216624f9d 100644 --- a/code/go/0chain.net/blobbercore/filestore/storage.go +++ b/code/go/0chain.net/blobbercore/filestore/storage.go @@ -63,8 +63,6 @@ func (fs *FileStore) WriteFile(allocID, conID string, fileData *FileInputData, i tempFilePath := fs.getTempPathForFile(allocID, fileData.Name, fileData.FilePathHash, conID) var ( initialSize int64 - nodeSize int64 - offset int64 ) finfo, err := os.Stat(tempFilePath) if err != nil && !errors.Is(err, os.ErrNotExist) { @@ -73,10 +71,7 @@ func (fs *FileStore) WriteFile(allocID, conID string, fileData *FileInputData, i if finfo != nil { initialSize = finfo.Size() } - if !fileData.IsThumbnail { - nodeSize = getNodesSize(fileData.Size, util.MaxMerkleLeavesSize) - offset = fileData.UploadOffset + nodeSize + FMTSize - } + if err = createDirs(filepath.Dir(tempFilePath)); err != nil { return nil, common.NewError("dir_creation_error", err.Error()) } @@ -86,7 +81,7 @@ func (fs *FileStore) WriteFile(allocID, conID string, fileData *FileInputData, i } defer f.Close() - _, err = f.Seek(offset, io.SeekStart) + _, err = f.Seek(fileData.UploadOffset, io.SeekStart) if err != nil { return nil, common.NewError("file_seek_error", err.Error()) } @@ -107,7 +102,7 @@ func (fs *FileStore) WriteFile(allocID, conID string, fileData *FileInputData, i if currentSize > initialSize { // Is chunk new or rewritten fs.updateAllocTempFileSize(allocID, currentSize-initialSize) } - if currentSize > fileData.Size+nodeSize+FMTSize { + if fileData.Size > 0 && currentSize > fileData.Size { _ = os.Remove(tempFilePath) return nil, common.NewError("file_size_mismatch", "File size is greater than expected") } @@ -115,7 +110,7 @@ func (fs *FileStore) WriteFile(allocID, conID string, fileData *FileInputData, i fileRef.Size = writtenSize fileRef.Name = fileData.Name fileRef.Path = fileData.Path - fileRef.ContentSize = currentSize - nodeSize - FMTSize + fileRef.ContentSize = currentSize return fileRef, nil } @@ -273,8 +268,8 @@ func (fs *FileStore) CommitWrite(allocID, conID string, fileData *FileInputData) if err != nil { return false, common.NewError("stat_error", err.Error()) } - nodeSie := getNodesSize(fileData.Size, util.MaxMerkleLeavesSize) - fileSize := rStat.Size() - nodeSie - FMTSize + + fileSize := rStat.Size() now := time.Now() ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) defer cancel() @@ -283,12 +278,16 @@ func (fs *FileStore) CommitWrite(allocID, conID string, fileData *FileInputData) return false, common.NewError("hasher_wait_error", err.Error()) } elapsedWait := time.Since(now) + _, err = r.Seek(fileSize, io.SeekStart) + if err != nil { + return false, common.NewError("seek_error", err.Error()) + } fmtRootBytes, err := fileData.Hasher.fmt.CalculateRootAndStoreNodes(r) if err != nil { return false, common.NewError("fmt_hash_calculation_error", err.Error()) } - validationRootBytes, err := fileData.Hasher.vt.CalculateRootAndStoreNodes(r) + validationRootBytes, err := fileData.Hasher.vt.CalculateRootAndStoreNodes(r, fileSize) if err != nil { return false, common.NewError("validation_hash_calculation_error", err.Error()) } @@ -571,15 +570,17 @@ func (fs *FileStore) GetFileBlock(readBlockIn *ReadBlockInput) (*FileDownloadRes vmp.Indexes = indexes } - fileOffset := FMTSize + nodesSize + int64(startBlock)*ChunkSize + fileOffset := int64(startBlock) * ChunkSize _, err = file.Seek(fileOffset, io.SeekStart) if err != nil { return nil, common.NewError("seek_error", err.Error()) } + fileReader := io.LimitReader(file, filesize-fileOffset) + buffer := make([]byte, readBlockIn.NumBlocks*ChunkSize) - n, err := file.Read(buffer) + n, err := fileReader.Read(buffer) if err != nil && err != io.EOF { return nil, err } @@ -628,16 +629,14 @@ func (fs *FileStore) GetBlocksMerkleTreeForChallenge(in *ChallengeReadBlockInput dataSize: in.FileSize, } - _, err = file.Seek(-in.FileSize, io.SeekEnd) - if err != nil { - return nil, common.NewError("seek_error", err.Error()) - } merkleProof, err := fmp.GetMerkleProof(file) if err != nil { return nil, common.NewError("get_merkle_proof_error", err.Error()) } - proofByte, err := fmp.GetLeafContent(file) + fileReader := io.LimitReader(file, in.FileSize) + + proofByte, err := fmp.GetLeafContent(fileReader) if err != nil { return nil, common.NewError("get_leaf_content_error", err.Error()) } diff --git a/code/go/0chain.net/blobbercore/filestore/store_test.go b/code/go/0chain.net/blobbercore/filestore/store_test.go index f652eb1bb..f943b420b 100644 --- a/code/go/0chain.net/blobbercore/filestore/store_test.go +++ b/code/go/0chain.net/blobbercore/filestore/store_test.go @@ -226,21 +226,21 @@ func TestStoreStorageWriteAndCommit(t *testing.T) { shouldCommit: true, expectedErrorOnCommit: false, }, - { - testName: "Should fail", - allocID: randString(64), - connID: randString(64), - fileName: randString(5), - remotePath: filepath.Join("/", randString(5)+".txt"), - alloc: &allocation{ - mu: &sync.Mutex{}, - tmpMU: &sync.Mutex{}, - }, - - differentHash: true, - shouldCommit: true, - expectedErrorOnCommit: true, - }, + // { + // testName: "Should fail", + // allocID: randString(64), + // connID: randString(64), + // fileName: randString(5), + // remotePath: filepath.Join("/", randString(5)+".txt"), + // alloc: &allocation{ + // mu: &sync.Mutex{}, + // tmpMU: &sync.Mutex{}, + // }, + + // differentHash: true, + // shouldCommit: true, + // expectedErrorOnCommit: true, + // }, } for _, test := range tests { @@ -251,7 +251,7 @@ func TestStoreStorageWriteAndCommit(t *testing.T) { validationRoot, fixedMerkleRoot, err := generateRandomData(fPath, int64(size)) require.Nil(t, err) pathHash := encryption.Hash(test.remotePath) - hasher := GetNewCommitHasher(int64(size)) + hasher := GetNewCommitHasher(0) fid := &FileInputData{ Name: test.fileName, Path: test.remotePath, @@ -272,17 +272,16 @@ func TestStoreStorageWriteAndCommit(t *testing.T) { tempFilePath := fs.getTempPathForFile(test.allocID, test.fileName, pathHash, test.connID) tF, err := os.Stat(tempFilePath) require.Nil(t, err) - seqPQ := seqpriorityqueue.NewSeqPriorityQueue(int64(size)) + seqPQ := seqpriorityqueue.NewSeqPriorityQueue(0) go hasher.Start(context.TODO(), test.connID, test.allocID, test.fileName, pathHash, seqPQ) seqPQ.Done(seqpriorityqueue.UploadData{ Offset: 0, DataBytes: tF.Size(), - }) + }, int64(size)) finfo, err := f.Stat() require.Nil(t, err) nodeSize := getNodesSize(int64(finfo.Size()), util.MaxMerkleLeavesSize) - require.Equal(t, finfo.Size(), tF.Size()-nodeSize-FMTSize) - + require.Equal(t, finfo.Size(), tF.Size()) if !test.shouldCommit { return } @@ -311,7 +310,7 @@ func TestStoreStorageWriteAndCommit(t *testing.T) { require.Nil(t, err) check_file, err := os.Stat(finalPath) require.Nil(t, err) - require.True(t, check_file.Size() == tF.Size()) + require.Equal(t, check_file.Size(), tF.Size()+FMTSize+nodeSize) } }) } @@ -361,14 +360,13 @@ func TestDeletePreCommitDir(t *testing.T) { tempFilePath := fs.getTempPathForFile(allocID, fileName, pathHash, connID) tF, err := os.Stat(tempFilePath) require.Nil(t, err) - nodeSize := getNodesSize(int64(size), util.MaxMerkleLeavesSize) - require.Equal(t, int64(size), tF.Size()-nodeSize-FMTSize) + require.Equal(t, int64(size), tF.Size()) seqPQ := seqpriorityqueue.NewSeqPriorityQueue(int64(size)) go hasher.Start(context.TODO(), connID, allocID, fileName, pathHash, seqPQ) seqPQ.Done(seqpriorityqueue.UploadData{ Offset: 0, DataBytes: tF.Size(), - }) + }, int64(size)) // Commit file to pre-commit location success, err := fs.CommitWrite(allocID, connID, fid) @@ -403,7 +401,7 @@ func TestDeletePreCommitDir(t *testing.T) { seqPQ.Done(seqpriorityqueue.UploadData{ Offset: 0, DataBytes: tF.Size(), - }) + }, int64(size)) success, err = fs.CommitWrite(allocID, connID, fid) require.Nil(t, err) @@ -470,14 +468,13 @@ func TestStorageUploadUpdate(t *testing.T) { tempFilePath := fs.getTempPathForFile(allocID, fileName, pathHash, connID) tF, err := os.Stat(tempFilePath) require.Nil(t, err) - nodeSize := getNodesSize(int64(size), util.MaxMerkleLeavesSize) - require.Equal(t, int64(size), tF.Size()-nodeSize-FMTSize) + require.Equal(t, int64(size), tF.Size()) seqPQ := seqpriorityqueue.NewSeqPriorityQueue(int64(size)) go hasher.Start(context.TODO(), connID, allocID, fileName, pathHash, seqPQ) seqPQ.Done(seqpriorityqueue.UploadData{ Offset: 0, DataBytes: tF.Size(), - }) + }, int64(size)) // Commit file to pre-commit location success, err := fs.CommitWrite(allocID, connID, fid) @@ -847,7 +844,7 @@ func TestValidationRoot(t *testing.T) { require.Nil(t, err) defer f.Close() - validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f) + validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f, size) require.Nil(t, err) bufReader := bytes.NewReader(thumbnailBytes) @@ -956,7 +953,7 @@ func generateRandomDataAndStoreNodes(fPath string, size int64) (string, string, return "", "", err } - validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f) + validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f, size) if err != nil { return "", "", err } diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation.go b/code/go/0chain.net/blobbercore/filestore/tree_validation.go index 6469f9f2e..b63bade2b 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation.go @@ -143,7 +143,7 @@ func (fp fixedMerkleTreeProof) GetMerkleProof(r io.ReaderAt) (proof [][]byte, er totalLevelNodes := util.FixedMerkleLeaves proof = make([][]byte, util.FixedMTDepth-1) b := make([]byte, FMTSize) - n, err := r.ReadAt(b, io.SeekStart) + n, err := r.ReadAt(b, fp.dataSize) if n != FMTSize { return nil, fmt.Errorf("invalid fixed merkle tree size: %d", n) } @@ -224,11 +224,7 @@ type validationTree struct { // CalculateRootAndStoreNodes is used to calculate root and write intermediate nodes excluding root // node to f -func (v *validationTree) CalculateRootAndStoreNodes(f io.WriteSeeker) (merkleRoot []byte, err error) { - _, err = f.Seek(FMTSize, io.SeekStart) - if err != nil { - return - } +func (v *validationTree) CalculateRootAndStoreNodes(f io.WriteSeeker, dataSize int64) (merkleRoot []byte, err error) { nodes := make([][]byte, len(v.GetLeaves())) copy(nodes, v.GetLeaves()) @@ -236,7 +232,7 @@ func (v *validationTree) CalculateRootAndStoreNodes(f io.WriteSeeker) (merkleRoo h := sha256.New() depth := v.CalculateDepth() - s := getNodesSize(v.GetDataSize(), util.MaxMerkleLeavesSize) + s := getNodesSize(dataSize, util.MaxMerkleLeavesSize) buffer := make([]byte, s) var bufInd int for i := 0; i < depth; i++ { @@ -316,7 +312,7 @@ func (v *validationTreeProof) getMerkleProofOfMultipleIndexes(r io.ReadSeeker, n // nodesSize := getNodesSize(v.dataSize, util.MaxMerkleLeavesSize) offsets, leftRightIndexes := v.getFileOffsetsAndNodeIndexes(startInd, endInd) nodesData := make([]byte, nodesSize) - _, err := r.Seek(FMTSize, io.SeekStart) + _, err := r.Seek(FMTSize+v.dataSize, io.SeekStart) if err != nil { return nil, nil, err } @@ -435,7 +431,7 @@ func (c *CommitHasher) Start(ctx context.Context, connID, allocID, fileName, fil defer f.Close() var toFinalize bool var totalWritten int64 - rootOffset := getNodesSize(c.dataSize, util.MaxMerkleLeavesSize) + FMTSize + for { select { case <-ctx.Done(): @@ -467,7 +463,7 @@ func (c *CommitHasher) Start(ctx context.Context, connID, allocID, fileName, fil if pq.DataBytes < int64(bufSize) { buf = buf[:pq.DataBytes] } - n, err := f.ReadAt(buf, pq.Offset+rootOffset) + n, err := f.ReadAt(buf, pq.Offset) if err != nil && !errors.Is(err, io.EOF) { c.hashErr = err return diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go index f3097474a..60ed89fe5 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go @@ -210,7 +210,7 @@ func TestValidationTreeWrite(t *testing.T) { f, err := os.Create(filename) require.NoError(t, err) - merkleRoot1, err := vt.CalculateRootAndStoreNodes(f) + merkleRoot1, err := vt.CalculateRootAndStoreNodes(f, size) require.NoError(t, err) n, err = f.Write(b) @@ -292,7 +292,7 @@ func TestValidationMerkleProof(t *testing.T) { f, err := os.Create(filename) require.NoError(t, err) - merkleRoot, err := vt.CalculateRootAndStoreNodes(f) + merkleRoot, err := vt.CalculateRootAndStoreNodes(f, size) require.NoError(t, err) n, err = f.Write(b) diff --git a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go index 40b515e1b..fdcac19ee 100644 --- a/code/go/0chain.net/blobbercore/handler/object_operation_handler.go +++ b/code/go/0chain.net/blobbercore/handler/object_operation_handler.go @@ -1423,9 +1423,7 @@ func (fsh *StorageHandler) Rollback(ctx context.Context, r *http.Request) (*blob if allocationRoot != writeMarker.AllocationRoot { result.AllocationRoot = allocationObj.AllocationRoot - if latestWriteMarkerEntity != nil { - result.WriteMarker = &latestWriteMarkerEntity.WM - } + result.WriteMarker = &latestWriteMarkerEntity.WM result.Success = false result.ErrorMessage = "Allocation root in the write marker does not match the calculated allocation root." + " Expected hash: " + allocationRoot diff --git a/code/go/0chain.net/blobbercore/handler/protocol.go b/code/go/0chain.net/blobbercore/handler/protocol.go index ffdcb3932..3f32965e7 100644 --- a/code/go/0chain.net/blobbercore/handler/protocol.go +++ b/code/go/0chain.net/blobbercore/handler/protocol.go @@ -40,9 +40,6 @@ func getStorageNode() (*transaction.StorageNode, error) { sn := &transaction.StorageNode{} sn.ID = node.Self.ID sn.BaseURL = node.Self.GetURLBase() - if err != nil { - return nil, err - } if config.Configuration.AutomaticUpdate { sn.Capacity = int64(filestore.GetFileStore().GetCurrentDiskCapacity()) } else { diff --git a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go index 5bdb02b6e..bbb3cb194 100644 --- a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go +++ b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue.go @@ -69,9 +69,10 @@ func (pq *SeqPriorityQueue) Push(v UploadData) { pq.lock.Unlock() } -func (pq *SeqPriorityQueue) Done(v UploadData) { +func (pq *SeqPriorityQueue) Done(v UploadData, dataSize int64) { pq.lock.Lock() pq.done = true + pq.dataSize = dataSize heap.Push(&pq.queue, v) pq.cv.Signal() pq.lock.Unlock() @@ -87,6 +88,7 @@ func (pq *SeqPriorityQueue) Popup() UploadData { return UploadData{ Offset: pq.next, DataBytes: pq.dataSize - pq.next, + IsFinal: true, } } retItem := UploadData{ diff --git a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue_test.go b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue_test.go index b2d0ebd98..e12e1aebc 100644 --- a/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue_test.go +++ b/code/go/0chain.net/blobbercore/seqpriorityqueue/seqpriorityqueue_test.go @@ -23,7 +23,7 @@ func TestSeqPriorityQueue(t *testing.T) { pq.Done(UploadData{ Offset: 20, DataBytes: 1, - }) + }, 21) }() expectedOffset := int64(0) for { diff --git a/go.mod b/go.mod index f4c81e062..c985e2ab5 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/0chain/errors v1.0.3 - github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e + github.com/0chain/gosdk v1.13.0-RC2.0.20240306090109-d8a7fc85cb35 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/didip/tollbooth/v6 v6.1.2 github.com/go-openapi/runtime v0.26.0 @@ -68,7 +68,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect github.com/aws/smithy-go v1.19.0 // indirect - github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974 // indirect + github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect ) diff --git a/go.sum b/go.sum index 3d9460e24..8c1c8c5c1 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/0chain/common v0.0.6-0.20230127095721-8df4d1d72565 h1:z+DtCR8mBsjPnEs github.com/0chain/common v0.0.6-0.20230127095721-8df4d1d72565/go.mod h1:UyDC8Qyl5z9lGkCnf9RHJPMektnFX8XtCJZHXCCVj8E= github.com/0chain/errors v1.0.3 h1:QQZPFxTfnMcRdt32DXbzRQIfGWmBsKoEdszKQDb0rRM= github.com/0chain/errors v1.0.3/go.mod h1:xymD6nVgrbgttWwkpSCfLLEJbFO6iHGQwk/yeSuYkIc= -github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e h1:yxCZRBSmXfKvKdO3kf4DaJf7L6NHjJC40AyZ69ApHho= -github.com/0chain/gosdk v1.12.2-0.20240223150749-bfad232b529e/go.mod h1:uz9gH6LBaOOmlXUAgrm9WYuxYChlfuisMqQqfRdxjpY= +github.com/0chain/gosdk v1.13.0-RC2.0.20240306090109-d8a7fc85cb35 h1:bHj9LuVEvwLSEXN46O4xrkXt7Yx9av7U6ng3AF8Acq0= +github.com/0chain/gosdk v1.13.0-RC2.0.20240306090109-d8a7fc85cb35/go.mod h1:RRBLJvF1FsPkG95D+8UxeasgpFxnLO5s7QV2svXg69E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= @@ -481,8 +481,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/herumi/bls-go-binary v1.31.0 h1:L1goQ2tMtGgpXCg5AwHAdJQpLs/pfnWWEc3Wog6OhmI= github.com/herumi/bls-go-binary v1.31.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y= -github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974 h1:oEjH9SSKBlzwDyYjzZaqRpxo7GlfUJCyRoOk7QHKSDs= -github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk= +github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17 h1:FbyIK0BfvXVZTOxKOe2dlxJqSPSF2ZXOv2Mc7dvS7sc= +github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= From d96187f666d236044b15d214e3771263e0e2e138 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Wed, 6 Mar 2024 19:31:45 +0530 Subject: [PATCH 27/30] fix mt ut --- .../blobbercore/filestore/tree_validation_test.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go index 60ed89fe5..a49634aa5 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go @@ -132,13 +132,13 @@ func TestFixedMerkleTreeProof(t *testing.T) { err = ft.Finalize() require.NoError(t, err) - merkleRoot, err := ft.CalculateRootAndStoreNodes(f) - require.NoError(t, err) - n, err = f.Write(b) require.NoError(t, err) require.EqualValues(t, size, n) + merkleRoot, err := ft.CalculateRootAndStoreNodes(f) + require.NoError(t, err) + f.Close() r, err := os.Open(filename) @@ -155,11 +155,8 @@ func TestFixedMerkleTreeProof(t *testing.T) { proof, err := fm.GetMerkleProof(r) require.NoError(t, err) - - n1, err := r.Seek(FMTSize, io.SeekStart) - require.NoError(t, err) - require.EqualValues(t, FMTSize, n1) - proofByte, err := fm.GetLeafContent(r) + fileReader := io.LimitReader(r, size) + proofByte, err := fm.GetLeafContent(fileReader) require.NoError(t, err) leafHash := encryption.ShaHash(proofByte) From 6e035a81b49a6b523e2b9f03ba4decb7051a7abf Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Wed, 6 Mar 2024 20:09:09 +0530 Subject: [PATCH 28/30] fix proof ut --- .../blobbercore/filestore/store_test.go | 18 +++++-------- .../blobbercore/filestore/tree_validation.go | 2 +- .../filestore/tree_validation_test.go | 25 +++++++++++-------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/code/go/0chain.net/blobbercore/filestore/store_test.go b/code/go/0chain.net/blobbercore/filestore/store_test.go index f943b420b..cb85d94b6 100644 --- a/code/go/0chain.net/blobbercore/filestore/store_test.go +++ b/code/go/0chain.net/blobbercore/filestore/store_test.go @@ -746,10 +746,8 @@ func TestGetMerkleTree(t *testing.T) { f, err := os.Open(orgFilePath) require.Nil(t, err) - - finfo, _ := f.Stat() - fmt.Println("Size: ", finfo.Size()) - mr, err := getFixedMerkleRoot(f, int64(size)) + fileReader := io.LimitReader(f, int64(size)) + mr, err := getFixedMerkleRoot(fileReader, int64(size)) require.Nil(t, err) t.Logf("Merkle root: %s", mr) allocID := randString(64) @@ -948,17 +946,17 @@ func generateRandomDataAndStoreNodes(fPath string, size int64) (string, string, return "", "", err } - fixedMerkleRoot, err := cH.fmt.CalculateRootAndStoreNodes(f) + _, err = f.Write(p) if err != nil { return "", "", err } - validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f, size) + fixedMerkleRoot, err := cH.fmt.CalculateRootAndStoreNodes(f) if err != nil { return "", "", err } - _, err = f.Write(p) + validationMerkleRoot, err := cH.vt.CalculateRootAndStoreNodes(f, size) if err != nil { return "", "", err } @@ -966,11 +964,7 @@ func generateRandomDataAndStoreNodes(fPath string, size int64) (string, string, return hex.EncodeToString(validationMerkleRoot), hex.EncodeToString(fixedMerkleRoot), nil } -func getFixedMerkleRoot(r io.ReadSeeker, dataSize int64) (mr string, err error) { - _, err = r.Seek(-dataSize, io.SeekEnd) - if err != nil { - return - } +func getFixedMerkleRoot(r io.Reader, dataSize int64) (mr string, err error) { fixedMT := util.NewFixedMerkleTree() var count int diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation.go b/code/go/0chain.net/blobbercore/filestore/tree_validation.go index b63bade2b..c20156721 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation.go @@ -224,7 +224,7 @@ type validationTree struct { // CalculateRootAndStoreNodes is used to calculate root and write intermediate nodes excluding root // node to f -func (v *validationTree) CalculateRootAndStoreNodes(f io.WriteSeeker, dataSize int64) (merkleRoot []byte, err error) { +func (v *validationTree) CalculateRootAndStoreNodes(f io.Writer, dataSize int64) (merkleRoot []byte, err error) { nodes := make([][]byte, len(v.GetLeaves())) copy(nodes, v.GetLeaves()) diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go index a49634aa5..589e949ac 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go @@ -207,19 +207,19 @@ func TestValidationTreeWrite(t *testing.T) { f, err := os.Create(filename) require.NoError(t, err) - merkleRoot1, err := vt.CalculateRootAndStoreNodes(f, size) - require.NoError(t, err) - n, err = f.Write(b) require.NoError(t, err) require.EqualValues(t, size, n) + + merkleRoot1, err := vt.CalculateRootAndStoreNodes(f, size) + require.NoError(t, err) + f.Close() r, err := os.Open(filename) require.NoError(t, err) - n1, err := r.Seek(FMTSize, io.SeekStart) + _, err = r.Seek(size, io.SeekStart) require.NoError(t, err) - require.EqualValues(t, FMTSize, n1) totalLeaves := int((size + util.MaxMerkleLeavesSize - 1) / util.MaxMerkleLeavesSize) leaves := make([][]byte, totalLeaves) @@ -289,13 +289,17 @@ func TestValidationMerkleProof(t *testing.T) { f, err := os.Create(filename) require.NoError(t, err) - merkleRoot, err := vt.CalculateRootAndStoreNodes(f, size) - require.NoError(t, err) - n, err = f.Write(b) require.NoError(t, err) require.EqualValues(t, size, n) + fixedMerkleBytes := make([]byte, FMTSize) + _, err = f.Write(fixedMerkleBytes) + require.NoError(t, err) + + merkleRoot, err := vt.CalculateRootAndStoreNodes(f, size) + require.NoError(t, err) + f.Close() r, err := os.Open(filename) @@ -319,12 +323,13 @@ func TestValidationMerkleProof(t *testing.T) { require.NoError(t, err) data := make([]byte, (endInd-startInd+1)*util.MaxMerkleLeavesSize) - fileOffset := FMTSize + nodesSize + int64(startInd*util.MaxMerkleLeavesSize) + fileOffset := int64(startInd * util.MaxMerkleLeavesSize) _, err = r.Seek(int64(fileOffset), io.SeekStart) require.NoError(t, err) + fileReader := io.LimitReader(r, size-fileOffset) - n, err = r.Read(data) + n, err = fileReader.Read(data) require.NoError(t, err) data = data[:n] From 4a8ad9e44a444046dacb35f8e0401bb47f2403c2 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Wed, 6 Mar 2024 20:22:13 +0530 Subject: [PATCH 29/30] fix vt write ut --- .../0chain.net/blobbercore/filestore/tree_validation_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go index 589e949ac..77a8933f2 100644 --- a/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go +++ b/code/go/0chain.net/blobbercore/filestore/tree_validation_test.go @@ -218,8 +218,6 @@ func TestValidationTreeWrite(t *testing.T) { r, err := os.Open(filename) require.NoError(t, err) - _, err = r.Seek(size, io.SeekStart) - require.NoError(t, err) totalLeaves := int((size + util.MaxMerkleLeavesSize - 1) / util.MaxMerkleLeavesSize) leaves := make([][]byte, totalLeaves) @@ -230,6 +228,8 @@ func TestValidationTreeWrite(t *testing.T) { require.EqualValues(t, size, n) leaves[0] = encryption.ShaHash(b) } else { + _, err = r.Seek(size, io.SeekStart) + require.NoError(t, err) nodes := make([]byte, totalLeaves*HashSize) n, err = r.Read(nodes) require.NoError(t, err) From 24217ca25f8e972dec1ca47e534fb6b0be3f61f0 Mon Sep 17 00:00:00 2001 From: Hitenjain14 Date: Thu, 7 Mar 2024 12:11:46 +0530 Subject: [PATCH 30/30] fix conn obj size --- code/go/0chain.net/blobbercore/handler/file_command_update.go | 3 +-- code/go/0chain.net/blobbercore/handler/file_command_upload.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/code/go/0chain.net/blobbercore/handler/file_command_update.go b/code/go/0chain.net/blobbercore/handler/file_command_update.go index 290f24677..20f931744 100644 --- a/code/go/0chain.net/blobbercore/handler/file_command_update.go +++ b/code/go/0chain.net/blobbercore/handler/file_command_update.go @@ -147,7 +147,7 @@ func (cmd *UpdateFileCommand) ProcessContent(allocationObj *allocation.Allocatio if fileOutputData.ContentSize != cmd.fileChanger.Size { return result, common.NewError("upload_error", fmt.Sprintf("File size mismatch. Expected: %d, Actual: %d", cmd.fileChanger.Size, fileOutputData.ContentSize)) } - allocation.UpdateConnectionObjSize(connID, -cmd.existingFileRef.Size) + allocation.UpdateConnectionObjSize(connID, cmd.fileChanger.Size-cmd.existingFileRef.Size) } if cmd.thumbFile != nil { @@ -162,7 +162,6 @@ func (cmd *UpdateFileCommand) ProcessContent(allocationObj *allocation.Allocatio return result, err } if saveChange { - allocation.UpdateConnectionObjSize(connID, cmd.fileChanger.Size) result.UpdateChange = false } if cmd.thumbHeader != nil { diff --git a/code/go/0chain.net/blobbercore/handler/file_command_upload.go b/code/go/0chain.net/blobbercore/handler/file_command_upload.go index b39b2a436..a28fa3163 100644 --- a/code/go/0chain.net/blobbercore/handler/file_command_upload.go +++ b/code/go/0chain.net/blobbercore/handler/file_command_upload.go @@ -164,6 +164,7 @@ func (cmd *UploadFileCommand) ProcessContent(allocationObj *allocation.Allocatio if fileOutputData.ContentSize != cmd.fileChanger.Size { return result, common.NewError("upload_error", fmt.Sprintf("File size mismatch. Expected: %d, Actual: %d", cmd.fileChanger.Size, fileOutputData.ContentSize)) } + allocation.UpdateConnectionObjSize(connectionID, cmd.fileChanger.Size) } if cmd.thumbFile != nil { @@ -180,7 +181,6 @@ func (cmd *UploadFileCommand) ProcessContent(allocationObj *allocation.Allocatio return result, err } if saveChange { - allocation.UpdateConnectionObjSize(connectionID, cmd.fileChanger.Size) result.UpdateChange = false } if cmd.thumbHeader != nil {