From afade4fb0920db92ef52028dc4891a7d7b3991ff Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sat, 5 Jul 2025 16:36:55 +0530 Subject: [PATCH 01/47] miner transaction request reduce timeout --- core/transaction/entity.go | 4 ++-- core/util/httpnet.go | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/transaction/entity.go b/core/transaction/entity.go index 995a45954..5eed4ef60 100644 --- a/core/transaction/entity.go +++ b/core/transaction/entity.go @@ -270,7 +270,7 @@ func (t *Transaction) VerifySigWith(pubkey string, verifyHandler VerifyFunc) (bo } func SendTransactionSync(txn *Transaction, miners []string) error { - const requestTimeout = 3 * time.Second // Timeout for each request + const requestTimeout = 12 * time.Second // Timeout for each request fails := make(chan error, len(miners)) var wg sync.WaitGroup @@ -282,7 +282,7 @@ func SendTransactionSync(txn *Transaction, miners []string) error { go func(url string) { defer wg.Done() - // Create a context with a 30-second timeout for each request + // Create a context with a 12-second timeout for each request ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) defer cancel() diff --git a/core/util/httpnet.go b/core/util/httpnet.go index bcc5f2b77..7a9e9703f 100644 --- a/core/util/httpnet.go +++ b/core/util/httpnet.go @@ -85,18 +85,27 @@ func init() { func httpDo(req *http.Request, ctx context.Context, cncl context.CancelFunc, f func(*http.Response, error) error) error { c := make(chan error, 1) + done := make(chan struct{}) - go func() { c <- f(Client.Do(req.WithContext(ctx))) }() + go func() { + select { + case c <- f(Client.Do(req.WithContext(ctx))): + // normal completion + case <-done: + // context cancelled, do not call f + } + }() select { - case <-ctx.Done(): - // Use the cancel function only after trying to get the result. - <-c // Wait for f to return. - return ctx.Err() - case err := <-c: - // Ensure that we call cncl after we are done with the response - defer cncl() // Move this here to ensure we cancel after processing - return err + case <-ctx.Done(): + // Use the cancel function only after trying to get the result. + close(done) + cncl() + return ctx.Err() + case err := <-c: + // Ensure that we call cncl after we are done with the response + defer cncl() // Move this here to ensure we cancel after processing + return err } } From 03482a5fd20b5a9dc400bf84af1182705658bd35 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 21 Jul 2025 09:42:14 +0530 Subject: [PATCH 02/47] upload test --- core/client/set.go | 45 +++++++- core/sys/sign.go | 3 + core/sys/vars.go | 2 +- core/version/version.go | 3 +- zboxcore/sdk/allocation.go | 3 + zboxcore/sdk/chunked_upload.go | 14 ++- zboxcore/sdk/chunked_upload_blobber.go | 16 ++- zboxcore/sdk/chunked_upload_form_builder.go | 7 +- zboxcore/sdk/chunked_upload_model.go | 2 + zboxcore/sdk/chunked_upload_option.go | 7 ++ zboxcore/sdk/chunked_upload_process.go | 25 +++- zboxcore/sdk/commitworker.go | 68 +++++++++-- zboxcore/sdk/multi_operation_worker.go | 80 +++++++++++-- zboxcore/sdk/rollback.go | 22 +++- zboxcore/sdk/sdk.go | 119 ++++++++++++++++++++ zboxcore/sdk/upload_worker.go | 5 + zboxcore/zboxutil/http.go | 61 +++++++++- 17 files changed, 439 insertions(+), 43 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 113909e90..5a6772da1 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strings" + "sync" "github.com/0chain/gosdk/core/conf" @@ -34,6 +35,8 @@ type Client struct { nonce int64 txnFee uint64 sign SignFunc + wg map[string]*sync.WaitGroup + walletCount map[string]int // maintains count of wallets in the WaitGroup by Client ID } type InitSdkOptions struct { @@ -74,7 +77,7 @@ func init() { // get sign lock <-sigC fmt.Println("Sign: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeys(clients...)) - sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(clients...)) + sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(clients...), wallet.ClientID) sigC <- struct{}{} return sig, err } @@ -82,6 +85,9 @@ func init() { sys.Verify = verifySignature sys.VerifyWith = verifySignatureWith sys.VerifyEd25519With = verifyEd25519With + + client.wg = make(map[string]*sync.WaitGroup) + client.walletCount = make(map[string]int) } var SignFn = func(hash string) (string, error) { @@ -95,16 +101,18 @@ var SignFn = func(hash string) (string, error) { return ss.Sign(hash) } -func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair) (string, error) { +func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientID string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } + fmt.Printf("Signature: %s\n", sig) + fmt.Printf("ClientID signHashWithAuth: %s\n", clientID) data, err := json.Marshal(AuthMessage{ Hash: hash, Signature: sig, - ClientID: client.wallet.ClientID, + ClientID: clientID, }) if err != nil { return "", err @@ -209,6 +217,37 @@ func SetWallet(w zcncrypto.Wallet) { client.wallets[w.ClientID] = &w } +func GetWalletByClientID(clientID string) *zcncrypto.Wallet { + if client.wallets == nil { + return nil + } + if _, exists := client.wallets[clientID]; !exists { + return nil + } + return client.wallets[clientID] +} + +func AddWallet(wallet zcncrypto.Wallet) { + if client.wallets == nil { + client.wallets = make(map[string]*zcncrypto.Wallet) + } + if _, exists := client.wg[wallet.ClientID]; !exists { + client.wg[wallet.ClientID] = &sync.WaitGroup{} + } + client.wg[wallet.ClientID].Add(1) + client.walletCount[wallet.ClientID]++ + client.wallets[wallet.ClientID] = &wallet +} + +// RemoveWallet should be set before any transaction or client specific APIs +func RemoveWallet(clientID string) { + client.wg[clientID].Done() + client.walletCount[clientID]-- + if client.walletCount[clientID] == 0 { + delete(client.wallets, clientID) + } +} + // SetWalletMode sets current wallet split key mode. func SetWalletMode(mode bool) { if client.wallet != nil { diff --git a/core/sys/sign.go b/core/sys/sign.go index 37ac18479..6f398b8a1 100644 --- a/core/sys/sign.go +++ b/core/sys/sign.go @@ -9,6 +9,9 @@ type KeyPair struct { // SignFunc sign method for request verification type SignFunc func(hash string, signatureScheme string, keys []KeyPair) (string, error) +// SignFunc sign method for request verification +type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, clientId string) (string, error) + type VerifyFunc func(signature string, msg string) (bool, error) type VerifyWithFunc func(pk, signature string, msg string) (bool, error) diff --git a/core/sys/vars.go b/core/sys/vars.go index f1f0fde5c..866c3980d 100644 --- a/core/sys/vars.go +++ b/core/sys/vars.go @@ -15,7 +15,7 @@ var ( // Sign sign method. it should be initialized on different platform. Sign SignFunc - SignWithAuth SignFunc + SignWithAuth SignWithAuthFunc // Verify verify method. it should be initialized on different platform. Verify VerifyFunc diff --git a/core/version/version.go b/core/version/version.go index fa0af25cc..4f54f23ab 100644 --- a/core/version/version.go +++ b/core/version/version.go @@ -1,5 +1,6 @@ + //====== THIS IS AUTOGENERATED FILE. DO NOT MODIFY ======== package version +const VERSIONSTR = "v1.20.6-1-gafade4fb" -const VERSIONSTR = "v1.17.11-269-g7fd90660" diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 1c4991bdb..4c8dc0aa5 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1082,6 +1082,7 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul go func(pos int) { defer wg.Done() err := mo.createConnectionObj(pos) + fmt.Printf("Multioperation: create connection for blobber %d , err : %v", pos, err) if err != nil { l.Logger.Error(err.Error()) connectionErrors[pos] = err @@ -1189,8 +1190,10 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul mo.operations = append(mo.operations, operation) } + fmt.Printf("Multioperation: operations to process %d ; operations: %v \n", len(mo.operations), mo.operations) if len(mo.operations) > 0 { err := mo.Process() + fmt.Printf("Multioperation: Process operations, err : %v", err) if err != nil { return err } diff --git a/zboxcore/sdk/chunked_upload.go b/zboxcore/sdk/chunked_upload.go index 1408fa539..d4d416de8 100644 --- a/zboxcore/sdk/chunked_upload.go +++ b/zboxcore/sdk/chunked_upload.go @@ -430,10 +430,14 @@ func (su *ChunkedUpload) process() error { defer su.chunkReader.Release() defer su.chunkReader.Close() defer su.ctxCncl(nil) + + fmt.Printf("ChunkedUpload process started for %s\n", su.fileMeta.RemoteName) for { - chunks, err := su.readChunks(su.chunkNumber) + fmt.Printf("Reading chunks from chunk reader: %v\n", su.chunkNumber) + chunks, err := su.readChunks(su.chunkNumber) + fmt.Printf("readChunks returned: %v\n", err) // chunk, err := su.chunkReader.Next() if err != nil { if su.statusCallback != nil { @@ -449,6 +453,7 @@ func (su *ChunkedUpload) process() error { if chunks.isFinal { if su.fileMeta.ActualHash == "" { su.fileMeta.ActualHash, err = su.chunkReader.GetFileHash() + fmt.Printf("GetFileHash returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -463,6 +468,7 @@ func (su *ChunkedUpload) process() error { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, thrown.New("upload_failed", "Upload failed. Uploaded size does not match with actual size: "+fmt.Sprintf("%d != %d", su.fileMeta.ActualSize, su.progress.ReadLength))) } + fmt.Printf("Upload failed. Uploaded size does not match with actual size: %d != %d\n", su.fileMeta.ActualSize, su.progress.ReadLength) return thrown.New("upload_failed", "Upload failed. Uploaded size does not match with actual size: "+fmt.Sprintf("%d != %d", su.fileMeta.ActualSize, su.progress.ReadLength)) } } @@ -472,6 +478,7 @@ func (su *ChunkedUpload) process() error { chunks.fileShards, chunks.thumbnailShards, chunks.isFinal, chunks.totalReadSize, ) + fmt.Printf("su processUpload returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -683,6 +690,7 @@ func (su *ChunkedUpload) uploadProcessor() { } func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { + fmt.Printf("uploadToBlobbers started!") select { case <-su.ctx.Done(): return context.Cause(su.ctx) @@ -706,7 +714,7 @@ func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { go func(pos uint64) { defer wg.Done() err := su.blobbers[pos].sendUploadRequest(ctx, su, uploadData.isFinal, su.encryptedKey, uploadData.uploadBody[pos].dataBuffers, uploadData.uploadBody[pos].formData, uploadData.uploadBody[pos].contentSlice, pos, &consensus) - + fmt.Printf("sendUploadRequest returned: %v\n", err) if err != nil { if strings.Contains(err.Error(), "duplicate") { su.consensus.Done() @@ -728,12 +736,14 @@ func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { close(wgErrors) for err := range wgErrors { su.ctxCncl(thrown.New("upload_failed", fmt.Sprintf("Upload failed. %s", err))) + fmt.Printf("Upload failed with error: %v\n", err) return err } if !consensus.isConsensusOk() { err := thrown.New("consensus_not_met", fmt.Sprintf("Upload failed File not found for path %s. Required consensus atleast %d, got %d", su.fileMeta.RemotePath, consensus.consensusThresh, consensus.getConsensus())) su.ctxCncl(err) + fmt.Printf("Upload failed with consensus error: %v\n", err) return err } if uploadData.uploadLength > 0 { diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index 2bbe2fe7a..847441b07 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -71,6 +71,12 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( eg, _ := errgroup.WithContext(ctx) + clientID := su.allocationObj.Owner + if su.wallet != nil { + clientID = su.wallet.ClientID + } + fmt.Printf("clientID: %s\n", clientID) + fmt.Printf("allocation owner: %s\n", su.allocationObj.Owner) for dataInd := 0; dataInd < len(dataBuffers); dataInd++ { ind := dataInd eg.Go(func() error { @@ -80,11 +86,19 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( var req *fasthttp.Request for i := 0; i < 6; i++ { req, err = zboxutil.NewFastUploadRequest( - sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, dataBuffers[ind].Bytes(), su.httpMethod, su.allocationObj.Owner) + sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, dataBuffers[ind].Bytes(), su.httpMethod, clientID) if err != nil { return err } + // Print all headers + fmt.Printf("Blobber Upload Request Headers for %s:\n", sb.blobber.Baseurl) + req.Header.VisitAll(func(k, v []byte) { + fmt.Printf(" %s: %s\n", string(k), string(v)) + }) + // Print body + // fmt.Printf("Blobber Upload Request Body for %s:\n%s\n", sb.blobber.Baseurl, string(req.Body())) + req.Header.Add("Content-Type", contentSlice[ind]) err, shouldContinue = func() (err error, shouldContinue bool) { resp := fasthttp.AcquireResponse() diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index 6781d311b..76c1406b9 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -24,7 +24,7 @@ type ChunkedUploadFormBuilder interface { fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, + thumbnailChunkData []byte, shardSize int64, clients... string, ) (blobberData, error) } @@ -59,7 +59,7 @@ func (b *chunkedUploadFormBuilder) Build( fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, + thumbnailChunkData []byte, shardSize int64, clients... string, ) (blobberData, error) { metadata := ChunkedUploadFormMetadata{ @@ -149,6 +149,7 @@ func (b *chunkedUploadFormBuilder) Build( metadata.FileBytesLen += len(chunkBytes) } + fmt.Printf("b.privateSigningKey: %v\n", b.privateSigningKey) if isFinal && i == numBodies-1 { err = hasher.Finalize() if err != nil { @@ -206,7 +207,7 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ValidationRootSignature = hex.EncodeToString(sig) } else { - rootSig, err := client.Sign(hash) + rootSig, err := client.Sign(hash, clients...) if err != nil { return res, err } diff --git a/zboxcore/sdk/chunked_upload_model.go b/zboxcore/sdk/chunked_upload_model.go index d5fb3d42f..db26f0407 100644 --- a/zboxcore/sdk/chunked_upload_model.go +++ b/zboxcore/sdk/chunked_upload_model.go @@ -11,6 +11,7 @@ import ( "time" "github.com/0chain/gosdk/core/common" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/encryption" "github.com/0chain/gosdk/zboxcore/fileref" @@ -97,6 +98,7 @@ type ChunkedUpload struct { processMap map[int]zboxutil.Uint128 //nolint:unused //used in wasm check chunked_upload_process_js.go processMapLock sync.Mutex //nolint:unused + wallet *zcncrypto.Wallet } // FileMeta metadata of stream input/local diff --git a/zboxcore/sdk/chunked_upload_option.go b/zboxcore/sdk/chunked_upload_option.go index 09bc26e56..89b7d5835 100644 --- a/zboxcore/sdk/chunked_upload_option.go +++ b/zboxcore/sdk/chunked_upload_option.go @@ -7,6 +7,7 @@ import ( "os" "time" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/zboxutil" "github.com/klauspost/reedsolomon" ) @@ -37,6 +38,12 @@ func WithThumbnail(buf []byte) ChunkedUploadOption { } } +func WithWallet(w *zcncrypto.Wallet) ChunkedUploadOption { + return func(su *ChunkedUpload) { + su.wallet = w + } +} + // WithThumbnailFile add thumbnail from file. stream mode is unnecessary for thumbnail. // - fileName: file name of the thumbnail, which will be read and uploaded func WithThumbnailFile(fileName string) ChunkedUploadOption { diff --git a/zboxcore/sdk/chunked_upload_process.go b/zboxcore/sdk/chunked_upload_process.go index 72a7560b7..6fc8e0ece 100644 --- a/zboxcore/sdk/chunked_upload_process.go +++ b/zboxcore/sdk/chunked_upload_process.go @@ -43,6 +43,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, fileShards []blobberShards, thumbnailShards blobberShards, isFinal bool, uploadLength int64) error { + fmt.Printf("inside su processUpload for chunk %d-%d\n", chunkStartIndex, chunkEndIndex) //chunk has not be uploaded yet if chunkEndIndex <= su.progress.ChunkIndex { // Write data to hashers @@ -50,6 +51,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, hasher := su.blobbers[i].progress.Hasher for _, chunkBytes := range blobberShard { err := hasher.WriteToFixedMT(chunkBytes) + fmt.Printf("WriteToFixedMT returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -57,6 +59,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, return err } err = hasher.WriteToValidationMT(chunkBytes) + fmt.Printf("WriteToValidationMT returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -88,6 +91,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, wgErrors := make(chan error, len(su.blobbers)) if len(fileShards) == 0 { + fmt.Printf("No data to upload, skipping upload process\n") return thrown.New("upload_failed", "Upload failed. No data to upload") } @@ -105,10 +109,21 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, wg.Add(1) go func(b *ChunkedUploadBlobber, thumbnailChunkData []byte, pos uint64) { defer wg.Done() - uploadData, err := su.formBuilder.Build( - &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, - su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, - fileShards[pos], thumbnailChunkData, su.shardSize) + var uploadData blobberData + var err error + if su.wallet != nil { + uploadData, err = su.formBuilder.Build( + &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, + su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, + fileShards[pos], thumbnailChunkData, su.shardSize, su.wallet.ClientID) + fmt.Printf("Build returned: %v\n", err) + } else { + uploadData, err = su.formBuilder.Build( + &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, + su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, + fileShards[pos], thumbnailChunkData, su.shardSize) + fmt.Printf("Build returned: %v\n", err) + } if err != nil { errC := atomic.AddInt32(&errCount, 1) if errC > int32(su.allocationObj.ParityShards-1) { // If atleast data shards + 1 number of blobbers can process the upload, it can be repaired later @@ -136,6 +151,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, close(wgErrors) fileShards = nil for err := range wgErrors { + fmt.Printf("Error in upload: %v\n", err) su.removeProgress() return thrown.New("upload_failed", fmt.Sprintf("Upload failed. %s", err)) } @@ -159,6 +175,7 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, blobberUpload.uploadBody = finalBuffer return su.uploadToBlobbers(blobberUpload) } + fmt.Printf("ChunkedUpload processUpload completed for chunk %d-%d\n", chunkStartIndex, chunkEndIndex) return nil } diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index 84449614c..f0ded1745 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -20,6 +20,7 @@ import ( thrown "github.com/0chain/errors" "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/encryption" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" @@ -90,6 +91,7 @@ type CommitRequestV2 struct { commitMask zboxutil.Uint128 changeIndex uint64 isRepair bool + wallet *zcncrypto.Wallet } var ( @@ -404,6 +406,7 @@ type refPathResp struct { } func (commitReq *CommitRequestV2) processCommit() { + fmt.Printf("commitReqV2 processCommit called\n") defer commitReq.wg.Done() l.Logger.Debug("received a commit request") paths := make([]string, 0) @@ -433,7 +436,19 @@ func (commitReq *CommitRequestV2) processCommit() { pos = uint64(i.TrailingZeros()) go func(ind uint64) { blobber := commitReq.allocationObj.Blobbers[ind] - trie, err := getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) + // trie, err := getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) + + var ( + trie *wmpt.WeightedMerkleTrie + err error + ) + if commitReq.wallet != nil { + trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu, commitReq.wallet.ClientID) + } else { + trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) + } + fmt.Printf("getReferencePathV2 err: %v\n", err) + resp := refPathResp{ trie: trie, err: err, @@ -468,11 +483,13 @@ func (commitReq *CommitRequestV2) processCommit() { } if trie == nil { + fmt.Printf("Failed to get reference path\n") commitReq.commitMask = zboxutil.NewUint128(0) commitReq.result = ErrorCommitResult("Failed to get reference path") return } if commitReq.commitMask.CountOnes() < commitReq.consensusThresh { + fmt.Printf("Consensus threshold not met: %d < %d\n", commitReq.commitMask.CountOnes(), commitReq.consensusThresh) commitReq.commitMask = zboxutil.NewUint128(0) commitReq.result = ErrorCommitResult("Failed to get reference path") return @@ -480,11 +497,13 @@ func (commitReq *CommitRequestV2) processCommit() { elapsedGetRefPath := time.Since(now) prevWeight := trie.Weight() for _, change := range commitReq.changes { + fmt.Printf("Processing change: %T\n", change) if change == nil { continue } err = change.ProcessChangeV2(trie, changeIndex) if err != nil && err != wmpt.ErrNotFound { + fmt.Printf("Error processing change: %v\n", err) l.Logger.Error("Error processing change ", err) commitReq.result = ErrorCommitResult("Failed to process change " + err.Error()) return @@ -505,6 +524,7 @@ func (commitReq *CommitRequestV2) processCommit() { defer wg.Done() commitErr := commitReq.commitBlobber(rootHash, rootWeight, prevWeight, blobber) if commitErr != nil { + fmt.Printf("Error committing to blobber: %s - %v\n", blobber.Baseurl, commitErr) l.Logger.Error("Error committing to blobber: ", blobber.Baseurl, " ", commitErr) errSlice[ind] = commitErr mu.Lock() @@ -538,12 +558,14 @@ func (commitReq *CommitRequestV2) processCommit() { err = errors.New("consensus_not_met", fmt.Sprintf("Successfully committed to %d blobbers, but required %d", commitReq.commitMask.CountOnes(), commitReq.consensusThresh)) } commitReq.result = ErrorCommitResult(err.Error()) + fmt.Printf("Consensus threshold not met: %d < %d\n", commitReq.commitMask.CountOnes(), commitReq.consensusThresh) return } if !commitReq.isRepair { commitReq.allocationObj.allocationRoot = encryption.Hash(hex.EncodeToString(rootHash) + commitReq.allocationObj.ID) } l.Logger.Info("[commit] ", "elapsedGetRefPath ", elapsedGetRefPath.Milliseconds(), " elapsedProcessChanges ", elapsedProcessChanges.Milliseconds(), " elapsedCommit ", elapsedCommit.Milliseconds(), " total ", time.Since(now).Milliseconds()) + fmt.Printf("processCommit completed!\n") commitReq.result = SuccessCommitResult() } @@ -574,6 +596,9 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh wm.AllocationID = req.allocationObj.ID wm.FileMetaRoot = fileMetaRoot wm.ClientID = client.Id() + if req.wallet != nil { + wm.ClientID = req.wallet.ClientID + } err = wm.Sign() if err != nil { l.Logger.Error("Error signing writemarker", err) @@ -585,8 +610,12 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh return err } - err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion) - if err != nil { + if req.wallet != nil { + err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion, req.wallet.ClientID) + } else { + err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion) + } + if err != nil { l.Logger.Error("Error submitting writemarker ", err) return err } @@ -616,7 +645,8 @@ func getFormWritter(connectionID string, wmData, fileIDMetaData []byte, body *by return formWriter, nil } -func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex) (*wmpt.WeightedMerkleTrie, error) { +func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, clientIds... string) (*wmpt.WeightedMerkleTrie, error) { + fmt.Printf("initial success: %v\n", *success) if len(paths) == 0 || blobber.LatestWM == nil || blobber.LatestWM.ChainSize == 0 { var node wmpt.Node if blobber.LatestWM != nil && len(blobber.LatestWM.FileMetaRoot) > 0 && blobber.LatestWM.ChainSize > 0 { @@ -635,7 +665,8 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio for retries := 0; retries < 3; retries++ { err, shouldContinue = func() (err error, shouldContinue bool) { var req *http.Request - req, err = zboxutil.NewReferencePathRequestV2(blobber.Baseurl, allocationID, allocationTx, sig, paths, false) + req, err = zboxutil.NewReferencePathRequestV2(blobber.Baseurl, allocationID, allocationTx, sig, paths, false, clientIds...) + fmt.Printf("getReferencePathV2 req err: %v\n", err) if err != nil { l.Logger.Error("Creating ref path req", err) return @@ -643,6 +674,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio ctx, cncl := context.WithTimeout(context.Background(), (time.Second * 30)) err = zboxutil.HttpDo(ctx, cncl, req, func(resp *http.Response, err error) error { + fmt.Printf("HttpDo req err: %v\n", err) if err != nil { l.Logger.Error("Ref path error:", err) if errors.Is(err, http.ErrServerClosed) || strings.Contains(err.Error(), "GOAWAY") { @@ -675,6 +707,8 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio shouldContinue = true return err } + fmt.Printf("Reference path error response: Status: %d - %s ", + resp.StatusCode, string(respBody)) return errors.New( strconv.Itoa(resp.StatusCode), fmt.Sprintf("Reference path error response: Status: %d - %s ", @@ -695,6 +729,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio break } } + fmt.Printf("HttpDo after req err: %v\n", err) if err != nil { return nil, err } @@ -702,34 +737,49 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio elapsedRefPath := time.Since(now) mu.Lock() defer mu.Unlock() + fmt.Printf("after success: %v\n", *success) if *success { + fmt.Printf("errAlreadySuccessful err\n") return nil, errAlreadySuccessful } trie := wmpt.New(nil, nil) - if lR.LatestWM != nil { - err = lR.LatestWM.VerifySignature(client.PublicKey()) + if lR.LatestWM != nil { + var useClientID string + if len(clientIds) > 0 && clientIds[0] != "" { + useClientID = clientIds[0] + } else { + useClientID = client.Id() + } + wallet := client.GetWalletByClientID(useClientID) + + err = lR.LatestWM.VerifySignature(wallet.ClientKey) + fmt.Printf("verify signature err : %v\n", err) if err != nil { return nil, errors.New("signature_verification_failed", err.Error()) } err = trie.Deserialize(lR.Path) + fmt.Printf("Deserialize err : %v\n", err) if err != nil { l.Logger.Error("Error deserializing trie", err) return nil, err } l.Logger.Info("[getReferencePathV2] elapsedRefPath ", elapsedRefPath.Milliseconds(), " elapsedDeserialize ", (time.Since(now) - elapsedRefPath).Milliseconds()) chainBlocks := numBlocks(lR.LatestWM.ChainSize) + fmt.Printf("chain_length_mismatch: %v\n", err) if trie.Weight() != uint64(chainBlocks) { return nil, errors.New("chain_length_mismatch", fmt.Sprintf("Expected chain length %d, got %d", chainBlocks, trie.Weight())) } + fmt.Printf("allocation_root_mismatch: %v\n", err) if hex.EncodeToString(trie.Root()) != lR.LatestWM.FileMetaRoot { return nil, errors.New("allocation_root_mismatch", fmt.Sprintf("Expected allocation root %s, got %s", lR.LatestWM.AllocationRoot, hex.EncodeToString(trie.Root()))) } } *success = true + fmt.Printf("getReferencePathV2 success") return trie, nil } -func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int) (err error) { +func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int, clientIds... string) (err error) { var ( resp *http.Response shouldContinue bool @@ -742,7 +792,7 @@ func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, l.Logger.Error("Creating form writer failed: ", err) return } - httpreq, err := zboxutil.NewCommitRequest(blobber.Baseurl, allocationID, allocationTx, body, apiVersion) + httpreq, err := zboxutil.NewCommitRequest(blobber.Baseurl, allocationID, allocationTx, body, apiVersion, clientIds...) if err != nil { l.Logger.Error("Error creating commit req: ", err) return diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index 38a6a6f07..dfa97818b 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -16,6 +16,7 @@ import ( "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/core/util" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/fileref" "github.com/0chain/gosdk/zboxcore/logger" @@ -63,10 +64,12 @@ type MultiOperation struct { changes [][]allocationchange.AllocationChange changesV2 []allocationchange.AllocationChangeV2 isRepair bool + wallet *zcncrypto.Wallet } func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { - + // fmt.Printf("Creating connection object for blobber index %d with connection ID %s", blobberIdx, mo.connectionID) + fmt.Printf("Creating connection object for blobber index %d with connection ID %s\n", blobberIdx, mo.connectionID) defer func() { if err == nil { mo.maskMU.Lock() @@ -85,6 +88,7 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { blobber := mo.allocationObj.Blobbers[blobberIdx] for i := 0; i < 3; i++ { + fmt.Printf("Iter %d", i+1) err, shouldContinue = func() (err error, shouldContinue bool) { body := new(bytes.Buffer) formWriter := multipart.NewWriter(body) @@ -95,11 +99,56 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { } formWriter.Close() + fmt.Printf("Creating connection object for blobber %s with connection ID %s", blobber.Baseurl, mo.connectionID) var httpreq *http.Request - httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.allocationObj.Owner) - if err != nil { - l.Logger.Error(blobber.Baseurl, "Error creating new connection request", err) - return + if mo.wallet != nil { + fmt.Printf("mo wallet : %v", *mo.wallet) + httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.wallet.ClientID) + if err != nil { + l.Logger.Error(blobber.Baseurl, "Error creating new connection request by wallet", err) + return err, false + } + + + // log + + fmt.Printf("Request created with wallet") + fmt.Printf("Request URL: %s\n", httpreq.URL.String()) + fmt.Printf("Request Method: %s\n", httpreq.Method) + fmt.Printf("Request Headers:\n") + for k, v := range httpreq.Header { + fmt.Printf(" %s: %v\n", k, v) + } + if httpreq.Body != nil { + bodyBytes, _ := io.ReadAll(httpreq.Body) + fmt.Printf("Request Body: %s\n", string(bodyBytes)) + // Restore body for later use + httpreq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + + } else { + fmt.Printf("No wallet") + httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.allocationObj.Owner) + if err != nil { + l.Logger.Error(blobber.Baseurl, "Error creating new connection request", err) + return + } + + // log + + fmt.Printf("Request created without wallet") + fmt.Printf("Request URL: %s\n", httpreq.URL.String()) + fmt.Printf("Request Method: %s\n", httpreq.Method) + fmt.Printf("Request Headers:\n") + for k, v := range httpreq.Header { + fmt.Printf(" %s: %v\n", k, v) + } + if httpreq.Body != nil { + bodyBytes, _ := io.ReadAll(httpreq.Body) + fmt.Printf("Request Body: %s\n", string(bodyBytes)) + // Restore body for later use + httpreq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } } httpreq.Header.Add("Content-Type", formWriter.FormDataContentType()) @@ -109,6 +158,7 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { resp = r return err }) + fmt.Printf("Create Connection Err: %v", err) if err != nil { logger.Logger.Error("Create Connection: ", err) return @@ -126,6 +176,8 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { latestRespMsg = string(respBody) latestStatusCode = resp.StatusCode + fmt.Printf("resp status code : %v", latestStatusCode) + fmt.Printf("resp status body : %v", latestRespMsg) if resp.StatusCode == http.StatusOK { l.Logger.Debug(blobber.Baseurl, " connection obj created.") return @@ -147,7 +199,8 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { err = errors.New("response_error", string(respBody)) return }() - + + fmt.Printf("Iter %d; err : %v, shouldContinue: %v", i+1, err, shouldContinue) if err != nil { return } @@ -163,6 +216,7 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { } func (mo *MultiOperation) Process() error { + fmt.Printf("MultiOperation Process start") l.Logger.Debug("MultiOperation Process start") wg := &sync.WaitGroup{} if mo.allocationObj.StorageVersion == 0 { @@ -270,7 +324,11 @@ func (mo *MultiOperation) Process() error { start = time.Now() status := Commit if !mo.isRepair && !mo.allocationObj.checkStatus { - status, _, err = mo.allocationObj.CheckAllocStatus() + if mo.wallet != nil { + status, _, err = mo.allocationObj.CheckAllocStatus(mo.wallet.ClientID) + } else { + status, _, err = mo.allocationObj.CheckAllocStatus() + } if err != nil { logger.Logger.Error("Error checking allocation status", err) if singleClientMode { @@ -323,7 +381,10 @@ func (mo *MultiOperation) Process() error { } if mo.allocationObj.StorageVersion == StorageV2 { - return mo.commitV2() + fmt.Printf("Commit V2 called!") + err = mo.commitV2() + fmt.Printf("Commit V2 returned: %v\n", err) + return err } commitReqs := make([]*CommitRequest, activeBlobbers) @@ -393,7 +454,7 @@ func (mo *MultiOperation) Process() error { } func (mo *MultiOperation) commitV2() error { - + fmt.Printf("commitV2 called \n") rootMap := make(map[string]zboxutil.Uint128) var pos uint64 for i := mo.operationMask; !i.Equals64(0); i = i.And(zboxutil.NewUint128(1).Lsh(pos).Not()) { @@ -427,6 +488,7 @@ func (mo *MultiOperation) commitV2() error { consensusThresh: threshold, changes: changes, isRepair: mo.isRepair, + wallet: mo.wallet, } commitReqs[counter] = commitReq counter++ diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 6d1607c44..2e8480355 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -65,6 +65,13 @@ type BlobberStatus struct { func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, clientId ...string) (*LatestPrevWriteMarker, error) { var lpm LatestPrevWriteMarker + var useClientID string + if len(clientId) > 0 && clientId[0] != "" { + useClientID = clientId[0] + } else { + useClientID = client.Id() + } + wallet := client.GetWalletByClientID(useClientID) req, err := zboxutil.NewWritemarkerRequest(baseUrl, allocID, allocTx, sig, clientId...) if err != nil { @@ -103,12 +110,12 @@ func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, clientId ...strin return nil, err } if lpm.LatestWM != nil { - err = lpm.LatestWM.VerifySignature(client.PublicKey()) + err = lpm.LatestWM.VerifySignature(wallet.ClientKey) if err != nil { return nil, fmt.Errorf("signature verification failed for latest writemarker: %s", err.Error()) } if lpm.PrevWM != nil { - err = lpm.PrevWM.VerifySignature(client.PublicKey()) + err = lpm.PrevWM.VerifySignature(wallet.ClientKey) if err != nil { return nil, fmt.Errorf("signature verification failed for latest writemarker: %s", err.Error()) } @@ -269,7 +276,14 @@ func (rb *RollbackBlobber) processRollback(ctx context.Context, tx string) error // CheckAllocStatus checks the status of the allocation // and returns the status of the allocation and its blobbers. -func (a *Allocation) CheckAllocStatus() (AllocStatus, []BlobberStatus, error) { +func (a *Allocation) CheckAllocStatus(clientId... string) (AllocStatus, []BlobberStatus, error) { + + var useClientID string + if len(clientId) > 0 && clientId[0] != "" { + useClientID = clientId[0] + } else { + useClientID = a.Owner + } wg := &sync.WaitGroup{} markerChan := make(chan *RollbackBlobber, len(a.Blobbers)) @@ -286,7 +300,7 @@ func (a *Allocation) CheckAllocStatus() (AllocStatus, []BlobberStatus, error) { ID: blobber.ID, Status: "available", } - wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, a.Owner) + wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, useClientID) if err != nil { atomic.AddInt32(&errCnt, 1) markerError = err diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 91b8ee639..3254ec70f 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -7,12 +7,22 @@ import ( "io" "math" "net/http" + "os" + "path" "strconv" + "strings" "github.com/0chain/common/core/currency" "github.com/0chain/errors" + thrown "github.com/0chain/errors" + "github.com/0chain/gosdk/constants" "github.com/0chain/gosdk/core/logger" + "github.com/0chain/gosdk/core/pathutil" "github.com/0chain/gosdk/core/screstapi" + "github.com/0chain/gosdk/core/sys" + "github.com/0chain/gosdk/core/zcncrypto" + + // "github.com/0chain/gosdk/zcncore" "gopkg.in/natefinch/lumberjack.v2" "github.com/0chain/gosdk/core/client" @@ -1473,3 +1483,112 @@ func updateMaskBit(mask uint16, index uint8, value bool) uint16 { return mask & ^uint16(1< 0 && clientIds[0] != "" { + wallet := client.GetWalletByClientID(clientIds[0]) + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) + return + } req.Header.Set("X-App-Client-ID", client.Id()) req.Header.Set("X-App-Client-Key", client.PublicKey()) } @@ -208,7 +218,11 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, c } else { clientID = client.Id() } - setClientInfo(req) + wallet := client.GetWalletByClientID(clientID) + fmt.Printf("setClientInfoWithSign: clientID: %s, allocation: %s, baseURL: %s\n", clientID, allocation, baseURL) + fmt.Printf("setClientInfoWithSign: wallet: %v\n", wallet) + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) hashData := allocation + baseURL @@ -243,7 +257,7 @@ func NewCommitRequest(baseUrl, allocationID string, allocationTx string, body io if err != nil { return nil, err } - setClientInfo(req) + setClientInfo(req, clients...) req.Header.Set(ALLOCATION_ID_HEADER, allocationID) @@ -651,11 +665,21 @@ func NewFastUploadRequest(baseURL, allocationID string, allocationTx string, bod } func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string, clients ...string) error { - req.Header.Set("X-App-Client-ID", client.Id()) - req.Header.Set("X-App-Client-Key", client.PublicKey()) + var clientID string + if len(clients) > 0 && clients[0] != "" { + clientID = clients[0] + } else { + clientID = client.Id() + } + wallet := client.GetWalletByClientID(clientID) + fmt.Printf("setFastClientInfoWithSign: clientID: %s, allocation: %s, baseURL: %s\n", clientID, allocation, baseURL) + fmt.Printf("setFastClientInfoWithSign: wallet: %v\n", wallet) + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) + hashData := allocation + baseURL - clientID := client.Id() + // clientID := client.Id() sig2, ok := SignCache.Get(hashData + ":" + clientID) if !ok { var err error @@ -694,7 +718,32 @@ func NewUploadRequest(baseUrl, allocationID, allocationTx, sig string, body io.R return req, nil } +func NewConnectionRequestByWallet(baseUrl, allocationID, allocationTx, sig string, body io.Reader, wallet *zcncrypto.Wallet) (*http.Request, error) { + l.Logger.Info(fmt.Sprintf("NewConnectionRequestByWallet: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) + u, err := joinUrl(baseUrl, CREATE_CONNECTION_ENDPOINT, allocationTx) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, u.String(), body) + if err != nil { + return nil, err + } + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) + req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) + hashData := allocationTx + baseUrl + sig2, err := wallet.Sign(encryption.Hash(hashData), constants.BLS0CHAIN.String()) + if err != nil { + return nil, err + } + req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) + req.Header.Set(CLIENT_SIGNATURE_HEADER_V2, sig2) + req.Header.Set(ALLOCATION_ID_HEADER, allocationID) + return req, nil +} + func NewConnectionRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, clients ...string) (*http.Request, error) { + l.Logger.Info(fmt.Sprintf("NewConnectionRequest: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) u, err := joinUrl(baseUrl, CREATE_CONNECTION_ENDPOINT, allocationTx) if err != nil { return nil, err From 56990735ecd34770358a7b3517bf7c2db6249987 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 28 Jul 2025 12:03:22 +0530 Subject: [PATCH 03/47] upload test --- core/client/set.go | 3 ++ zboxcore/sdk/allocation.go | 19 +++++++++-- zboxcore/sdk/chunked_upload_form_builder.go | 22 ++++++++++++- zboxcore/sdk/deleteworker.go | 35 ++++++++++++++++++--- zboxcore/sdk/dirworker.go | 19 +++++++++-- zboxcore/sdk/downloadworker.go | 27 ++++++++++++++++ zboxcore/sdk/multi_operation_worker.go | 20 +++++++----- zboxcore/sdk/sdk.go | 2 +- zboxcore/zboxutil/http.go | 2 +- 9 files changed, 130 insertions(+), 19 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 5a6772da1..c49df5e20 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -237,15 +237,18 @@ func AddWallet(wallet zcncrypto.Wallet) { client.wg[wallet.ClientID].Add(1) client.walletCount[wallet.ClientID]++ client.wallets[wallet.ClientID] = &wallet + fmt.Println("AddWallet: ", wallet.ClientID, "wallets: ", client.wallets, "wgCount: ", client.walletCount[wallet.ClientID]) } // RemoveWallet should be set before any transaction or client specific APIs func RemoveWallet(clientID string) { + fmt.Println("RemoveWallet: ", clientID, "wg: ", client.wg[clientID]) client.wg[clientID].Done() client.walletCount[clientID]-- if client.walletCount[clientID] == 0 { delete(client.wallets, clientID) } + fmt.Println("RemoveWallet: ", clientID, "wallets: ", client.wallets, "wgCount: ", client.walletCount[clientID]) } // SetWalletMode sets current wallet split key mode. diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 4c8dc0aa5..c9278a00f 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1049,6 +1049,7 @@ func (a *Allocation) RepairRequired(remotepath string) (zboxutil.Uint128, zboxut // - operations: the operations to perform. // - opts: the options of the multi operation as operation functions that customize the multi operation. func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...MultiOperationOption) error { + fmt.Printf("DoMultiOperation called with operations %v with Opts : %v", operations, opts) if len(operations) == 0 { return nil } @@ -1070,9 +1071,11 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul consensusThresh: a.consensusThreshold, fullconsensus: a.fullconsensus, } + fmt.Printf("opts : %v", opts) for _, opt := range opts { opt(&mo) } + fmt.Printf("mo.Wallet : %v", mo.Wallet) previousPaths := make(map[string]bool) connectionErrors := make([]error, len(mo.allocationObj.Blobbers)) @@ -1152,10 +1155,20 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationDelete: + fmt.Printf("FileOperationDelete : %v", op.RemotePath) + var clientId string + if mo.Wallet != nil { + fmt.Printf("mo.Wallet is not nil : %v", mo.Wallet.ClientID) + clientId = mo.Wallet.ClientID + } else { + fmt.Printf("mo.Wallet is nil : %v", mo.allocationObj.Owner) + clientId = mo.allocationObj.Owner + } + if op.Mask != nil { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, clientId) } else { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, clientId) } case constants.FileOperationUpdate: @@ -1165,7 +1178,7 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, true, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationCreateDir: - operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx) + operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.Wallet) default: return errors.New("invalid_operation", "Operation is not valid") diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index 76c1406b9..5a6f7afc1 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -105,6 +105,9 @@ func (b *chunkedUploadFormBuilder) Build( if b.privateSigningKey != nil { formData.SignatureVersion = SignatureV2 + fmt.Printf("[UPLOAD] Setting SignatureVersion to %d (SignatureV2) - using allocation private signing key\n", SignatureV2) + } else { + fmt.Printf("[UPLOAD] SignatureVersion not set (legacy mode) - using client private key\n") } for i := 0; i < numBodies; i++ { @@ -182,17 +185,28 @@ func (b *chunkedUploadFormBuilder) Build( } if b.privateSigningKey != nil { decodedHash, _ := hex.DecodeString(fileMeta.ActualHash) + fmt.Printf("[UPLOAD] Creating signature with allocation private signing key\n") + fmt.Printf("[UPLOAD] SignatureVersion: %d (SignatureV2)\n", SignatureV2) + fmt.Printf("[UPLOAD] ActualFileHash: %s\n", fileMeta.ActualHash) + fmt.Printf("[UPLOAD] Signing key type: allocation private signing key\n") + fmt.Printf("[UPLOAD] Signing key length: %d bytes\n", len(b.privateSigningKey)) sig, err := b.privateSigningKey.Sign(nil, decodedHash, crypto.Hash(0)) if err != nil { return res, err } formData.ActualFileHashSignature = hex.EncodeToString(sig) + fmt.Printf("[UPLOAD] ActualFileHashSignature created: %s\n", formData.ActualFileHashSignature) } else { - sig, err := client.Sign(fileMeta.ActualHash) + fmt.Printf("[UPLOAD] Creating signature with client private key\n") + fmt.Printf("[UPLOAD] SignatureVersion: %d (legacy)\n", 0) + fmt.Printf("[UPLOAD] ActualFileHash: %s\n", fileMeta.ActualHash) + fmt.Printf("[UPLOAD] Signing key type: client private key\n") + sig, err := client.Sign(fileMeta.ActualHash, clients...) if err != nil { return res, err } formData.ActualFileHashSignature = sig + fmt.Printf("[UPLOAD] ActualFileHashSignature created: %s\n", formData.ActualFileHashSignature) } hash := formData.ActualFileHashSignature + formData.ValidationRoot if b.storageVersion == StorageV2 { @@ -201,17 +215,23 @@ func (b *chunkedUploadFormBuilder) Build( } if b.privateSigningKey != nil { decodedHash, _ := hex.DecodeString(hash) + fmt.Printf("[UPLOAD] Creating validation root signature with allocation private signing key\n") + fmt.Printf("[UPLOAD] Validation root hash: %s\n", hash) sig, err := b.privateSigningKey.Sign(nil, decodedHash, crypto.Hash(0)) if err != nil { return res, err } formData.ValidationRootSignature = hex.EncodeToString(sig) + fmt.Printf("[UPLOAD] ValidationRootSignature created: %s\n", formData.ValidationRootSignature) } else { + fmt.Printf("[UPLOAD] Creating validation root signature with client private key\n") + fmt.Printf("[UPLOAD] Validation root hash: %s\n", hash) rootSig, err := client.Sign(hash, clients...) if err != nil { return res, err } formData.ValidationRootSignature = rootSig + fmt.Printf("[UPLOAD] ValidationRootSignature created: %s\n", formData.ValidationRootSignature) } formData.ActualHash = fileMeta.ActualHash diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index 243e88c5b..c7cbf075b 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -19,6 +19,7 @@ import ( "github.com/google/uuid" "github.com/0chain/gosdk/constants" + "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" @@ -43,6 +44,7 @@ type DeleteRequest struct { connectionID string consensus Consensus timestamp int64 + clientId string } var errFileDeleted = errors.New("file_deleted", "file is already deleted") @@ -66,7 +68,7 @@ func (req *DeleteRequest) deleteBlobberFile( query.Add("connection_id", req.connectionID) query.Add("path", req.remotefilepath) - httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.allocationObj.Owner) + httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.clientId) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating delete request", err) return err @@ -356,6 +358,7 @@ type DeleteOperation struct { consensus Consensus lookupHash string refs []fileref.RefEntity + clientId string } func (dop *DeleteOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { @@ -374,6 +377,7 @@ func (dop *DeleteOperation) Process(allocObj *Allocation, connectionID string) ( maskMu: dop.maskMu, wg: &sync.WaitGroup{}, consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: dop.clientId, } deleteReq.consensus.fullconsensus = dop.consensus.fullconsensus deleteReq.consensus.consensusThresh = dop.consensus.consensusThresh @@ -582,7 +586,7 @@ func (dop *DeleteOperation) Error(allocObj *Allocation, consensus int, err error } -func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int) *DeleteOperation { +func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int, clientIds... string) *DeleteOperation { dop := &DeleteOperation{} dop.remotefilepath = zboxutil.RemoteClean(remotePath) dop.deleteMask = deleteMask @@ -590,6 +594,7 @@ func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxu dop.consensus.consensusThresh = consensusTh dop.consensus.fullconsensus = fullConsensus dop.ctx, dop.ctxCncl = context.WithCancel(ctx) + dop.clientId = clientIds[0] return dop } @@ -623,7 +628,18 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.clientId != "" { + clientId := req.clientId + wallet := client.GetWalletByClientID(clientId) + if wallet == nil { + return errors.New("client_not_found", "wallet is not set for the client") + } + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { + mo.Wallet = wallet + }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } @@ -657,7 +673,18 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.clientId != "" { + clientId := req.clientId + wallet := client.GetWalletByClientID(clientId) + if wallet == nil { + return errors.New("client_not_found", "wallet is not set for the client") + } + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { + mo.Wallet = wallet + }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } diff --git a/zboxcore/sdk/dirworker.go b/zboxcore/sdk/dirworker.go index a1b4ef26f..dc64f450d 100644 --- a/zboxcore/sdk/dirworker.go +++ b/zboxcore/sdk/dirworker.go @@ -16,6 +16,7 @@ import ( "github.com/0chain/errors" "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/core/util" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" @@ -45,6 +46,7 @@ type DirRequest struct { timestamp int64 alreadyExists map[uint64]bool customMeta string + wallet *zcncrypto.Wallet Consensus } @@ -187,7 +189,17 @@ func (req *DirRequest) createDirInBlobber(blobber *blockchain.StorageNode, pos u } formWriter.Close() - httpreq, err := zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) + var ( + httpreq *http.Request + ) + if req.wallet != nil { + fmt.Printf("req.wallet is not nil : %v", req.wallet.ClientID) + httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.wallet.ClientID) + } else { + fmt.Printf("req.wallet is nil : %v", req.allocationObj.Owner) + httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) + } + fmt.Printf("error creating dir request : %v", err) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating dir request", err) return err, false @@ -282,6 +294,7 @@ type DirOperation struct { maskMU *sync.Mutex customMeta string alreadyExists map[uint64]bool + wallet *zcncrypto.Wallet Consensus } @@ -303,6 +316,7 @@ func (dirOp *DirOperation) Process(allocObj *Allocation, connectionID string) ([ wg: &sync.WaitGroup{}, alreadyExists: make(map[uint64]bool), customMeta: dirOp.customMeta, + wallet: dirOp.wallet, } dR.Consensus = Consensus{ RWMutex: &sync.RWMutex{}, @@ -364,7 +378,7 @@ func (dirOp *DirOperation) Error(allocObj *Allocation, consensus int, err error) } -func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context) *DirOperation { +func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, wallet *zcncrypto.Wallet) *DirOperation { dirOp := &DirOperation{} dirOp.remotePath = zboxutil.RemoteClean(remotePath) dirOp.dirMask = dirMask @@ -372,6 +386,7 @@ func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, ma dirOp.consensusThresh = consensusTh dirOp.fullconsensus = fullConsensus dirOp.customMeta = customMeta + dirOp.wallet = wallet dirOp.ctx, dirOp.ctxCncl = context.WithCancel(ctx) dirOp.alreadyExists = make(map[uint64]bool) return dirOp diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index a28479f9e..a3c7dadad 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -1235,17 +1235,30 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) } actualHash := fmr.fileref.ActualFileHash actualFileHashSignature := fmr.fileref.ActualFileHashSignature + fmt.Printf("[DOWNLOAD] Processing fileRef from blobber %d\n", fmr.blobberIdx) + fmt.Printf("[DOWNLOAD] FileRef SignatureVersion: %d\n", fmr.fileref.SignatureVersion) + fmt.Printf("[DOWNLOAD] FileRef ActualFileHash: %s\n", actualHash) + fmt.Printf("[DOWNLOAD] FileRef ActualFileHashSignature: %s\n", actualFileHashSignature) + fmt.Printf("[DOWNLOAD] FileRef ValidationRoot: %s\n", fmr.fileref.ValidationRoot) + fmt.Printf("[DOWNLOAD] FileRef ValidationRootSignature: %s\n", fmr.fileref.ValidationRootSignature) + var ( isValid bool err error ) if fmr.fileref.SignatureVersion == SignatureV2 { + fmt.Printf("[DOWNLOAD] Using SignatureV2 verification with allocation owner signing public key\n") + fmt.Printf("[DOWNLOAD] Verification key type: allocation owner signing public key\n") + fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerSigningPubKey) isValid, err = sys.VerifyEd25519With( req.allocOwnerSigningPubKey, actualFileHashSignature, actualHash, ) } else { + fmt.Printf("[DOWNLOAD] Using legacy verification with allocation owner public key\n") + fmt.Printf("[DOWNLOAD] Verification key type: allocation owner public key\n") + fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerPubKey) isValid, err = sys.VerifyWith( req.allocOwnerPubKey, actualFileHashSignature, @@ -1253,13 +1266,16 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) ) } if err != nil { + fmt.Printf("[DOWNLOAD] Signature verification error: %v\n", err) l.Logger.Error(err) continue } if !isValid { + fmt.Printf("[DOWNLOAD] Invalid signature for blobber %d\n", fmr.blobberIdx) l.Logger.Error("invalid signature") continue } + fmt.Printf("[DOWNLOAD] Signature verification successful for blobber %d\n", fmr.blobberIdx) retMap[actualFileHashSignature]++ if retMap[actualFileHashSignature] > req.consensus { @@ -1301,17 +1317,25 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) hashData := fmt.Sprintf("%s:%s:%s:%s", fRef.ActualFileHash, fRef.ValidationRoot, fRef.FixedMerkleRoot, req.blobbers[i].ID) hash = encrypt.Hash(hashData) } + fmt.Printf("[DOWNLOAD] Verifying validation root signature for blobber %d\n", i) + fmt.Printf("[DOWNLOAD] Validation root hash: %s\n", hash) + fmt.Printf("[DOWNLOAD] Validation root signature: %s\n", fRef.ValidationRootSignature) + var ( isValid bool err error ) if fRef.SignatureVersion == SignatureV2 { + fmt.Printf("[DOWNLOAD] Using SignatureV2 verification for validation root\n") + fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerSigningPubKey) isValid, err = sys.VerifyEd25519With( req.allocOwnerSigningPubKey, fRef.ValidationRootSignature, hash, ) } else { + fmt.Printf("[DOWNLOAD] Using legacy verification for validation root\n") + fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerPubKey) isValid, err = sys.VerifyWith( req.allocOwnerPubKey, fRef.ValidationRootSignature, @@ -1319,13 +1343,16 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) ) } if err != nil { + fmt.Printf("[DOWNLOAD] Validation root signature verification error: %v\n", err) l.Logger.Error(err, "allocOwnerPubKey: ", req.allocOwnerPubKey, " validationRootSignature: ", fRef.ValidationRootSignature, " actualFileHashSignature: ", fRef.ActualFileHashSignature, " validationRoot: ", fRef.ValidationRoot) continue } if !isValid { + fmt.Printf("[DOWNLOAD] Invalid validation root signature for blobber %d\n", i) l.Logger.Error("invalid validation root signature") continue } + fmt.Printf("[DOWNLOAD] Validation root signature verification successful for blobber %d\n", i) blobber := req.blobbers[fmr.blobberIdx] vr, _ := hex.DecodeString(fmr.fileref.ValidationRoot) diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index dfa97818b..2c4d3d52e 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -64,7 +64,7 @@ type MultiOperation struct { changes [][]allocationchange.AllocationChange changesV2 []allocationchange.AllocationChangeV2 isRepair bool - wallet *zcncrypto.Wallet + Wallet *zcncrypto.Wallet } func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { @@ -101,9 +101,9 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { fmt.Printf("Creating connection object for blobber %s with connection ID %s", blobber.Baseurl, mo.connectionID) var httpreq *http.Request - if mo.wallet != nil { - fmt.Printf("mo wallet : %v", *mo.wallet) - httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.wallet.ClientID) + if mo.Wallet != nil { + fmt.Printf("mo wallet : %v", *mo.Wallet) + httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.Wallet.ClientID) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating new connection request by wallet", err) return err, false @@ -217,6 +217,7 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { func (mo *MultiOperation) Process() error { fmt.Printf("MultiOperation Process start") + fmt.Printf("MultiOperation mo.Wallet : %v", mo.Wallet) l.Logger.Debug("MultiOperation Process start") wg := &sync.WaitGroup{} if mo.allocationObj.StorageVersion == 0 { @@ -324,8 +325,8 @@ func (mo *MultiOperation) Process() error { start = time.Now() status := Commit if !mo.isRepair && !mo.allocationObj.checkStatus { - if mo.wallet != nil { - status, _, err = mo.allocationObj.CheckAllocStatus(mo.wallet.ClientID) + if mo.Wallet != nil { + status, _, err = mo.allocationObj.CheckAllocStatus(mo.Wallet.ClientID) } else { status, _, err = mo.allocationObj.CheckAllocStatus() } @@ -488,10 +489,15 @@ func (mo *MultiOperation) commitV2() error { consensusThresh: threshold, changes: changes, isRepair: mo.isRepair, - wallet: mo.wallet, + wallet: mo.Wallet, } commitReqs[counter] = commitReq counter++ + if commitReq.wallet != nil { + fmt.Printf("commitReq wallet ID : %v", commitReq.wallet.ClientID) + } else { + fmt.Printf("commitReq wallet is nil \n") + } go AddCommitRequest(commitReq) } wg.Wait() diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 3254ec70f..78eff6825 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -1586,7 +1586,7 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin } setWalletOpt := func (mo *MultiOperation) { - mo.wallet = &wallet + mo.Wallet = &wallet } return a.DoMultiOperation(operationRequests, setWalletOpt) diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index b8536164a..b403ca032 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -880,7 +880,7 @@ func NewRedeemRequest(baseUrl, allocationID, allocationTx string, clients ...str return req, nil } -func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, clients ...string) (*http.Request, error) { +func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, clients... string) (*http.Request, error) { u, err := joinUrl(baseUrl, UPLOAD_ENDPOINT, allocationTx) if err != nil { return nil, err From 44dec8235aef9bf4b79a04bdb2e852fc45972656 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 28 Jul 2025 16:13:33 +0530 Subject: [PATCH 04/47] change func arg --- core/client/set.go | 14 +++++++++++--- core/sys/sign.go | 2 +- wasmsdk/proxy.go | 24 ++++++++++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index c49df5e20..3fd470eb0 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -101,12 +101,20 @@ var SignFn = func(hash string) (string, error) { return ss.Sign(hash) } -func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientID string) (string, error) { +func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientIds ...string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } + // Get the first clientID from variadic arguments, or use default wallet clientID + var clientID string + if len(clientIds) > 0 && clientIds[0] != "" { + clientID = clientIds[0] + } else { + clientID = client.wallet.ClientID + } + fmt.Printf("Signature: %s\n", sig) fmt.Printf("ClientID signHashWithAuth: %s\n", clientID) data, err := json.Marshal(AuthMessage{ @@ -219,8 +227,8 @@ func SetWallet(w zcncrypto.Wallet) { func GetWalletByClientID(clientID string) *zcncrypto.Wallet { if client.wallets == nil { - return nil - } + return nil + } if _, exists := client.wallets[clientID]; !exists { return nil } diff --git a/core/sys/sign.go b/core/sys/sign.go index 6f398b8a1..0b58a6e58 100644 --- a/core/sys/sign.go +++ b/core/sys/sign.go @@ -10,7 +10,7 @@ type KeyPair struct { type SignFunc func(hash string, signatureScheme string, keys []KeyPair) (string, error) // SignFunc sign method for request verification -type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, clientId string) (string, error) +type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, clientIds ...string) (string, error) type VerifyFunc func(signature string, msg string) (bool, error) diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index 7d4ec007e..9ae4a77bd 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -78,16 +78,24 @@ func main() { return signFunc(hash) } - sys.SignWithAuth = func(hash, signatureScheme string, keys []sys.KeyPair) (string, error) { + sys.SignWithAuth = func(hash, signatureScheme string, keys []sys.KeyPair, clientIds ...string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } + // Get the first clientID from variadic arguments, or use default wallet clientID + var clientID string + if len(clientIds) > 0 && clientIds[0] != "" { + clientID = clientIds[0] + } else { + clientID = client.Wallet().ClientID + } + data, err := json.Marshal(client.AuthMessage{ Hash: hash, Signature: sig, - ClientID: client.Wallet().ClientID, + ClientID: clientID, }) if err != nil { return "", err @@ -377,17 +385,25 @@ func main() { return signFunc(hash) } - sys.SignWithAuth = func(hash, signatureScheme string, keys []sys.KeyPair) (string, error) { + sys.SignWithAuth = func(hash, signatureScheme string, keys []sys.KeyPair, clientIds ...string) (string, error) { fmt.Println("[worker] SignWithAuth pubkey:", keys[0]) sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } + // Get the first clientID from variadic arguments, or use default wallet clientID + var clientID string + if len(clientIds) > 0 && clientIds[0] != "" { + clientID = clientIds[0] + } else { + clientID = client.Wallet().ClientID + } + data, err := json.Marshal(client.AuthMessage{ Hash: hash, Signature: sig, - ClientID: client.GetClient().ClientID, + ClientID: clientID, }) if err != nil { return "", err From 107c28174614247c892ec69bd2c44835e7b42579 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sat, 2 Aug 2025 15:36:00 +0530 Subject: [PATCH 05/47] remove logs and reset miners --- core/client/set.go | 5 -- core/transaction/entity.go | 7 +++ zboxcore/sdk/allocation.go | 9 ---- zboxcore/sdk/chunked_upload.go | 11 ---- zboxcore/sdk/chunked_upload_blobber.go | 10 ---- zboxcore/sdk/chunked_upload_form_builder.go | 23 +------- zboxcore/sdk/chunked_upload_process.go | 8 --- zboxcore/sdk/commitworker.go | 26 ++------- zboxcore/sdk/deleteworker.go | 4 +- zboxcore/sdk/dirworker.go | 3 -- zboxcore/sdk/downloadworker.go | 25 --------- zboxcore/sdk/multi_operation_worker.go | 58 +-------------------- zboxcore/sdk/rollback.go | 3 ++ zboxcore/sdk/sdk.go | 4 -- zboxcore/sdk/upload_worker.go | 5 -- zboxcore/zboxutil/http.go | 13 +++-- znft/keystore.go | 2 +- 17 files changed, 27 insertions(+), 189 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 3fd470eb0..dbd097c55 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -115,8 +115,6 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientId clientID = client.wallet.ClientID } - fmt.Printf("Signature: %s\n", sig) - fmt.Printf("ClientID signHashWithAuth: %s\n", clientID) data, err := json.Marshal(AuthMessage{ Hash: hash, Signature: sig, @@ -245,18 +243,15 @@ func AddWallet(wallet zcncrypto.Wallet) { client.wg[wallet.ClientID].Add(1) client.walletCount[wallet.ClientID]++ client.wallets[wallet.ClientID] = &wallet - fmt.Println("AddWallet: ", wallet.ClientID, "wallets: ", client.wallets, "wgCount: ", client.walletCount[wallet.ClientID]) } // RemoveWallet should be set before any transaction or client specific APIs func RemoveWallet(clientID string) { - fmt.Println("RemoveWallet: ", clientID, "wg: ", client.wg[clientID]) client.wg[clientID].Done() client.walletCount[clientID]-- if client.walletCount[clientID] == 0 { delete(client.wallets, clientID) } - fmt.Println("RemoveWallet: ", clientID, "wallets: ", client.wallets, "wgCount: ", client.walletCount[clientID]) } // SetWalletMode sets current wallet split key mode. diff --git a/core/transaction/entity.go b/core/transaction/entity.go index 5eed4ef60..b79b5b965 100644 --- a/core/transaction/entity.go +++ b/core/transaction/entity.go @@ -320,6 +320,13 @@ func SendTransactionSync(txn *Transaction, miners []string) error { } } + // Reset stable miners list if any miner failed + if failureCount > 0 { + if nodeClient, err := client.GetNode(); err == nil { + nodeClient.ResetStableMiners() + } + } + if failureCount == len(miners) { return fmt.Errorf(dominantErr) } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index d9688f134..8e5ee85fb 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1049,7 +1049,6 @@ func (a *Allocation) RepairRequired(remotepath string) (zboxutil.Uint128, zboxut // - operations: the operations to perform. // - opts: the options of the multi operation as operation functions that customize the multi operation. func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...MultiOperationOption) error { - fmt.Printf("DoMultiOperation called with operations %v with Opts : %v", operations, opts) if len(operations) == 0 { return nil } @@ -1071,11 +1070,9 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul consensusThresh: a.consensusThreshold, fullconsensus: a.fullconsensus, } - fmt.Printf("opts : %v", opts) for _, opt := range opts { opt(&mo) } - fmt.Printf("mo.Wallet : %v", mo.Wallet) previousPaths := make(map[string]bool) connectionErrors := make([]error, len(mo.allocationObj.Blobbers)) @@ -1085,7 +1082,6 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul go func(pos int) { defer wg.Done() err := mo.createConnectionObj(pos) - fmt.Printf("Multioperation: create connection for blobber %d , err : %v", pos, err) if err != nil { l.Logger.Error(err.Error()) connectionErrors[pos] = err @@ -1155,13 +1151,10 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationDelete: - fmt.Printf("FileOperationDelete : %v", op.RemotePath) var clientId string if mo.Wallet != nil { - fmt.Printf("mo.Wallet is not nil : %v", mo.Wallet.ClientID) clientId = mo.Wallet.ClientID } else { - fmt.Printf("mo.Wallet is nil : %v", mo.allocationObj.Owner) clientId = mo.allocationObj.Owner } @@ -1203,10 +1196,8 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul mo.operations = append(mo.operations, operation) } - fmt.Printf("Multioperation: operations to process %d ; operations: %v \n", len(mo.operations), mo.operations) if len(mo.operations) > 0 { err := mo.Process() - fmt.Printf("Multioperation: Process operations, err : %v", err) if err != nil { return err } diff --git a/zboxcore/sdk/chunked_upload.go b/zboxcore/sdk/chunked_upload.go index d4d416de8..7eab1b015 100644 --- a/zboxcore/sdk/chunked_upload.go +++ b/zboxcore/sdk/chunked_upload.go @@ -431,13 +431,9 @@ func (su *ChunkedUpload) process() error { defer su.chunkReader.Close() defer su.ctxCncl(nil) - fmt.Printf("ChunkedUpload process started for %s\n", su.fileMeta.RemoteName) for { - fmt.Printf("Reading chunks from chunk reader: %v\n", su.chunkNumber) - chunks, err := su.readChunks(su.chunkNumber) - fmt.Printf("readChunks returned: %v\n", err) // chunk, err := su.chunkReader.Next() if err != nil { if su.statusCallback != nil { @@ -453,7 +449,6 @@ func (su *ChunkedUpload) process() error { if chunks.isFinal { if su.fileMeta.ActualHash == "" { su.fileMeta.ActualHash, err = su.chunkReader.GetFileHash() - fmt.Printf("GetFileHash returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -468,7 +463,6 @@ func (su *ChunkedUpload) process() error { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, thrown.New("upload_failed", "Upload failed. Uploaded size does not match with actual size: "+fmt.Sprintf("%d != %d", su.fileMeta.ActualSize, su.progress.ReadLength))) } - fmt.Printf("Upload failed. Uploaded size does not match with actual size: %d != %d\n", su.fileMeta.ActualSize, su.progress.ReadLength) return thrown.New("upload_failed", "Upload failed. Uploaded size does not match with actual size: "+fmt.Sprintf("%d != %d", su.fileMeta.ActualSize, su.progress.ReadLength)) } } @@ -478,7 +472,6 @@ func (su *ChunkedUpload) process() error { chunks.fileShards, chunks.thumbnailShards, chunks.isFinal, chunks.totalReadSize, ) - fmt.Printf("su processUpload returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -690,7 +683,6 @@ func (su *ChunkedUpload) uploadProcessor() { } func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { - fmt.Printf("uploadToBlobbers started!") select { case <-su.ctx.Done(): return context.Cause(su.ctx) @@ -714,7 +706,6 @@ func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { go func(pos uint64) { defer wg.Done() err := su.blobbers[pos].sendUploadRequest(ctx, su, uploadData.isFinal, su.encryptedKey, uploadData.uploadBody[pos].dataBuffers, uploadData.uploadBody[pos].formData, uploadData.uploadBody[pos].contentSlice, pos, &consensus) - fmt.Printf("sendUploadRequest returned: %v\n", err) if err != nil { if strings.Contains(err.Error(), "duplicate") { su.consensus.Done() @@ -736,14 +727,12 @@ func (su *ChunkedUpload) uploadToBlobbers(uploadData UploadData) error { close(wgErrors) for err := range wgErrors { su.ctxCncl(thrown.New("upload_failed", fmt.Sprintf("Upload failed. %s", err))) - fmt.Printf("Upload failed with error: %v\n", err) return err } if !consensus.isConsensusOk() { err := thrown.New("consensus_not_met", fmt.Sprintf("Upload failed File not found for path %s. Required consensus atleast %d, got %d", su.fileMeta.RemotePath, consensus.consensusThresh, consensus.getConsensus())) su.ctxCncl(err) - fmt.Printf("Upload failed with consensus error: %v\n", err) return err } if uploadData.uploadLength > 0 { diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index 847441b07..005898a41 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -75,8 +75,6 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( if su.wallet != nil { clientID = su.wallet.ClientID } - fmt.Printf("clientID: %s\n", clientID) - fmt.Printf("allocation owner: %s\n", su.allocationObj.Owner) for dataInd := 0; dataInd < len(dataBuffers); dataInd++ { ind := dataInd eg.Go(func() error { @@ -91,14 +89,6 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( return err } - // Print all headers - fmt.Printf("Blobber Upload Request Headers for %s:\n", sb.blobber.Baseurl) - req.Header.VisitAll(func(k, v []byte) { - fmt.Printf(" %s: %s\n", string(k), string(v)) - }) - // Print body - // fmt.Printf("Blobber Upload Request Body for %s:\n%s\n", sb.blobber.Baseurl, string(req.Body())) - req.Header.Add("Content-Type", contentSlice[ind]) err, shouldContinue = func() (err error, shouldContinue bool) { resp := fasthttp.AcquireResponse() diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index 5a6f7afc1..be3e1d813 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -105,10 +105,7 @@ func (b *chunkedUploadFormBuilder) Build( if b.privateSigningKey != nil { formData.SignatureVersion = SignatureV2 - fmt.Printf("[UPLOAD] Setting SignatureVersion to %d (SignatureV2) - using allocation private signing key\n", SignatureV2) - } else { - fmt.Printf("[UPLOAD] SignatureVersion not set (legacy mode) - using client private key\n") - } + } for i := 0; i < numBodies; i++ { @@ -152,7 +149,6 @@ func (b *chunkedUploadFormBuilder) Build( metadata.FileBytesLen += len(chunkBytes) } - fmt.Printf("b.privateSigningKey: %v\n", b.privateSigningKey) if isFinal && i == numBodies-1 { err = hasher.Finalize() if err != nil { @@ -185,28 +181,17 @@ func (b *chunkedUploadFormBuilder) Build( } if b.privateSigningKey != nil { decodedHash, _ := hex.DecodeString(fileMeta.ActualHash) - fmt.Printf("[UPLOAD] Creating signature with allocation private signing key\n") - fmt.Printf("[UPLOAD] SignatureVersion: %d (SignatureV2)\n", SignatureV2) - fmt.Printf("[UPLOAD] ActualFileHash: %s\n", fileMeta.ActualHash) - fmt.Printf("[UPLOAD] Signing key type: allocation private signing key\n") - fmt.Printf("[UPLOAD] Signing key length: %d bytes\n", len(b.privateSigningKey)) sig, err := b.privateSigningKey.Sign(nil, decodedHash, crypto.Hash(0)) if err != nil { return res, err } formData.ActualFileHashSignature = hex.EncodeToString(sig) - fmt.Printf("[UPLOAD] ActualFileHashSignature created: %s\n", formData.ActualFileHashSignature) } else { - fmt.Printf("[UPLOAD] Creating signature with client private key\n") - fmt.Printf("[UPLOAD] SignatureVersion: %d (legacy)\n", 0) - fmt.Printf("[UPLOAD] ActualFileHash: %s\n", fileMeta.ActualHash) - fmt.Printf("[UPLOAD] Signing key type: client private key\n") sig, err := client.Sign(fileMeta.ActualHash, clients...) if err != nil { return res, err } formData.ActualFileHashSignature = sig - fmt.Printf("[UPLOAD] ActualFileHashSignature created: %s\n", formData.ActualFileHashSignature) } hash := formData.ActualFileHashSignature + formData.ValidationRoot if b.storageVersion == StorageV2 { @@ -215,23 +200,17 @@ func (b *chunkedUploadFormBuilder) Build( } if b.privateSigningKey != nil { decodedHash, _ := hex.DecodeString(hash) - fmt.Printf("[UPLOAD] Creating validation root signature with allocation private signing key\n") - fmt.Printf("[UPLOAD] Validation root hash: %s\n", hash) sig, err := b.privateSigningKey.Sign(nil, decodedHash, crypto.Hash(0)) if err != nil { return res, err } formData.ValidationRootSignature = hex.EncodeToString(sig) - fmt.Printf("[UPLOAD] ValidationRootSignature created: %s\n", formData.ValidationRootSignature) } else { - fmt.Printf("[UPLOAD] Creating validation root signature with client private key\n") - fmt.Printf("[UPLOAD] Validation root hash: %s\n", hash) rootSig, err := client.Sign(hash, clients...) if err != nil { return res, err } formData.ValidationRootSignature = rootSig - fmt.Printf("[UPLOAD] ValidationRootSignature created: %s\n", formData.ValidationRootSignature) } formData.ActualHash = fileMeta.ActualHash diff --git a/zboxcore/sdk/chunked_upload_process.go b/zboxcore/sdk/chunked_upload_process.go index 6fc8e0ece..5f2680e8b 100644 --- a/zboxcore/sdk/chunked_upload_process.go +++ b/zboxcore/sdk/chunked_upload_process.go @@ -43,7 +43,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, fileShards []blobberShards, thumbnailShards blobberShards, isFinal bool, uploadLength int64) error { - fmt.Printf("inside su processUpload for chunk %d-%d\n", chunkStartIndex, chunkEndIndex) //chunk has not be uploaded yet if chunkEndIndex <= su.progress.ChunkIndex { // Write data to hashers @@ -51,7 +50,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, hasher := su.blobbers[i].progress.Hasher for _, chunkBytes := range blobberShard { err := hasher.WriteToFixedMT(chunkBytes) - fmt.Printf("WriteToFixedMT returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -59,7 +57,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, return err } err = hasher.WriteToValidationMT(chunkBytes) - fmt.Printf("WriteToValidationMT returned: %v\n", err) if err != nil { if su.statusCallback != nil { su.statusCallback.Error(su.allocationObj.ID, su.fileMeta.RemotePath, su.opCode, err) @@ -91,7 +88,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, wgErrors := make(chan error, len(su.blobbers)) if len(fileShards) == 0 { - fmt.Printf("No data to upload, skipping upload process\n") return thrown.New("upload_failed", "Upload failed. No data to upload") } @@ -116,13 +112,11 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, fileShards[pos], thumbnailChunkData, su.shardSize, su.wallet.ClientID) - fmt.Printf("Build returned: %v\n", err) } else { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, fileShards[pos], thumbnailChunkData, su.shardSize) - fmt.Printf("Build returned: %v\n", err) } if err != nil { errC := atomic.AddInt32(&errCount, 1) @@ -151,7 +145,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, close(wgErrors) fileShards = nil for err := range wgErrors { - fmt.Printf("Error in upload: %v\n", err) su.removeProgress() return thrown.New("upload_failed", fmt.Sprintf("Upload failed. %s", err)) } @@ -175,7 +168,6 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, blobberUpload.uploadBody = finalBuffer return su.uploadToBlobbers(blobberUpload) } - fmt.Printf("ChunkedUpload processUpload completed for chunk %d-%d\n", chunkStartIndex, chunkEndIndex) return nil } diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index a9302655b..df958116c 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -406,7 +406,6 @@ type refPathResp struct { } func (commitReq *CommitRequestV2) processCommit() { - fmt.Printf("commitReqV2 processCommit called\n") defer commitReq.wg.Done() l.Logger.Debug("received a commit request") paths := make([]string, 0) @@ -447,7 +446,6 @@ func (commitReq *CommitRequestV2) processCommit() { } else { trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) } - fmt.Printf("getReferencePathV2 err: %v\n", err) resp := refPathResp{ trie: trie, @@ -483,13 +481,11 @@ func (commitReq *CommitRequestV2) processCommit() { } if trie == nil { - fmt.Printf("Failed to get reference path\n") commitReq.commitMask = zboxutil.NewUint128(0) commitReq.result = ErrorCommitResult("Failed to get reference path") return } if commitReq.commitMask.CountOnes() < commitReq.consensusThresh { - fmt.Printf("Consensus threshold not met: %d < %d\n", commitReq.commitMask.CountOnes(), commitReq.consensusThresh) commitReq.commitMask = zboxutil.NewUint128(0) commitReq.result = ErrorCommitResult("Failed to get reference path") return @@ -497,13 +493,11 @@ func (commitReq *CommitRequestV2) processCommit() { elapsedGetRefPath := time.Since(now) prevWeight := trie.Weight() for _, change := range commitReq.changes { - fmt.Printf("Processing change: %T\n", change) if change == nil { continue } err = change.ProcessChangeV2(trie, changeIndex) if err != nil && err != wmpt.ErrNotFound { - fmt.Printf("Error processing change: %v\n", err) l.Logger.Error("Error processing change ", err) commitReq.result = ErrorCommitResult("Failed to process change " + err.Error()) return @@ -524,7 +518,6 @@ func (commitReq *CommitRequestV2) processCommit() { defer wg.Done() commitErr := commitReq.commitBlobber(rootHash, rootWeight, prevWeight, blobber) if commitErr != nil { - fmt.Printf("Error committing to blobber: %s - %v\n", blobber.Baseurl, commitErr) l.Logger.Error("Error committing to blobber: ", blobber.Baseurl, " ", commitErr) errSlice[ind] = commitErr mu.Lock() @@ -558,14 +551,12 @@ func (commitReq *CommitRequestV2) processCommit() { err = errors.New("consensus_not_met", fmt.Sprintf("Successfully committed to %d blobbers, but required %d", commitReq.commitMask.CountOnes(), commitReq.consensusThresh)) } commitReq.result = ErrorCommitResult(err.Error()) - fmt.Printf("Consensus threshold not met: %d < %d\n", commitReq.commitMask.CountOnes(), commitReq.consensusThresh) return } if !commitReq.isRepair { commitReq.allocationObj.allocationRoot = encryption.Hash(hex.EncodeToString(rootHash) + commitReq.allocationObj.ID) } l.Logger.Info("[commit] ", "elapsedGetRefPath ", elapsedGetRefPath.Milliseconds(), " elapsedProcessChanges ", elapsedProcessChanges.Milliseconds(), " elapsedCommit ", elapsedCommit.Milliseconds(), " total ", time.Since(now).Milliseconds()) - fmt.Printf("processCommit completed!\n") commitReq.result = SuccessCommitResult() } @@ -649,7 +640,6 @@ func getFormWritter(connectionID string, wmData, fileIDMetaData []byte, body *by } func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, clientIds... string) (*wmpt.WeightedMerkleTrie, error) { - fmt.Printf("initial success: %v\n", *success) if len(paths) == 0 || blobber.LatestWM == nil || blobber.LatestWM.ChainSize == 0 { var node wmpt.Node if blobber.LatestWM != nil && len(blobber.LatestWM.FileMetaRoot) > 0 && blobber.LatestWM.ChainSize > 0 { @@ -669,7 +659,6 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio err, shouldContinue = func() (err error, shouldContinue bool) { var req *http.Request req, err = zboxutil.NewReferencePathRequestV2(blobber.Baseurl, allocationID, allocationTx, sig, paths, false, clientIds...) - fmt.Printf("getReferencePathV2 req err: %v\n", err) if err != nil { l.Logger.Error("Creating ref path req", err) return @@ -677,7 +666,6 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio ctx, cncl := context.WithTimeout(context.Background(), (time.Second * 30)) err = zboxutil.HttpDo(ctx, cncl, req, func(resp *http.Response, err error) error { - fmt.Printf("HttpDo req err: %v\n", err) if err != nil { l.Logger.Error("Ref path error:", err) if errors.Is(err, http.ErrServerClosed) || strings.Contains(err.Error(), "GOAWAY") { @@ -710,8 +698,6 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio shouldContinue = true return err } - fmt.Printf("Reference path error response: Status: %d - %s ", - resp.StatusCode, string(respBody)) return errors.New( strconv.Itoa(resp.StatusCode), fmt.Sprintf("Reference path error response: Status: %d - %s ", @@ -732,7 +718,6 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio break } } - fmt.Printf("HttpDo after req err: %v\n", err) if err != nil { return nil, err } @@ -740,9 +725,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio elapsedRefPath := time.Since(now) mu.Lock() defer mu.Unlock() - fmt.Printf("after success: %v\n", *success) if *success { - fmt.Printf("errAlreadySuccessful err\n") return nil, errAlreadySuccessful } trie := wmpt.New(nil, nil) @@ -754,31 +737,28 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio useClientID = client.Id() } wallet := client.GetWalletByClientID(useClientID) - + if wallet == nil { + return nil, errors.New("wallet not found", useClientID) + } err = lR.LatestWM.VerifySignature(wallet.ClientKey) - fmt.Printf("verify signature err : %v\n", err) if err != nil { return nil, errors.New("signature_verification_failed", err.Error()) } err = trie.Deserialize(lR.Path) - fmt.Printf("Deserialize err : %v\n", err) if err != nil { l.Logger.Error("Error deserializing trie", err) return nil, err } l.Logger.Info("[getReferencePathV2] elapsedRefPath ", elapsedRefPath.Milliseconds(), " elapsedDeserialize ", (time.Since(now) - elapsedRefPath).Milliseconds()) chainBlocks := numBlocks(lR.LatestWM.ChainSize) - fmt.Printf("chain_length_mismatch: %v\n", err) if trie.Weight() != uint64(chainBlocks) { return nil, errors.New("chain_length_mismatch", fmt.Sprintf("Expected chain length %d, got %d", chainBlocks, trie.Weight())) } - fmt.Printf("allocation_root_mismatch: %v\n", err) if hex.EncodeToString(trie.Root()) != lR.LatestWM.FileMetaRoot { return nil, errors.New("allocation_root_mismatch", fmt.Sprintf("Expected allocation root %s, got %s", lR.LatestWM.AllocationRoot, hex.EncodeToString(trie.Root()))) } } *success = true - fmt.Printf("getReferencePathV2 success") return trie, nil } diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index c7cbf075b..c3f3e3eef 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -632,7 +632,7 @@ func (req *DeleteRequest) deleteSubDirectories() error { clientId := req.clientId wallet := client.GetWalletByClientID(clientId) if wallet == nil { - return errors.New("client_not_found", "wallet is not set for the client") + return errors.New("client_not_found", clientId) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.Wallet = wallet @@ -677,7 +677,7 @@ func (req *DeleteRequest) deleteSubDirectories() error { clientId := req.clientId wallet := client.GetWalletByClientID(clientId) if wallet == nil { - return errors.New("client_not_found", "wallet is not set for the client") + return errors.New("client_not_found", clientId) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.Wallet = wallet diff --git a/zboxcore/sdk/dirworker.go b/zboxcore/sdk/dirworker.go index dc64f450d..bdca91bdb 100644 --- a/zboxcore/sdk/dirworker.go +++ b/zboxcore/sdk/dirworker.go @@ -193,13 +193,10 @@ func (req *DirRequest) createDirInBlobber(blobber *blockchain.StorageNode, pos u httpreq *http.Request ) if req.wallet != nil { - fmt.Printf("req.wallet is not nil : %v", req.wallet.ClientID) httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.wallet.ClientID) } else { - fmt.Printf("req.wallet is nil : %v", req.allocationObj.Owner) httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) } - fmt.Printf("error creating dir request : %v", err) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating dir request", err) return err, false diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index a3c7dadad..fa8af5008 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -1235,30 +1235,18 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) } actualHash := fmr.fileref.ActualFileHash actualFileHashSignature := fmr.fileref.ActualFileHashSignature - fmt.Printf("[DOWNLOAD] Processing fileRef from blobber %d\n", fmr.blobberIdx) - fmt.Printf("[DOWNLOAD] FileRef SignatureVersion: %d\n", fmr.fileref.SignatureVersion) - fmt.Printf("[DOWNLOAD] FileRef ActualFileHash: %s\n", actualHash) - fmt.Printf("[DOWNLOAD] FileRef ActualFileHashSignature: %s\n", actualFileHashSignature) - fmt.Printf("[DOWNLOAD] FileRef ValidationRoot: %s\n", fmr.fileref.ValidationRoot) - fmt.Printf("[DOWNLOAD] FileRef ValidationRootSignature: %s\n", fmr.fileref.ValidationRootSignature) var ( isValid bool err error ) if fmr.fileref.SignatureVersion == SignatureV2 { - fmt.Printf("[DOWNLOAD] Using SignatureV2 verification with allocation owner signing public key\n") - fmt.Printf("[DOWNLOAD] Verification key type: allocation owner signing public key\n") - fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerSigningPubKey) isValid, err = sys.VerifyEd25519With( req.allocOwnerSigningPubKey, actualFileHashSignature, actualHash, ) } else { - fmt.Printf("[DOWNLOAD] Using legacy verification with allocation owner public key\n") - fmt.Printf("[DOWNLOAD] Verification key type: allocation owner public key\n") - fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerPubKey) isValid, err = sys.VerifyWith( req.allocOwnerPubKey, actualFileHashSignature, @@ -1266,16 +1254,13 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) ) } if err != nil { - fmt.Printf("[DOWNLOAD] Signature verification error: %v\n", err) l.Logger.Error(err) continue } if !isValid { - fmt.Printf("[DOWNLOAD] Invalid signature for blobber %d\n", fmr.blobberIdx) l.Logger.Error("invalid signature") continue } - fmt.Printf("[DOWNLOAD] Signature verification successful for blobber %d\n", fmr.blobberIdx) retMap[actualFileHashSignature]++ if retMap[actualFileHashSignature] > req.consensus { @@ -1317,25 +1302,18 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) hashData := fmt.Sprintf("%s:%s:%s:%s", fRef.ActualFileHash, fRef.ValidationRoot, fRef.FixedMerkleRoot, req.blobbers[i].ID) hash = encrypt.Hash(hashData) } - fmt.Printf("[DOWNLOAD] Verifying validation root signature for blobber %d\n", i) - fmt.Printf("[DOWNLOAD] Validation root hash: %s\n", hash) - fmt.Printf("[DOWNLOAD] Validation root signature: %s\n", fRef.ValidationRootSignature) var ( isValid bool err error ) if fRef.SignatureVersion == SignatureV2 { - fmt.Printf("[DOWNLOAD] Using SignatureV2 verification for validation root\n") - fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerSigningPubKey) isValid, err = sys.VerifyEd25519With( req.allocOwnerSigningPubKey, fRef.ValidationRootSignature, hash, ) } else { - fmt.Printf("[DOWNLOAD] Using legacy verification for validation root\n") - fmt.Printf("[DOWNLOAD] Verification key: %s\n", req.allocOwnerPubKey) isValid, err = sys.VerifyWith( req.allocOwnerPubKey, fRef.ValidationRootSignature, @@ -1343,16 +1321,13 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) ) } if err != nil { - fmt.Printf("[DOWNLOAD] Validation root signature verification error: %v\n", err) l.Logger.Error(err, "allocOwnerPubKey: ", req.allocOwnerPubKey, " validationRootSignature: ", fRef.ValidationRootSignature, " actualFileHashSignature: ", fRef.ActualFileHashSignature, " validationRoot: ", fRef.ValidationRoot) continue } if !isValid { - fmt.Printf("[DOWNLOAD] Invalid validation root signature for blobber %d\n", i) l.Logger.Error("invalid validation root signature") continue } - fmt.Printf("[DOWNLOAD] Validation root signature verification successful for blobber %d\n", i) blobber := req.blobbers[fmr.blobberIdx] vr, _ := hex.DecodeString(fmr.fileref.ValidationRoot) diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index 2c4d3d52e..b70883049 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -68,8 +68,6 @@ type MultiOperation struct { } func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { - // fmt.Printf("Creating connection object for blobber index %d with connection ID %s", blobberIdx, mo.connectionID) - fmt.Printf("Creating connection object for blobber index %d with connection ID %s\n", blobberIdx, mo.connectionID) defer func() { if err == nil { mo.maskMU.Lock() @@ -88,7 +86,6 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { blobber := mo.allocationObj.Blobbers[blobberIdx] for i := 0; i < 3; i++ { - fmt.Printf("Iter %d", i+1) err, shouldContinue = func() (err error, shouldContinue bool) { body := new(bytes.Buffer) formWriter := multipart.NewWriter(body) @@ -99,56 +96,19 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { } formWriter.Close() - fmt.Printf("Creating connection object for blobber %s with connection ID %s", blobber.Baseurl, mo.connectionID) var httpreq *http.Request if mo.Wallet != nil { - fmt.Printf("mo wallet : %v", *mo.Wallet) httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.Wallet.ClientID) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating new connection request by wallet", err) return err, false } - - - // log - - fmt.Printf("Request created with wallet") - fmt.Printf("Request URL: %s\n", httpreq.URL.String()) - fmt.Printf("Request Method: %s\n", httpreq.Method) - fmt.Printf("Request Headers:\n") - for k, v := range httpreq.Header { - fmt.Printf(" %s: %v\n", k, v) - } - if httpreq.Body != nil { - bodyBytes, _ := io.ReadAll(httpreq.Body) - fmt.Printf("Request Body: %s\n", string(bodyBytes)) - // Restore body for later use - httpreq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - } - } else { - fmt.Printf("No wallet") httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.allocationObj.Owner) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating new connection request", err) return } - - // log - - fmt.Printf("Request created without wallet") - fmt.Printf("Request URL: %s\n", httpreq.URL.String()) - fmt.Printf("Request Method: %s\n", httpreq.Method) - fmt.Printf("Request Headers:\n") - for k, v := range httpreq.Header { - fmt.Printf(" %s: %v\n", k, v) - } - if httpreq.Body != nil { - bodyBytes, _ := io.ReadAll(httpreq.Body) - fmt.Printf("Request Body: %s\n", string(bodyBytes)) - // Restore body for later use - httpreq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - } } httpreq.Header.Add("Content-Type", formWriter.FormDataContentType()) @@ -158,7 +118,6 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { resp = r return err }) - fmt.Printf("Create Connection Err: %v", err) if err != nil { logger.Logger.Error("Create Connection: ", err) return @@ -176,8 +135,6 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { latestRespMsg = string(respBody) latestStatusCode = resp.StatusCode - fmt.Printf("resp status code : %v", latestStatusCode) - fmt.Printf("resp status body : %v", latestRespMsg) if resp.StatusCode == http.StatusOK { l.Logger.Debug(blobber.Baseurl, " connection obj created.") return @@ -199,8 +156,6 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { err = errors.New("response_error", string(respBody)) return }() - - fmt.Printf("Iter %d; err : %v, shouldContinue: %v", i+1, err, shouldContinue) if err != nil { return } @@ -216,8 +171,6 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { } func (mo *MultiOperation) Process() error { - fmt.Printf("MultiOperation Process start") - fmt.Printf("MultiOperation mo.Wallet : %v", mo.Wallet) l.Logger.Debug("MultiOperation Process start") wg := &sync.WaitGroup{} if mo.allocationObj.StorageVersion == 0 { @@ -382,10 +335,7 @@ func (mo *MultiOperation) Process() error { } if mo.allocationObj.StorageVersion == StorageV2 { - fmt.Printf("Commit V2 called!") - err = mo.commitV2() - fmt.Printf("Commit V2 returned: %v\n", err) - return err + return mo.commitV2() } commitReqs := make([]*CommitRequest, activeBlobbers) @@ -455,7 +405,6 @@ func (mo *MultiOperation) Process() error { } func (mo *MultiOperation) commitV2() error { - fmt.Printf("commitV2 called \n") rootMap := make(map[string]zboxutil.Uint128) var pos uint64 for i := mo.operationMask; !i.Equals64(0); i = i.And(zboxutil.NewUint128(1).Lsh(pos).Not()) { @@ -493,11 +442,6 @@ func (mo *MultiOperation) commitV2() error { } commitReqs[counter] = commitReq counter++ - if commitReq.wallet != nil { - fmt.Printf("commitReq wallet ID : %v", commitReq.wallet.ClientID) - } else { - fmt.Printf("commitReq wallet is nil \n") - } go AddCommitRequest(commitReq) } wg.Wait() diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 2e8480355..2044c033b 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -72,6 +72,9 @@ func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, clientId ...strin useClientID = client.Id() } wallet := client.GetWalletByClientID(useClientID) + if wallet == nil { + return nil, errors.New("wallet not found : " + useClientID) + } req, err := zboxutil.NewWritemarkerRequest(baseUrl, allocID, allocTx, sig, clientId...) if err != nil { diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 78eff6825..872f29738 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -1485,8 +1485,6 @@ func updateMaskBit(mask uint16, index uint8, value bool) uint16 { } func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback) error { - - fmt.Printf("Starting multi upload with walletID: %v, walletKey: %v", wallet.ClientID, wallet.ClientKey) if len(localPaths) != len(thumbnailPaths) { return errors.New("invalid_value", "length of localpaths and thumbnailpaths must be equal") @@ -1589,6 +1587,4 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin mo.Wallet = &wallet } return a.DoMultiOperation(operationRequests, setWalletOpt) - - // return allocationObj.StartMultiUpload(workdir, localPaths, fileNames, thumbnailPaths, encrypts, chunkNumbers, remotePaths, isUpdate, isWebstreaming, status) } diff --git a/zboxcore/sdk/upload_worker.go b/zboxcore/sdk/upload_worker.go index 73b6ad7eb..285443c1e 100644 --- a/zboxcore/sdk/upload_worker.go +++ b/zboxcore/sdk/upload_worker.go @@ -5,7 +5,6 @@ import ( "context" "encoding/hex" "errors" - "fmt" "io" "strings" @@ -32,7 +31,6 @@ type UploadOperation struct { var ErrPauseUpload = errors.New("upload paused by user") func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { - fmt.Printf("upload operation started\n") if uo.isDownload { if f, ok := uo.chunkedUpload.fileReader.(sys.File); ok { err := allocObj.DownloadFileToFileHandler(f, uo.chunkedUpload.fileMeta.RemotePath, false, nil, true, WithFileCallback(func() { @@ -45,7 +43,6 @@ func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([ } } err := uo.chunkedUpload.process() - fmt.Printf("process returned: %v\n", err) if err != nil { l.Logger.Error("UploadOperation Failed", zap.String("name", uo.chunkedUpload.fileMeta.RemoteName), zap.Error(err)) return nil, uo.chunkedUpload.uploadMask, err @@ -67,7 +64,6 @@ func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([ } uo.lookupHash = fileref.GetReferenceLookup(uo.chunkedUpload.allocationObj.ID, uo.chunkedUpload.fileMeta.RemotePath) l.Logger.Debug("UploadOperation Success", zap.String("name", uo.chunkedUpload.fileMeta.RemoteName)) - fmt.Printf("UploadOperation Success: %s\n", uo.chunkedUpload.fileMeta.RemoteName) return nil, uo.chunkedUpload.uploadMask, nil } @@ -139,7 +135,6 @@ func NewUploadOperation(ctx context.Context, workdir string, allocObj *Allocatio } cu, err := CreateChunkedUpload(ctx, workdir, allocObj, fileMeta, fileReader, isUpdate, isRepair, isWebstreaming, connectionID, opts...) - fmt.Printf("CreateChunkedUpload returned: %v", err) if err != nil { return nil, "", err } diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index b403ca032..b7d587261 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -203,6 +203,9 @@ func NewHTTPRequest(method string, url string, data []byte) (*http.Request, cont func setClientInfo(req *http.Request, clientIds... string) { if len(clientIds) > 0 && clientIds[0] != "" { wallet := client.GetWalletByClientID(clientIds[0]) + if wallet == nil { + panic("wallet not found : " + clientIds[0]) + } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) return @@ -219,8 +222,9 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, c clientID = client.Id() } wallet := client.GetWalletByClientID(clientID) - fmt.Printf("setClientInfoWithSign: clientID: %s, allocation: %s, baseURL: %s\n", clientID, allocation, baseURL) - fmt.Printf("setClientInfoWithSign: wallet: %v\n", wallet) + if wallet == nil { + return errors.New("wallet not found", clientID) + } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) @@ -672,8 +676,9 @@ func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string clientID = client.Id() } wallet := client.GetWalletByClientID(clientID) - fmt.Printf("setFastClientInfoWithSign: clientID: %s, allocation: %s, baseURL: %s\n", clientID, allocation, baseURL) - fmt.Printf("setFastClientInfoWithSign: wallet: %v\n", wallet) + if wallet == nil { + return errors.New("wallet not found", clientID) + } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) diff --git a/znft/keystore.go b/znft/keystore.go index 14ea36680..4762acda9 100644 --- a/znft/keystore.go +++ b/znft/keystore.go @@ -30,7 +30,7 @@ func DeleteAccount(homedir, address string) bool { }) if err != nil && wallet == nil { - Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err))`` + Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err)) return false } From 2d4071fba85dcd5ea6cae26de0b38a61e579f40f Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sun, 3 Aug 2025 12:01:02 +0530 Subject: [PATCH 06/47] fix compilation --- znft/znft.go | 1 - 1 file changed, 1 deletion(-) diff --git a/znft/znft.go b/znft/znft.go index 5a5b27224..54f18dd5c 100644 --- a/znft/znft.go +++ b/znft/znft.go @@ -2,7 +2,6 @@ package znft import ( "context" - "fmt" "os" "github.com/0chain/gosdk/core/logger" From df4dbdf40bf88835b8010ea8d021b9c7c147ac15 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 19 Aug 2025 21:08:18 +0530 Subject: [PATCH 07/47] client id support in zauth sign --- core/client/set.go | 4 ++-- core/client/zauth.go | 20 ++++++++++++++++++-- core/sys/sign.go | 2 +- zboxcore/zboxutil/http.go | 1 + 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index dbd097c55..da2d9821a 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -73,7 +73,7 @@ func init() { if !wallet.IsSplit { return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(clients...)) } - + fmt.Printf("Sign: wallet details: %+v\n", *wallet) // get sign lock <-sigC fmt.Println("Sign: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeys(clients...)) @@ -128,7 +128,7 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientId return "", errors.New("authCommon is not set") } - rsp, err := sys.AuthCommon(string(data)) + rsp, err := sys.AuthCommon(string(data), clientID) if err != nil { return "", err } diff --git a/core/client/zauth.go b/core/client/zauth.go index 9e31f3457..a38179653 100644 --- a/core/client/zauth.go +++ b/core/client/zauth.go @@ -535,7 +535,7 @@ func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) { // ZauthSignTxn returns a function that sends a txn signing request to the zauth server func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { - return func(msg string) (string, error) { + return func(msg string, clientIds ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -543,6 +543,14 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { req.Header.Set("Content-Type", "application/json") c := GetClient() pubkey := c.Keys[0].PublicKey + if len(clientIds) > 0 { + c = GetWalletByClientID(clientIds[0]) + if c == nil { + return "", errors.Errorf("wallet not found for client ID: %s", clientIds[0]) + } + pubkey = c.Keys[0].PublicKey + } + req.Header.Set("X-Peer-Public-Key", pubkey) client := &http.Client{} @@ -572,7 +580,7 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { } func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { - return func(msg string) (string, error) { + return func(msg string, clientIds ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -580,6 +588,14 @@ func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { c := GetClient() pubkey := c.Keys[0].PublicKey + if len(clientIds) > 0 { + c = GetWalletByClientID(clientIds[0]) + if c == nil { + return "", errors.Errorf("wallet not found for client ID: %s", clientIds[0]) + } + pubkey = c.Keys[0].PublicKey + } + req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Peer-Public-Key", pubkey) diff --git a/core/sys/sign.go b/core/sys/sign.go index 0b58a6e58..186729726 100644 --- a/core/sys/sign.go +++ b/core/sys/sign.go @@ -16,4 +16,4 @@ type VerifyFunc func(signature string, msg string) (bool, error) type VerifyWithFunc func(pk, signature string, msg string) (bool, error) -type AuthorizeFunc func(msg string) (string, error) +type AuthorizeFunc func(msg string, clientIds... string) (string, error) diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index b7d587261..927290502 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -225,6 +225,7 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, c if wallet == nil { return errors.New("wallet not found", clientID) } + fmt.Printf("setClientInfoWithSign: wallet details: %+v\n", *wallet) req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) From a8fbe2e0f5689091da650cafaaee6a1a35daecfd Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 2 Sep 2025 11:57:26 +0530 Subject: [PATCH 08/47] add godocs --- core/client/set.go | 4 +++- zboxcore/sdk/sdk.go | 1 + zboxcore/zboxutil/http.go | 47 ++++++++++++++++++++------------------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index da2d9821a..e5df9e3c3 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -223,6 +223,7 @@ func SetWallet(w zcncrypto.Wallet) { client.wallets[w.ClientID] = &w } +// GetWalletByClientID gets a wallet by client id. func GetWalletByClientID(clientID string) *zcncrypto.Wallet { if client.wallets == nil { return nil @@ -233,6 +234,7 @@ func GetWalletByClientID(clientID string) *zcncrypto.Wallet { return client.wallets[clientID] } +// AddWallet adds a new wallet to the sdk. func AddWallet(wallet zcncrypto.Wallet) { if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) @@ -245,7 +247,7 @@ func AddWallet(wallet zcncrypto.Wallet) { client.wallets[wallet.ClientID] = &wallet } -// RemoveWallet should be set before any transaction or client specific APIs +// RemoveWallet removes a wallet from the sdk. func RemoveWallet(clientID string) { client.wg[clientID].Done() client.walletCount[clientID]-- diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 872f29738..0b018bca4 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -1484,6 +1484,7 @@ func updateMaskBit(mask uint16, index uint8, value bool) uint16 { } } +// DoMultiUploadByWallet uploads multiple files to the allocation using the given wallet. func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback) error { if len(localPaths) != len(thumbnailPaths) { diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index 927290502..cb2225127 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -724,29 +724,30 @@ func NewUploadRequest(baseUrl, allocationID, allocationTx, sig string, body io.R return req, nil } -func NewConnectionRequestByWallet(baseUrl, allocationID, allocationTx, sig string, body io.Reader, wallet *zcncrypto.Wallet) (*http.Request, error) { - l.Logger.Info(fmt.Sprintf("NewConnectionRequestByWallet: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) - u, err := joinUrl(baseUrl, CREATE_CONNECTION_ENDPOINT, allocationTx) - if err != nil { - return nil, err - } - req, err := http.NewRequest(http.MethodPost, u.String(), body) - if err != nil { - return nil, err - } - req.Header.Set("X-App-Client-ID", wallet.ClientID) - req.Header.Set("X-App-Client-Key", wallet.ClientKey) - req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) - hashData := allocationTx + baseUrl - sig2, err := wallet.Sign(encryption.Hash(hashData), constants.BLS0CHAIN.String()) - if err != nil { - return nil, err - } - req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) - req.Header.Set(CLIENT_SIGNATURE_HEADER_V2, sig2) - req.Header.Set(ALLOCATION_ID_HEADER, allocationID) - return req, nil -} +// NewConnectionRequestByWallet creates a new connection request using the given wallet. +// func NewConnectionRequestByWallet(baseUrl, allocationID, allocationTx, sig string, body io.Reader, wallet *zcncrypto.Wallet) (*http.Request, error) { +// l.Logger.Info(fmt.Sprintf("NewConnectionRequestByWallet: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) +// u, err := joinUrl(baseUrl, CREATE_CONNECTION_ENDPOINT, allocationTx) +// if err != nil { +// return nil, err +// } +// req, err := http.NewRequest(http.MethodPost, u.String(), body) +// if err != nil { +// return nil, err +// } +// req.Header.Set("X-App-Client-ID", wallet.ClientID) +// req.Header.Set("X-App-Client-Key", wallet.ClientKey) +// req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) +// hashData := allocationTx + baseUrl +// sig2, err := wallet.Sign(encryption.Hash(hashData), constants.BLS0CHAIN.String()) +// if err != nil { +// return nil, err +// } +// req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) +// req.Header.Set(CLIENT_SIGNATURE_HEADER_V2, sig2) +// req.Header.Set(ALLOCATION_ID_HEADER, allocationID) +// return req, nil +// } func NewConnectionRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, clients ...string) (*http.Request, error) { l.Logger.Info(fmt.Sprintf("NewConnectionRequest: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) From f1a2b7a756c58e20a567f1e18630d9008021d129 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 2 Sep 2025 12:04:53 +0530 Subject: [PATCH 09/47] revert keystore.go same as staging --- znft/keystore.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/znft/keystore.go b/znft/keystore.go index 4762acda9..757f329d5 100644 --- a/znft/keystore.go +++ b/znft/keystore.go @@ -5,6 +5,7 @@ import ( "os" "path" + log "github.com/0chain/gosdk/zcnbridge/log" hdw "github.com/0chain/gosdk/zcncore/ethhdwallet" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -30,7 +31,7 @@ func DeleteAccount(homedir, address string) bool { }) if err != nil && wallet == nil { - Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err)) + log.Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err)) return false } @@ -54,17 +55,17 @@ func AccountExists(homedir, address string) bool { }) if err != nil && wallet == nil { - Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err)) + log.Logger.Error(fmt.Sprintf("failed to find account %s, error: %s", address, err)) return false } status, _ := wallet.Status() url := wallet.URL() - Logger.Info( + log.Logger.Info( fmt.Sprintf("Account exists. Status: %s, Path: %s", status, url), ) - + return true } @@ -76,10 +77,10 @@ func CreateKeyStorage(homedir, password string) error { if err != nil { return errors.Wrap(err, "failed to create keystore") } - Logger.Info( + log.Logger.Info( fmt.Sprintf("Created account: %s", account.Address.Hex()), ) - + return nil } @@ -144,7 +145,7 @@ func ImportAccount(homedir, mnemonic, password string) (string, error) { // 3. Find key acc, err := ks.Find(account) if err == nil { - Logger.Info( + log.Logger.Info( fmt.Sprintf("Account already exists: %s\nPath: %s\n\n", acc.Address.Hex(), acc.URL.Path), ) return acc.Address.Hex(), nil @@ -156,9 +157,9 @@ func ImportAccount(homedir, mnemonic, password string) (string, error) { return "", errors.Wrap(err, "failed to get import private key") } - Logger.Info( + log.Logger.Info( fmt.Sprintf("Imported account %s to path: %s\n", acc.Address.Hex(), acc.URL.Path), ) - + return acc.Address.Hex(), nil } From 6b1ddf594266b9d66264b5d53205d11cb4174c4b Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 2 Sep 2025 12:08:12 +0530 Subject: [PATCH 10/47] fix compilation --- zboxcore/zboxutil/http.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index cb2225127..05e01891b 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -17,11 +17,9 @@ import ( "github.com/hashicorp/golang-lru/v2/simplelru" "github.com/0chain/errors" - "github.com/0chain/gosdk/constants" "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/encryption" "github.com/0chain/gosdk/core/logger" - "github.com/0chain/gosdk/core/zcncrypto" l "github.com/0chain/gosdk/zboxcore/logger" lru "github.com/hashicorp/golang-lru/v2" "github.com/hitenjain14/fasthttp" From 34f7c5f20babf816871d983cf0b0ad7cc2f6b8aa Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 2 Sep 2025 12:16:52 +0530 Subject: [PATCH 11/47] fix compilation --- mobilesdk/sdk/sdk.go | 2 +- wasmsdk/auth_txn.go | 4 ++-- wasmsdk/proxy.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mobilesdk/sdk/sdk.go b/mobilesdk/sdk/sdk.go index 8ce6558c9..d9b78bcfd 100644 --- a/mobilesdk/sdk/sdk.go +++ b/mobilesdk/sdk/sdk.go @@ -33,7 +33,7 @@ var nonce = int64(0) var allocationIDRequired = errors.Errorf("Allocation ID is required") type Autorizer interface { - Auth(msg string) (string, error) + Auth(msg string, clientIDs ...string) (string, error) } // ChainConfig - blockchain config diff --git a/wasmsdk/auth_txn.go b/wasmsdk/auth_txn.go index e917512e5..aa8354446 100644 --- a/wasmsdk/auth_txn.go +++ b/wasmsdk/auth_txn.go @@ -29,7 +29,7 @@ func registerAuthorizer(this js.Value, args []js.Value) interface{} { authCallback = parseAuthorizerCallback(args[0]) authResponseC = make(chan string, 1) - sys.Authorize = func(msg string) (string, error) { + sys.Authorize = func(msg string, clientIDs ...string) (string, error) { authCallback(msg) return <-authResponseC, nil } @@ -93,7 +93,7 @@ func registerAuthCommon(this js.Value, args []js.Value) interface{} { authMsgCallback = parseAuthorizerCallback(args[0]) authMsgResponseC = make(chan string, 1) - sys.AuthCommon = func(msg string) (string, error) { + sys.AuthCommon = func(msg string, clientIDs ...string) (string, error) { authMsgLock <- struct{}{} defer func() { <-authMsgLock diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index 16b1d0045..ec56f3ec0 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -478,7 +478,7 @@ func main() { gInitProxyKeys(publicKey, privateKey) if isSplit { - sys.AuthCommon = func(msg string) (string, error) { + sys.AuthCommon = func(msg string, clientIDs ...string) (string, error) { // send message to main thread sendMessageToMainThread(msg) // wait for response from main thread From d497ed3776998e9f0e64329af2ce5ec1b34fe8ec Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Sat, 27 Sep 2025 22:59:20 +0530 Subject: [PATCH 12/47] move method changes for multi wallet --- zboxcore/sdk/renameworker.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/zboxcore/sdk/renameworker.go b/zboxcore/sdk/renameworker.go index 644bfcc75..6881dcd1e 100644 --- a/zboxcore/sdk/renameworker.go +++ b/zboxcore/sdk/renameworker.go @@ -45,10 +45,15 @@ type RenameRequest struct { connectionID string consensus Consensus timestamp int64 + clientId string } func (req *RenameRequest) getObjectTreeFromBlobber(blobber *blockchain.StorageNode) (fileref.RefEntity, error) { - return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner) + clientId := req.clientId + if clientId == "" { + clientId = req.allocationObj.Owner + } + return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner, clientId) } func (req *RenameRequest) getFileMetaFromBlobber(pos int) (fileRef *fileref.FileRef, err error) { @@ -117,7 +122,11 @@ func (req *RenameRequest) renameBlobberObject( formWriter.Close() var httpreq *http.Request - httpreq, err = zboxutil.NewRenameRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) + clientId := req.clientId + if clientId == "" { + clientId = req.allocationObj.Owner + } + httpreq, err = zboxutil.NewRenameRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -418,6 +427,7 @@ type RenameOperation struct { newName string maskMU *sync.Mutex objectTreeRefs []fileref.RefEntity + clientId string consensus Consensus } @@ -439,6 +449,7 @@ func (ro *RenameOperation) Process(allocObj *Allocation, connectionID string) ([ maskMU: ro.maskMU, wg: &sync.WaitGroup{}, consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: ro.clientId } if filepath.Base(ro.remotefilepath) == ro.newName { return nil, ro.renameMask, errors.New("invalid_operation", "Cannot rename to same name") @@ -526,7 +537,7 @@ func (ro *RenameOperation) Error(allocObj *Allocation, consensus int, err error) } -func NewRenameOperation(remotePath string, destName string, renameMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context) *RenameOperation { +func NewRenameOperation(remotePath string, destName string, renameMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string) *RenameOperation { ro := &RenameOperation{} ro.remotefilepath = zboxutil.RemoteClean(remotePath) ro.newName = path.Base(destName) @@ -535,6 +546,7 @@ func NewRenameOperation(remotePath string, destName string, renameMask zboxutil. ro.consensus.consensusThresh = consensusTh ro.consensus.fullconsensus = fullConsensus ro.ctx, ro.ctxCncl = context.WithCancel(ctx) + ro.clientId = clientId return ro } From d27ab0c90e5b7efcd5bf7e19f1aca2ec93561d43 Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Sat, 27 Sep 2025 23:04:00 +0530 Subject: [PATCH 13/47] move method changes for multi wallet --- zboxcore/sdk/moveworker.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/zboxcore/sdk/moveworker.go b/zboxcore/sdk/moveworker.go index 2bceac689..2294e09c0 100644 --- a/zboxcore/sdk/moveworker.go +++ b/zboxcore/sdk/moveworker.go @@ -45,11 +45,16 @@ type MoveRequest struct { connectionID string timestamp int64 destLookupHash string + clientId string Consensus } func (req *MoveRequest) getObjectTreeFromBlobber(blobber *blockchain.StorageNode) (fileref.RefEntity, error) { - return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner) + clientId := req.clientId + if clientId == "" { + clientId = req.allocationObj.Owner + } + return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner, clientId) } func (req *MoveRequest) getFileMetaFromBlobber(pos int) (fileRef *fileref.FileRef, err error) { @@ -122,7 +127,11 @@ func (req *MoveRequest) moveBlobberObject( cncl context.CancelFunc ) - httpreq, err = zboxutil.NewMoveRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) + clientId := req.clientId + if clientId == "" { + clientId = req.allocationObj.Owner + } + httpreq, err = zboxutil.NewMoveRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -422,6 +431,7 @@ type MoveOperation struct { maskMU *sync.Mutex consensus Consensus objectTreeRefs []fileref.RefEntity + clientId string } func (mo *MoveOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { @@ -439,6 +449,7 @@ func (mo *MoveOperation) Process(allocObj *Allocation, connectionID string) ([]f maskMU: mo.maskMU, destPath: mo.destPath, Consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: mo.clientId, } mR.Consensus.fullconsensus = mo.consensus.fullconsensus mR.Consensus.consensusThresh = mo.consensus.consensusThresh @@ -518,7 +529,7 @@ func (mo *MoveOperation) Error(allocObj *Allocation, consensus int, err error) { } -func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context) *MoveOperation { +func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string) *MoveOperation { mo := &MoveOperation{} mo.remotefilepath = zboxutil.RemoteClean(remotePath) if destPath != "/" { @@ -530,6 +541,7 @@ func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint mo.consensus.consensusThresh = consensusTh mo.consensus.fullconsensus = fullConsensus mo.ctx, mo.ctxCncl = context.WithCancel(ctx) + mo.clientId = clientId return mo } From 7fb10ba109833203894567be86e2cf64738a3bfb Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Sat, 27 Sep 2025 23:23:13 +0530 Subject: [PATCH 14/47] copy changes for multi wallet --- zboxcore/sdk/copyworker.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zboxcore/sdk/copyworker.go b/zboxcore/sdk/copyworker.go index 9d77f2425..5e7d1bbd9 100644 --- a/zboxcore/sdk/copyworker.go +++ b/zboxcore/sdk/copyworker.go @@ -46,6 +46,7 @@ type CopyRequest struct { timestamp int64 dirOnly bool destLookupHash string + clientId string Consensus } @@ -130,7 +131,11 @@ func (req *CopyRequest) copyBlobberObject( cncl context.CancelFunc ) - httpreq, err = zboxutil.NewCopyRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) + clientId := req.clientId + if clientId == "" { + clientId = req.allocationObj.Owner + } + httpreq, err = zboxutil.NewCopyRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -417,6 +422,7 @@ type CopyOperation struct { copyMask zboxutil.Uint128 maskMU *sync.Mutex objectTreeRefs []fileref.RefEntity + clientId string Consensus } @@ -438,6 +444,7 @@ func (co *CopyOperation) Process(allocObj *Allocation, connectionID string) ([]f maskMU: co.maskMU, dirOnly: co.dirOnly, Consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: co.clientId, } cR.consensusThresh = co.consensusThresh @@ -517,7 +524,7 @@ func (co *CopyOperation) Error(allocObj *Allocation, consensus int, err error) { } -func NewCopyOperation(ctx context.Context, remotePath string, destPath string, copyMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh, fullConsensus int, copyDirOnly bool) *CopyOperation { +func NewCopyOperation(ctx context.Context, remotePath string, destPath string, copyMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh, fullConsensus int, copyDirOnly bool, clientId string) *CopyOperation { co := &CopyOperation{} co.remotefilepath = zboxutil.RemoteClean(remotePath) co.copyMask = copyMask @@ -530,6 +537,7 @@ func NewCopyOperation(ctx context.Context, remotePath string, destPath string, c co.destPath = destPath co.ctx, co.ctxCncl = context.WithCancel(ctx) co.dirOnly = copyDirOnly + co.clientId = clientId return co } From a574e9fa3dea81c7e1d20f8fb36ee01621b3c3a2 Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Sat, 27 Sep 2025 23:28:12 +0530 Subject: [PATCH 15/47] add clientId for all operations --- zboxcore/sdk/allocation.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 8b605f5f5..83c75cab8 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1139,13 +1139,31 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul switch op.OperationType { case constants.FileOperationRename: - operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx) + var clientId string + if mo.Wallet != nil { + clientId = mo.Wallet.ClientID + } else { + clientId = mo.allocationObj.Owner + } + operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, clientId) case constants.FileOperationCopy: - operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly) + var clientId string + if mo.Wallet != nil { + clientId = mo.Wallet.ClientID + } else { + clientId = mo.allocationObj.Owner + } + operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly, clientId) case constants.FileOperationMove: - operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx) + var clientId string + if mo.Wallet != nil { + clientId = mo.Wallet.ClientID + } else { + clientId = mo.allocationObj.Owner + } + operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, clientId) case constants.FileOperationInsert: cancelLock.Lock() From 346ab9774fb72e0210ff4b16bfed3c2c05a6a0c3 Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Sun, 28 Sep 2025 00:50:58 +0530 Subject: [PATCH 16/47] make public key as key for wallet map --- core/client/set.go | 102 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index e5df9e3c3..bb999f486 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -66,8 +66,17 @@ func init() { Sign = func(hash string, clients ...string) (string, error) { wallet := client.wallet - if len(clients) > 0 && clients[0] != "" && client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] + if len(clients) > 0 && clients[0] != "" { + if client.wallets[clients[0]] != nil { + wallet = client.wallets[clients[0]] + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + wallet = w + break + } + } + } } if !wallet.IsSplit { @@ -197,9 +206,20 @@ func verifyEd25519With(pubKey, signature, hash string) (bool, error) { func GetClientSysKeys(clients ...string) []sys.KeyPair { var wallet *zcncrypto.Wallet - if len(clients) > 0 && clients[0] != "" && client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] - } else { + if len(clients) > 0 && clients[0] != "" { + if client.wallets[clients[0]] != nil { + wallet = client.wallets[clients[0]] + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + wallet = w + break + } + } + } + } + + if wallet == nil{ wallet = client.wallet } @@ -220,7 +240,14 @@ func SetWallet(w zcncrypto.Wallet) { if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) } - client.wallets[w.ClientID] = &w + client.wallets[w.ClientKey] = &w +} + +func GetWalletByClientKey(clientKey string) *zcncrypto.Wallet { + if client.wallets == nil { + return nil + } + return client.wallets[clientKey] } // GetWalletByClientID gets a wallet by client id. @@ -231,28 +258,45 @@ func GetWalletByClientID(clientID string) *zcncrypto.Wallet { if _, exists := client.wallets[clientID]; !exists { return nil } - return client.wallets[clientID] + + for _, wallet := range client.wallets { + if wallet.ClientID == clientID { + return wallet + } + } + + return nil } // AddWallet adds a new wallet to the sdk. func AddWallet(wallet zcncrypto.Wallet) { + clientKey := wallet.ClientKey if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) } if _, exists := client.wg[wallet.ClientID]; !exists { client.wg[wallet.ClientID] = &sync.WaitGroup{} } - client.wg[wallet.ClientID].Add(1) - client.walletCount[wallet.ClientID]++ - client.wallets[wallet.ClientID] = &wallet + client.wg[clientKey].Add(1) + client.walletCount[clientKey]++ + client.wallets[clientKey] = &wallet } // RemoveWallet removes a wallet from the sdk. -func RemoveWallet(clientID string) { - client.wg[clientID].Done() - client.walletCount[clientID]-- - if client.walletCount[clientID] == 0 { - delete(client.wallets, clientID) +func RemoveWallet(clientKey string) { + client.wg[clientKey].Done() + client.walletCount[clientKey]-- + if client.walletCount[clientKey] == 0 { + delete(client.wallets, clientKey) + } +} + +func RemoveWalletByClientID(clientID string) { + for clientKey, wallet := range client.wallets { + if wallet.ClientID == clientID { + RemoveWallet(clientKey) + return + } } } @@ -327,12 +371,16 @@ func IsWalletSet() bool { } func PublicKey(clients ...string) string { - if len(clients) > 0 && clients[0] != "" && client.wallets[clients[0]] != nil { - if client.wallets[clients[0]] == nil { - fmt.Println("Public key is empty") - return "" + if len(clients) > 0 && clients[0] != "" { + if client.wallets[clients[0]] != nil { + return client.wallets[clients[0]].ClientKey + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + return w.ClientKey + } + } } - return client.wallets[clients[0]].ClientKey } return client.wallet.ClientKey @@ -350,12 +398,16 @@ func PrivateKey() string { } func Id(clients ...string) string { - if len(clients) > 0 && clients[0] != "" && client.wallets[clients[0]] != nil { - if client.wallets[clients[0]] == nil { - fmt.Println("Id is empty : ", clients[0]) - return "" + if len(clients) > 0 && clients[0] != "" { + if client.wallets[clients[0]] != nil { + return client.wallets[clients[0]].ClientID + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + return w.ClientID + } + } } - return client.wallets[clients[0]].ClientID } return client.wallet.ClientID } From ea5f6a85d5210cd6d289b7216675960aefca3f9d Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Thu, 2 Oct 2025 03:57:54 +0530 Subject: [PATCH 17/47] created SignByMultiWallet function --- core/client/set.go | 94 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index bb999f486..954fe4b7f 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -19,12 +19,15 @@ var ( client Client sdkInitialized bool - Sign SignFunc - sigC = make(chan struct{}, 1) + Sign SignFunc + SignByMultiWallet SignByMultiWalletFunc + sigC = make(chan struct{}, 1) ) type SignFunc func(hash string, clients ...string) (string, error) +type SignByMultiWalletFunc func(hash string, pubkey string, clients ...string) (string, error) + // maintains client's information type Client struct { wallet *zcncrypto.Wallet @@ -91,6 +94,59 @@ func init() { return sig, err } + SignByMultiWallet = func(hash string, pubkey string, clients ...string) (string, error) { + var wallet *zcncrypto.Wallet + + // First try to find wallet by public key + if pubkey != "" { + if client.wallets[pubkey] != nil { + wallet = client.wallets[pubkey] + } else { + // Fallback to searching by client ID if pubkey not found + if len(clients) > 0 && clients[0] != "" { + if client.wallets[clients[0]] != nil { + wallet = client.wallets[clients[0]] + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + wallet = w + break + } + } + } + } + } + } else if len(clients) > 0 && clients[0] != "" { + // If no pubkey provided, fallback to client ID lookup + if client.wallets[clients[0]] != nil { + wallet = client.wallets[clients[0]] + } else { + for _, w := range client.wallets { + if w.ClientID == clients[0] { + wallet = w + break + } + } + } + } + + // If no wallet found, use default wallet + if wallet == nil { + wallet = client.wallet + } + + if !wallet.IsSplit { + return sys.Sign(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet)) + } + fmt.Printf("SignByMultiWallet: wallet details: %+v\n", *wallet) + // get sign lock + <-sigC + fmt.Println("SignByMultiWallet: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeysByWallet(wallet)) + sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet), wallet.ClientID) + sigC <- struct{}{} + return sig, err + } + sys.Verify = verifySignature sys.VerifyWith = verifySignatureWith sys.VerifyEd25519With = verifyEd25519With @@ -217,9 +273,9 @@ func GetClientSysKeys(clients ...string) []sys.KeyPair { } } } - } - - if wallet == nil{ + } + + if wallet == nil { wallet = client.wallet } @@ -234,6 +290,22 @@ func GetClientSysKeys(clients ...string) []sys.KeyPair { return keys } +func GetClientSysKeysByWallet(wallet *zcncrypto.Wallet) []sys.KeyPair { + if wallet == nil { + return GetClientSysKeys() + } + + var keys []sys.KeyPair + for _, kv := range wallet.Keys { + keys = append(keys, sys.KeyPair{ + PrivateKey: kv.PrivateKey, + PublicKey: kv.PublicKey, + }) + } + + return keys +} + // SetWallet should be set before any transaction or client specific APIs func SetWallet(w zcncrypto.Wallet) { client.wallet = &w @@ -253,11 +325,11 @@ func GetWalletByClientKey(clientKey string) *zcncrypto.Wallet { // GetWalletByClientID gets a wallet by client id. func GetWalletByClientID(clientID string) *zcncrypto.Wallet { if client.wallets == nil { - return nil - } + return nil + } if _, exists := client.wallets[clientID]; !exists { - return nil - } + return nil + } for _, wallet := range client.wallets { if wallet.ClientID == clientID { @@ -275,8 +347,8 @@ func AddWallet(wallet zcncrypto.Wallet) { client.wallets = make(map[string]*zcncrypto.Wallet) } if _, exists := client.wg[wallet.ClientID]; !exists { - client.wg[wallet.ClientID] = &sync.WaitGroup{} - } + client.wg[wallet.ClientID] = &sync.WaitGroup{} + } client.wg[clientKey].Add(1) client.walletCount[clientKey]++ client.wallets[clientKey] = &wallet From 370243f75a7f016c2ec3656b7219b9da25483082 Mon Sep 17 00:00:00 2001 From: Kunal Goyal <151kgoyal@gmail.com> Date: Thu, 2 Oct 2025 04:14:27 +0530 Subject: [PATCH 18/47] updated file operations and test files --- zboxcore/sdk/blobber_operations.go | 6 ++++-- zboxcore/sdk/chunked_upload_form_builder.go | 19 ++++++++++++++----- zboxcore/sdk/copyworker_test.go | 6 ++++-- zboxcore/sdk/filestatsworker_test.go | 4 +++- zboxcore/sdk/renameworker.go | 2 +- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index cdcd3b9c2..b24d645a5 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -196,7 +196,8 @@ func UpdateAllocation( func GetUpdateAllocTicket(allocationID, userID, operationType string, roundExpiry int64) (string, error) { payload := fmt.Sprintf("%s:%d:%s:%s", allocationID, roundExpiry, userID, operationType) - signature, err := client.Sign(hex.EncodeToString([]byte(payload))) + pubkey := client.PublicKey() + signature, err := client.SignByMultiWallet(hex.EncodeToString([]byte(payload)), pubkey) if err != nil { return "", err } @@ -366,7 +367,8 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string) (ed25519.PrivateKey return nil, errors.New("owner_public_key_required", "owner public key is required") } hashData := fmt.Sprintf("%s:%s", ownerPublicKey, "owner_signing_public_key") - sig, err := client.Sign(encryption.Hash(hashData), ownerID) + pubkey := client.PublicKey() + sig, err := client.SignByMultiWallet(encryption.Hash(hashData), pubkey, ownerID) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) return nil, err diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index be3e1d813..cc103cd6e 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -24,7 +24,7 @@ type ChunkedUploadFormBuilder interface { fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, clients... string, + thumbnailChunkData []byte, shardSize int64, clients ...string, ) (blobberData, error) } @@ -59,7 +59,7 @@ func (b *chunkedUploadFormBuilder) Build( fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, clients... string, + thumbnailChunkData []byte, shardSize int64, clients ...string, ) (blobberData, error) { metadata := ChunkedUploadFormMetadata{ @@ -105,7 +105,7 @@ func (b *chunkedUploadFormBuilder) Build( if b.privateSigningKey != nil { formData.SignatureVersion = SignatureV2 - } + } for i := 0; i < numBodies; i++ { @@ -187,7 +187,12 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ActualFileHashSignature = hex.EncodeToString(sig) } else { - sig, err := client.Sign(fileMeta.ActualHash, clients...) + var pubkey string + if len(clients) > 0 && clients[0] != "" { + pubkey = client.PublicKey(clients...) + } + + sig, err := client.SignByMultiWallet(fileMeta.ActualHash, pubkey, clients...) if err != nil { return res, err } @@ -206,7 +211,11 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ValidationRootSignature = hex.EncodeToString(sig) } else { - rootSig, err := client.Sign(hash, clients...) + var pubkey string + if len(clients) > 0 && clients[0] != "" { + pubkey = client.PublicKey(clients...) + } + rootSig, err := client.SignByMultiWallet(hash, pubkey, clients...) if err != nil { return res, err } diff --git a/zboxcore/sdk/copyworker_test.go b/zboxcore/sdk/copyworker_test.go index f795ce51b..fdc7a3496 100644 --- a/zboxcore/sdk/copyworker_test.go +++ b/zboxcore/sdk/copyworker_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "github.com/0chain/gosdk/zboxcore/mocks" "io" "mime" "mime/multipart" @@ -14,6 +13,8 @@ import ( "sync" "testing" + "github.com/0chain/gosdk/zboxcore/mocks" + "github.com/0chain/errors" "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/zcncrypto" @@ -495,7 +496,8 @@ func TestCopyRequest_ProcessCopy(t *testing.T) { maskMU: &sync.Mutex{}, connectionID: mockConnectionId, } - sig, err := client.Sign(mockAllocationTxId) + pubkey := client.PublicKey() + sig, err := client.SignByMultiWallet(mockAllocationTxId, pubkey) require.NoError(err) req.sig = sig req.ctx, req.ctxCncl = context.WithCancel(context.TODO()) diff --git a/zboxcore/sdk/filestatsworker_test.go b/zboxcore/sdk/filestatsworker_test.go index d9c7e6ba4..a1a50f97a 100644 --- a/zboxcore/sdk/filestatsworker_test.go +++ b/zboxcore/sdk/filestatsworker_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "github.com/0chain/gosdk/zboxcore/mocks" "io" @@ -126,7 +127,8 @@ func TestListRequest_getFileStatsInfoFromBlobber(t *testing.T) { require.NoError(t, err) require.EqualValues(t, expected, string(actual)) - sign, _ := client.Sign(encryption.Hash(mockAllocationTxId)) + pubkey := client.PublicKey() + sign, _ := client.SignByMultiWallet(encryption.Hash(mockAllocationTxId), pubkey) return req.URL.Path == "Test_Success"+zboxutil.FILE_STATS_ENDPOINT+mockAllocationTxId && req.Method == "POST" && req.Header.Get("X-App-Client-ID") == mockClientId && diff --git a/zboxcore/sdk/renameworker.go b/zboxcore/sdk/renameworker.go index 6881dcd1e..f83dc75ac 100644 --- a/zboxcore/sdk/renameworker.go +++ b/zboxcore/sdk/renameworker.go @@ -449,7 +449,7 @@ func (ro *RenameOperation) Process(allocObj *Allocation, connectionID string) ([ maskMU: ro.maskMU, wg: &sync.WaitGroup{}, consensus: Consensus{RWMutex: &sync.RWMutex{}}, - clientId: ro.clientId + clientId: ro.clientId, } if filepath.Base(ro.remotefilepath) == ro.newName { return nil, ro.renameMask, errors.New("invalid_operation", "Cannot rename to same name") From 2c22143b17f47ebf29be4b81723f6a7920749999 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sun, 26 Oct 2025 17:34:16 +0530 Subject: [PATCH 19/47] download --- core/client/set.go | 48 +++++++++------------------------- core/client/zauth.go | 16 ++++++------ core/sys/sign.go | 2 +- zboxcore/marker/readmarker.go | 9 +++++++ zboxcore/sdk/allocation.go | 10 +++++++ zboxcore/sdk/commitworker.go | 12 ++++----- zboxcore/sdk/deleteworker.go | 6 ++--- zboxcore/sdk/downloadworker.go | 29 ++++++++++++++------ zboxcore/sdk/rollback.go | 24 ++++++++--------- zboxcore/zboxutil/http.go | 11 ++++---- 10 files changed, 88 insertions(+), 79 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 954fe4b7f..312c9ee8b 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -166,7 +166,7 @@ var SignFn = func(hash string) (string, error) { return ss.Sign(hash) } -func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientIds ...string) (string, error) { +func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys ...string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) @@ -174,8 +174,12 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientId // Get the first clientID from variadic arguments, or use default wallet clientID var clientID string - if len(clientIds) > 0 && clientIds[0] != "" { - clientID = clientIds[0] + if len(pubkeys) > 0 && pubkeys[0] != "" { + wallet := GetWalletByPubKey(pubkeys[0]) + if wallet == nil { + return "", fmt.Errorf("wallet not found for pubkey: %s", pubkeys[0]) + } + clientID = wallet.ClientID } else { clientID = client.wallet.ClientID } @@ -193,7 +197,7 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, clientId return "", errors.New("authCommon is not set") } - rsp, err := sys.AuthCommon(string(data), clientID) + rsp, err := sys.AuthCommon(string(data)) if err != nil { return "", err } @@ -315,29 +319,12 @@ func SetWallet(w zcncrypto.Wallet) { client.wallets[w.ClientKey] = &w } -func GetWalletByClientKey(clientKey string) *zcncrypto.Wallet { +// GetWalletByPubKey gets a wallet by client id. +func GetWalletByPubKey(pubkey string) *zcncrypto.Wallet { if client.wallets == nil { return nil } - return client.wallets[clientKey] -} - -// GetWalletByClientID gets a wallet by client id. -func GetWalletByClientID(clientID string) *zcncrypto.Wallet { - if client.wallets == nil { - return nil - } - if _, exists := client.wallets[clientID]; !exists { - return nil - } - - for _, wallet := range client.wallets { - if wallet.ClientID == clientID { - return wallet - } - } - - return nil + return client.wallets[pubkey] } // AddWallet adds a new wallet to the sdk. @@ -346,8 +333,8 @@ func AddWallet(wallet zcncrypto.Wallet) { if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) } - if _, exists := client.wg[wallet.ClientID]; !exists { - client.wg[wallet.ClientID] = &sync.WaitGroup{} + if _, exists := client.wg[clientKey]; !exists { + client.wg[clientKey] = &sync.WaitGroup{} } client.wg[clientKey].Add(1) client.walletCount[clientKey]++ @@ -363,15 +350,6 @@ func RemoveWallet(clientKey string) { } } -func RemoveWalletByClientID(clientID string) { - for clientKey, wallet := range client.wallets { - if wallet.ClientID == clientID { - RemoveWallet(clientKey) - return - } - } -} - // SetWalletMode sets current wallet split key mode. func SetWalletMode(mode bool) { if client.wallet != nil { diff --git a/core/client/zauth.go b/core/client/zauth.go index a38179653..6eab8134d 100644 --- a/core/client/zauth.go +++ b/core/client/zauth.go @@ -535,7 +535,7 @@ func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) { // ZauthSignTxn returns a function that sends a txn signing request to the zauth server func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { - return func(msg string, clientIds ...string) (string, error) { + return func(msg string, pubkeys ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -543,10 +543,10 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { req.Header.Set("Content-Type", "application/json") c := GetClient() pubkey := c.Keys[0].PublicKey - if len(clientIds) > 0 { - c = GetWalletByClientID(clientIds[0]) + if len(pubkeys) > 0 { + c = GetWalletByPubKey(pubkeys[0]) if c == nil { - return "", errors.Errorf("wallet not found for client ID: %s", clientIds[0]) + return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) } pubkey = c.Keys[0].PublicKey } @@ -580,7 +580,7 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { } func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { - return func(msg string, clientIds ...string) (string, error) { + return func(msg string, pubkeys ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -588,10 +588,10 @@ func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { c := GetClient() pubkey := c.Keys[0].PublicKey - if len(clientIds) > 0 { - c = GetWalletByClientID(clientIds[0]) + if len(pubkeys) > 0 { + c = GetWalletByPubKey(pubkeys[0]) if c == nil { - return "", errors.Errorf("wallet not found for client ID: %s", clientIds[0]) + return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) } pubkey = c.Keys[0].PublicKey } diff --git a/core/sys/sign.go b/core/sys/sign.go index 186729726..c53b440b9 100644 --- a/core/sys/sign.go +++ b/core/sys/sign.go @@ -16,4 +16,4 @@ type VerifyFunc func(signature string, msg string) (bool, error) type VerifyWithFunc func(pk, signature string, msg string) (bool, error) -type AuthorizeFunc func(msg string, clientIds... string) (string, error) +type AuthorizeFunc func(msg string, pubkeys... string) (string, error) diff --git a/zboxcore/marker/readmarker.go b/zboxcore/marker/readmarker.go index 53db55ccd..77afac4a4 100644 --- a/zboxcore/marker/readmarker.go +++ b/zboxcore/marker/readmarker.go @@ -20,6 +20,7 @@ type ReadMarker struct { ReadCounter int64 `json:"counter"` Signature string `json:"signature"` SessionRC int64 `json:"session_rc"` + IsSignUnderMultiWallet bool `json:"is_sign_under_multi_wallet"` } func (rm *ReadMarker) GetHash() string { @@ -31,6 +32,14 @@ func (rm *ReadMarker) GetHash() string { func (rm *ReadMarker) Sign() error { var err error + wallet := client.GetWalletByPubKey(rm.ClientPublicKey) + if wallet == nil { + return errors.New("sign_rm", "wallet not found for public key "+rm.ClientPublicKey) + } + if rm.IsSignUnderMultiWallet { + rm.Signature, err = client.SignByMultiWallet(rm.GetHash(), rm.ClientPublicKey) + return err + } rm.Signature, err = client.Sign(rm.GetHash()) return err } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 83c75cab8..c3ffe6abf 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1499,6 +1499,16 @@ func (a *Allocation) addAndGenerateDownloadRequest( for _, opt := range downloadReqOpts { opt(downloadReq) } + if downloadReq.Pubkey != "" { + wallet := client.GetWalletByPubKey(downloadReq.Pubkey) + var err error + var sk []byte + sk, err = GenerateOwnerSigningKey(downloadReq.Pubkey, wallet.ClientID) + if err != nil { + return err + } + downloadReq.allocOwnerSigningPrivateKey = sk + } downloadReq.workdir = filepath.Join(downloadReq.workdir, ".zcn") hash := encryption.Hash(fmt.Sprintf("%s:%d:%d", remotePath, startBlock, endBlock)) a.downloadProgressMap[hash] = downloadReq diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index df958116c..44d0a2324 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -436,7 +436,7 @@ func (commitReq *CommitRequestV2) processCommit() { go func(ind uint64) { blobber := commitReq.allocationObj.Blobbers[ind] // trie, err := getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) - + var ( trie *wmpt.WeightedMerkleTrie err error @@ -609,7 +609,7 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh } else { err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion) } - if err != nil { + if err != nil { l.Logger.Error("Error submitting writemarker ", err) return err } @@ -639,7 +639,7 @@ func getFormWritter(connectionID string, wmData, fileIDMetaData []byte, body *by return formWriter, nil } -func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, clientIds... string) (*wmpt.WeightedMerkleTrie, error) { +func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, clientIds ...string) (*wmpt.WeightedMerkleTrie, error) { if len(paths) == 0 || blobber.LatestWM == nil || blobber.LatestWM.ChainSize == 0 { var node wmpt.Node if blobber.LatestWM != nil && len(blobber.LatestWM.FileMetaRoot) > 0 && blobber.LatestWM.ChainSize > 0 { @@ -729,14 +729,14 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio return nil, errAlreadySuccessful } trie := wmpt.New(nil, nil) - if lR.LatestWM != nil { + if lR.LatestWM != nil { var useClientID string if len(clientIds) > 0 && clientIds[0] != "" { useClientID = clientIds[0] } else { useClientID = client.Id() } - wallet := client.GetWalletByClientID(useClientID) + wallet := client.GetWalletByPubKey(useClientID) if wallet == nil { return nil, errors.New("wallet not found", useClientID) } @@ -762,7 +762,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio return trie, nil } -func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int, clientIds... string) (err error) { +func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int, clientIds ...string) (err error) { var ( resp *http.Response shouldContinue bool diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index c3f3e3eef..73b304c5b 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -586,7 +586,7 @@ func (dop *DeleteOperation) Error(allocObj *Allocation, consensus int, err error } -func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int, clientIds... string) *DeleteOperation { +func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int, clientIds ...string) *DeleteOperation { dop := &DeleteOperation{} dop.remotefilepath = zboxutil.RemoteClean(remotePath) dop.deleteMask = deleteMask @@ -630,7 +630,7 @@ func (req *DeleteRequest) deleteSubDirectories() error { } if req.clientId != "" { clientId := req.clientId - wallet := client.GetWalletByClientID(clientId) + wallet := client.GetWalletByPubKey(clientId) if wallet == nil { return errors.New("client_not_found", clientId) } @@ -675,7 +675,7 @@ func (req *DeleteRequest) deleteSubDirectories() error { } if req.clientId != "" { clientId := req.clientId - wallet := client.GetWalletByClientID(clientId) + wallet := client.GetWalletByPubKey(clientId) if wallet == nil { return errors.New("client_not_found", clientId) } diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index fa8af5008..9c64e6b8a 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -120,6 +120,7 @@ type DownloadRequest struct { allocOwnerSigningPubKey string // in case of auth ticket, this key will be of the shared user rather than the owner of the allocation allocOwnerSigningPrivateKey ed25519.PrivateKey + Pubkey string // in case of multi-wallet settings, this will be the public key of the wallet used for downloading } type downloadPriority struct { @@ -842,15 +843,27 @@ func (req *DownloadRequest) submitReadMarker(blobber *blockchain.StorageNode, re func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageNode, readCount int64) error { lockBlobberReadCtr(req.allocationID, blobber.ID) defer unlockBlobberReadCtr(req.allocationID, blobber.ID) + + clientID := client.Id(req.ClientId) + clientPublicKey := client.PublicKey() + if req.Pubkey != "" { + wallet := client.GetWalletByPubKey(req.Pubkey) + if wallet == nil { + return fmt.Errorf("wallet not found for public key: %s", req.Pubkey) + } + clientID = wallet.ClientID + clientPublicKey = req.Pubkey + } rm := &marker.ReadMarker{ - ClientID: client.Id(req.ClientId), - ClientPublicKey: client.PublicKey(), - BlobberID: blobber.ID, - AllocationID: req.allocationID, - OwnerID: req.allocOwnerID, - Timestamp: common.Now(), - ReadCounter: getBlobberReadCtr(req.allocationID, blobber.ID) + readCount, - SessionRC: readCount, + ClientID: clientID, + ClientPublicKey: clientPublicKey, + BlobberID: blobber.ID, + AllocationID: req.allocationID, + OwnerID: req.allocOwnerID, + Timestamp: common.Now(), + ReadCounter: getBlobberReadCtr(req.allocationID, blobber.ID) + readCount, + SessionRC: readCount, + IsSignUnderMultiWallet: req.Pubkey != "", } err := rm.Sign() if err != nil { diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 2044c033b..1369c6185 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -66,12 +66,12 @@ func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, clientId ...strin var lpm LatestPrevWriteMarker var useClientID string - if len(clientId) > 0 && clientId[0] != "" { - useClientID = clientId[0] - } else { - useClientID = client.Id() - } - wallet := client.GetWalletByClientID(useClientID) + if len(clientId) > 0 && clientId[0] != "" { + useClientID = clientId[0] + } else { + useClientID = client.Id() + } + wallet := client.GetWalletByPubKey(useClientID) if wallet == nil { return nil, errors.New("wallet not found : " + useClientID) } @@ -279,14 +279,14 @@ func (rb *RollbackBlobber) processRollback(ctx context.Context, tx string) error // CheckAllocStatus checks the status of the allocation // and returns the status of the allocation and its blobbers. -func (a *Allocation) CheckAllocStatus(clientId... string) (AllocStatus, []BlobberStatus, error) { +func (a *Allocation) CheckAllocStatus(clientId ...string) (AllocStatus, []BlobberStatus, error) { var useClientID string - if len(clientId) > 0 && clientId[0] != "" { - useClientID = clientId[0] - } else { - useClientID = a.Owner - } + if len(clientId) > 0 && clientId[0] != "" { + useClientID = clientId[0] + } else { + useClientID = a.Owner + } wg := &sync.WaitGroup{} markerChan := make(chan *RollbackBlobber, len(a.Blobbers)) diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index 05e01891b..d4e1ffc44 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -198,9 +198,9 @@ func NewHTTPRequest(method string, url string, data []byte) (*http.Request, cont return req, ctx, cncl, err } -func setClientInfo(req *http.Request, clientIds... string) { +func setClientInfo(req *http.Request, clientIds ...string) { if len(clientIds) > 0 && clientIds[0] != "" { - wallet := client.GetWalletByClientID(clientIds[0]) + wallet := client.GetWalletByPubKey(clientIds[0]) if wallet == nil { panic("wallet not found : " + clientIds[0]) } @@ -219,7 +219,7 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, c } else { clientID = client.Id() } - wallet := client.GetWalletByClientID(clientID) + wallet := client.GetWalletByPubKey(clientID) if wallet == nil { return errors.New("wallet not found", clientID) } @@ -674,13 +674,12 @@ func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string } else { clientID = client.Id() } - wallet := client.GetWalletByClientID(clientID) + wallet := client.GetWalletByPubKey(clientID) if wallet == nil { return errors.New("wallet not found", clientID) } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) - hashData := allocation + baseURL // clientID := client.Id() @@ -885,7 +884,7 @@ func NewRedeemRequest(baseUrl, allocationID, allocationTx string, clients ...str return req, nil } -func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, clients... string) (*http.Request, error) { +func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, clients ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, UPLOAD_ENDPOINT, allocationTx) if err != nil { return nil, err From 9e0ef1e4a902384b90d21ecf9a670af827f2fc1b Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sun, 26 Oct 2025 18:50:46 +0530 Subject: [PATCH 20/47] concurrency support --- core/client/set.go | 330 +++++++++++++++------------------------------ core/sys/sign.go | 2 +- 2 files changed, 111 insertions(+), 221 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 312c9ee8b..6f1f27ab5 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -1,15 +1,12 @@ package client import ( - "context" "encoding/json" "errors" "fmt" "strings" "sync" - "github.com/0chain/gosdk/core/conf" - "github.com/0chain/gosdk/constants" "github.com/0chain/gosdk/core/sys" "github.com/0chain/gosdk/core/zcncrypto" @@ -26,7 +23,7 @@ var ( type SignFunc func(hash string, clients ...string) (string, error) -type SignByMultiWalletFunc func(hash string, pubkey string, clients ...string) (string, error) +type SignByMultiWalletFunc func(hash string, pubkey string) (string, error) // maintains client's information type Client struct { @@ -39,7 +36,8 @@ type Client struct { txnFee uint64 sign SignFunc wg map[string]*sync.WaitGroup - walletCount map[string]int // maintains count of wallets in the WaitGroup by Client ID + walletCount map[string]int // maintains count of wallets in the WaitGroup by pubkey + mu sync.RWMutex // allow concurrent readers } type InitSdkOptions struct { @@ -63,86 +61,55 @@ func init() { sys.Sign = signHash sys.SignWithAuth = signHashWithAuth + // prime the sign channel sigC <- struct{}{} - // initialize SignFunc as default implementation + // default Sign implementation (uses client.wallet or wallets map) Sign = func(hash string, clients ...string) (string, error) { + client.mu.RLock() + defer client.mu.RUnlock() wallet := client.wallet - if len(clients) > 0 && clients[0] != "" { - if client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - wallet = w - break - } + if client.wallets != nil { + if w, ok := client.wallets[clients[0]]; ok && w != nil { + wallet = w } + } else { + return "", errors.New("no wallets available for signing by client ID: " + clients[0]) } } if !wallet.IsSplit { return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(clients...)) } - fmt.Printf("Sign: wallet details: %+v\n", *wallet) - // get sign lock + + // split-key signing via auth <-sigC - fmt.Println("Sign: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeys(clients...)) - sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(clients...), wallet.ClientID) + sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(clients...), wallet.Keys[0].PublicKey) sigC <- struct{}{} return sig, err } - SignByMultiWallet = func(hash string, pubkey string, clients ...string) (string, error) { + SignByMultiWallet = func(hash string, pubkey string) (string, error) { + client.mu.RLock() + defer client.mu.RUnlock() var wallet *zcncrypto.Wallet - - // First try to find wallet by public key - if pubkey != "" { - if client.wallets[pubkey] != nil { - wallet = client.wallets[pubkey] - } else { - // Fallback to searching by client ID if pubkey not found - if len(clients) > 0 && clients[0] != "" { - if client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - wallet = w - break - } - } - } - } - } - } else if len(clients) > 0 && clients[0] != "" { - // If no pubkey provided, fallback to client ID lookup - if client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - wallet = w - break - } - } + + if client.wallets != nil { + if w, ok := client.wallets[pubkey]; ok && w != nil { + wallet = w } } - - // If no wallet found, use default wallet if wallet == nil { - wallet = client.wallet + return "", errors.New("no wallet available for signing with pubkey: " + pubkey) } if !wallet.IsSplit { return sys.Sign(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet)) } - fmt.Printf("SignByMultiWallet: wallet details: %+v\n", *wallet) - // get sign lock + <-sigC - fmt.Println("SignByMultiWallet: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeysByWallet(wallet)) - sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet), wallet.ClientID) + sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet), pubkey) sigC <- struct{}{} return sig, err } @@ -155,24 +122,17 @@ func init() { client.walletCount = make(map[string]int) } -var SignFn = func(hash string) (string, error) { - ss := zcncrypto.NewSignatureScheme(client.signatureScheme) - - err := ss.SetPrivateKey(client.wallet.Keys[0].PrivateKey) - if err != nil { - return "", err - } - - return ss.Sign(hash) +func GetClient() *zcncrypto.Wallet { + return client.wallet } +// Sign helpers that use sys package func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys ...string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } - // Get the first clientID from variadic arguments, or use default wallet clientID var clientID string if len(pubkeys) > 0 && pubkeys[0] != "" { wallet := GetWalletByPubKey(pubkeys[0]) @@ -197,7 +157,7 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys return "", errors.New("authCommon is not set") } - rsp, err := sys.AuthCommon(string(data)) + rsp, err := sys.AuthCommon(string(data), pubkeys...) if err != nil { return "", err } @@ -206,8 +166,7 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys Sig string `json:"sig"` } - err = json.Unmarshal([]byte(rsp), &sigpk) - if err != nil { + if err = json.Unmarshal([]byte(rsp), &sigpk); err != nil { return "", err } @@ -233,7 +192,6 @@ func signHash(hash string, signatureScheme string, keys []sys.KeyPair) (string, return "", err } } - return retSignature, nil } @@ -264,25 +222,17 @@ func verifyEd25519With(pubKey, signature, hash string) (bool, error) { return sch.Verify(signature, hash) } +// GetClientSysKeys reads wallets -> use RLock func GetClientSysKeys(clients ...string) []sys.KeyPair { - var wallet *zcncrypto.Wallet - if len(clients) > 0 && clients[0] != "" { - if client.wallets[clients[0]] != nil { - wallet = client.wallets[clients[0]] - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - wallet = w - break - } - } + client.mu.RLock() + defer client.mu.RUnlock() + wallet := client.wallet + if len(clients) > 0 && clients[0] != "" && client.wallets != nil { + if w, ok := client.wallets[clients[0]]; ok && w != nil { + wallet = w } } - if wallet == nil { - wallet = client.wallet - } - var keys []sys.KeyPair for _, kv := range wallet.Keys { keys = append(keys, sys.KeyPair{ @@ -298,7 +248,6 @@ func GetClientSysKeysByWallet(wallet *zcncrypto.Wallet) []sys.KeyPair { if wallet == nil { return GetClientSysKeys() } - var keys []sys.KeyPair for _, kv := range wallet.Keys { keys = append(keys, sys.KeyPair{ @@ -306,12 +255,14 @@ func GetClientSysKeysByWallet(wallet *zcncrypto.Wallet) []sys.KeyPair { PublicKey: kv.PublicKey, }) } - return keys } // SetWallet should be set before any transaction or client specific APIs func SetWallet(w zcncrypto.Wallet) { + client.mu.Lock() + defer client.mu.Unlock() + client.wallet = &w if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) @@ -319,8 +270,10 @@ func SetWallet(w zcncrypto.Wallet) { client.wallets[w.ClientKey] = &w } -// GetWalletByPubKey gets a wallet by client id. +// GetWalletByPubKey gets a wallet by client pubkey. func GetWalletByPubKey(pubkey string) *zcncrypto.Wallet { + client.mu.RLock() + defer client.mu.RUnlock() if client.wallets == nil { return nil } @@ -329,24 +282,64 @@ func GetWalletByPubKey(pubkey string) *zcncrypto.Wallet { // AddWallet adds a new wallet to the sdk. func AddWallet(wallet zcncrypto.Wallet) { - clientKey := wallet.ClientKey + pubkey := wallet.Keys[0].PublicKey + + client.mu.Lock() + defer client.mu.Unlock() + if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) } - if _, exists := client.wg[clientKey]; !exists { - client.wg[clientKey] = &sync.WaitGroup{} + if client.wg == nil { + client.wg = make(map[string]*sync.WaitGroup) + } + if client.walletCount == nil { + client.walletCount = make(map[string]int) + } + + // if wallet already present, just increment counter + if _, exists := client.wallets[pubkey]; exists { + client.walletCount[pubkey]++ + // ensure wg exists + if client.wg[pubkey] == nil { + client.wg[pubkey] = &sync.WaitGroup{} + } + client.wg[pubkey].Add(1) + return + } + + // add new wallet + client.wallets[pubkey] = &wallet + if client.wg[pubkey] == nil { + client.wg[pubkey] = &sync.WaitGroup{} } - client.wg[clientKey].Add(1) - client.walletCount[clientKey]++ - client.wallets[clientKey] = &wallet + client.wg[pubkey].Add(1) + client.walletCount[pubkey]++ } // RemoveWallet removes a wallet from the sdk. -func RemoveWallet(clientKey string) { - client.wg[clientKey].Done() - client.walletCount[clientKey]-- - if client.walletCount[clientKey] == 0 { - delete(client.wallets, clientKey) +func RemoveWallet(pubkey string) { + client.mu.Lock() + defer client.mu.Unlock() + + if pubkey == "" || client.walletCount == nil { + return + } + + // only decrement if count > 0 + if client.walletCount[pubkey] > 0 { + client.walletCount[pubkey]-- + // call Done on wg only if it exists + if wg, ok := client.wg[pubkey]; ok && wg != nil { + wg.Done() + } + } + + // if count reaches zero, clean up maps + if client.walletCount[pubkey] == 0 { + delete(client.wallets, pubkey) + delete(client.wg, pubkey) + delete(client.walletCount, pubkey) } } @@ -420,17 +413,18 @@ func IsWalletSet() bool { return client.wallet.ClientID != "" } +// PublicKey lookup uses read lock func PublicKey(clients ...string) string { if len(clients) > 0 && clients[0] != "" { - if client.wallets[clients[0]] != nil { - return client.wallets[clients[0]].ClientKey - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - return w.ClientKey - } + client.mu.RLock() + if client.wallets != nil { + if w, ok := client.wallets[clients[0]]; ok && w != nil { + k := w.Keys[0].PublicKey + client.mu.RUnlock() + return k } } + client.mu.RUnlock() } return client.wallet.ClientKey @@ -449,129 +443,25 @@ func PrivateKey() string { func Id(clients ...string) string { if len(clients) > 0 && clients[0] != "" { - if client.wallets[clients[0]] != nil { - return client.wallets[clients[0]].ClientID - } else { - for _, w := range client.wallets { - if w.ClientID == clients[0] { - return w.ClientID - } + client.mu.RLock() + if client.wallets != nil { + if w, ok := client.wallets[clients[0]]; ok && w != nil { + id := w.ClientID + client.mu.RUnlock() + return id } } + client.mu.RUnlock() } return client.wallet.ClientID } -func GetWallet() *zcncrypto.Wallet { - return client.wallet -} - -func GetClient() *zcncrypto.Wallet { - return client.wallet -} - -// InitSDK Initialize the storage SDK -// -// - walletJSON: Client's wallet JSON -// - blockWorker: Block worker URL (block worker refers to 0DNS) -// - chainID: ID of the blokcchain network -// - signatureScheme: Signature scheme that will be used for signing transactions -// - preferredBlobbers: List of preferred blobbers to use when creating an allocation. This is usually configured by the client in the configuration files -// - nonce: Initial nonce value for the transactions -// - fee: Preferred value for the transaction fee, just the first value is taken -func InitSDK(walletJSON string, - blockWorker, chainID, signatureScheme string, - nonce int64, addWallet bool, - options ...int) error { - - if addWallet { - wallet := zcncrypto.Wallet{} - err := json.Unmarshal([]byte(walletJSON), &wallet) - if err != nil { - return err - } - - SetWallet(wallet) - SetSignatureScheme(signatureScheme) - SetNonce(nonce) - if len(options) > 0 { - SetTxnFee(uint64(options[0])) - } - } - - var minConfirmation, minSubmit, confirmationChainLength, sharderConsensous int - if len(options) > 1 { - minConfirmation = options[1] - } - if len(options) > 2 { - minSubmit = options[2] - } - if len(options) > 3 { - confirmationChainLength = options[3] - } - if len(options) > 4 { - sharderConsensous = options[4] - } - - err := Init(context.Background(), conf.Config{ - BlockWorker: blockWorker, - SignatureScheme: signatureScheme, - ChainID: chainID, - MinConfirmation: minConfirmation, - MinSubmit: minSubmit, - ConfirmationChainLength: confirmationChainLength, - SharderConsensous: sharderConsensous, - }) - if err != nil { - return err - } - SetSdkInitialized(true) - return nil -} - -func InitSDKWithWebApp(params InitSdkOptions) error { - if params.MinConfirmation != nil && params.MinSubmit != nil && params.ConfirmationChainLength != nil && params.SharderConsensous != nil { - err := InitSDK(params.WalletJSON, params.BlockWorker, params.ChainID, params.SignatureScheme, params.Nonce, params.AddWallet, *params.MinConfirmation, *params.MinSubmit, *params.ConfirmationChainLength, *params.SharderConsensous) - if err != nil { - return err - } - } else { - err := InitSDK(params.WalletJSON, params.BlockWorker, params.ChainID, params.SignatureScheme, params.Nonce, params.AddWallet) - if err != nil { - return err - } - } - conf.SetZboxAppConfigs(params.ZboxHost, params.ZboxAppType) - SetIsAppFlow(true) - return nil -} - -func IsSDKInitialized() bool { - return sdkInitialized -} - -func SetSdkInitialized(val bool) { - sdkInitialized = val -} - -func PopulateClient(walletJSON, signatureScheme string) (zcncrypto.Wallet, error) { - wallet := zcncrypto.Wallet{} - err := json.Unmarshal([]byte(walletJSON), &wallet) - if err != nil { - return wallet, err - } - - SetWallet(wallet) - SetSignatureScheme(signatureScheme) - return wallet, nil -} - +// VerifySignature ... func VerifySignature(signature string, msg string) (bool, error) { ss := zcncrypto.NewSignatureScheme(client.signatureScheme) if err := ss.SetPublicKey(PublicKey()); err != nil { return false, err } - return ss.Verify(signature, msg) } diff --git a/core/sys/sign.go b/core/sys/sign.go index c53b440b9..d66baa171 100644 --- a/core/sys/sign.go +++ b/core/sys/sign.go @@ -10,7 +10,7 @@ type KeyPair struct { type SignFunc func(hash string, signatureScheme string, keys []KeyPair) (string, error) // SignFunc sign method for request verification -type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, clientIds ...string) (string, error) +type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, pubkeys ...string) (string, error) type VerifyFunc func(signature string, msg string) (bool, error) From 0bbf15d4d1e686ddfc8794d33e1ab471e683f3b3 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 28 Oct 2025 16:48:02 +0530 Subject: [PATCH 21/47] use key --- core/client/set.go | 122 ++++++++------------ core/client/zauth.go | 4 +- zboxcore/marker/readmarker.go | 24 ++-- zboxcore/marker/writemarker.go | 1 + zboxcore/sdk/allocation.go | 46 ++++---- zboxcore/sdk/blobber_operations.go | 2 +- zboxcore/sdk/chunked_upload_blobber.go | 4 +- zboxcore/sdk/chunked_upload_form_builder.go | 4 +- zboxcore/sdk/chunked_upload_model.go | 3 +- zboxcore/sdk/chunked_upload_option.go | 2 +- zboxcore/sdk/chunked_upload_process.go | 4 +- zboxcore/sdk/commitworker.go | 29 +++-- zboxcore/sdk/deleteworker.go | 8 +- zboxcore/sdk/dirworker.go | 15 ++- zboxcore/sdk/downloadworker.go | 2 +- zboxcore/sdk/multi_operation_worker.go | 13 +-- zboxcore/sdk/rollback.go | 28 ++--- zboxcore/sdk/sdk.go | 8 +- zboxcore/sdk/upload_worker.go | 4 +- zboxcore/zboxutil/http.go | 50 ++++---- 20 files changed, 176 insertions(+), 197 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 6f1f27ab5..1ce201b2a 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -16,14 +16,14 @@ var ( client Client sdkInitialized bool - Sign SignFunc - SignByMultiWallet SignByMultiWalletFunc - sigC = make(chan struct{}, 1) + Sign SignFunc + // SignByMultiWallet SignByMultiWalletFunc + sigC = make(chan struct{}, 1) ) -type SignFunc func(hash string, clients ...string) (string, error) +type SignFunc func(hash string, keys ...string) (string, error) -type SignByMultiWalletFunc func(hash string, pubkey string) (string, error) +// type SignByMultiWalletFunc func(hash string, pubkey string) (string, error) // maintains client's information type Client struct { @@ -65,51 +65,27 @@ func init() { sigC <- struct{}{} // default Sign implementation (uses client.wallet or wallets map) - Sign = func(hash string, clients ...string) (string, error) { + Sign = func(hash string, keys ...string) (string, error) { client.mu.RLock() defer client.mu.RUnlock() wallet := client.wallet - if len(clients) > 0 && clients[0] != "" { + if len(keys) > 0 && keys[0] != "" { if client.wallets != nil { - if w, ok := client.wallets[clients[0]]; ok && w != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { wallet = w } } else { - return "", errors.New("no wallets available for signing by client ID: " + clients[0]) + return "", errors.New("no wallets available for signing by key: " + keys[0]) } } if !wallet.IsSplit { - return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(clients...)) + return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(keys...)) } // split-key signing via auth <-sigC - sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(clients...), wallet.Keys[0].PublicKey) - sigC <- struct{}{} - return sig, err - } - - SignByMultiWallet = func(hash string, pubkey string) (string, error) { - client.mu.RLock() - defer client.mu.RUnlock() - var wallet *zcncrypto.Wallet - - if client.wallets != nil { - if w, ok := client.wallets[pubkey]; ok && w != nil { - wallet = w - } - } - if wallet == nil { - return "", errors.New("no wallet available for signing with pubkey: " + pubkey) - } - - if !wallet.IsSplit { - return sys.Sign(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet)) - } - - <-sigC - sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeysByWallet(wallet), pubkey) + sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(keys...), wallet.Keys[0].PublicKey) sigC <- struct{}{} return sig, err } @@ -126,18 +102,37 @@ func GetClient() *zcncrypto.Wallet { return client.wallet } +var SignFn = func(hash string) (string, error) { + ss := zcncrypto.NewSignatureScheme(client.signatureScheme) + + err := ss.SetPrivateKey(client.wallet.Keys[0].PrivateKey) + if err != nil { + return "", err + } + + return ss.Sign(hash) +} + +func IsSDKInitialized() bool { + return sdkInitialized +} + +func SetSdkInitialized(val bool) { + sdkInitialized = val +} + // Sign helpers that use sys package -func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys ...string) (string, error) { +func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, key ...string) (string, error) { sig, err := sys.Sign(hash, signatureScheme, keys) if err != nil { return "", fmt.Errorf("failed to sign with split key: %v", err) } var clientID string - if len(pubkeys) > 0 && pubkeys[0] != "" { - wallet := GetWalletByPubKey(pubkeys[0]) + if len(key) > 0 && key[0] != "" { + wallet := GetWalletByKey(key[0]) if wallet == nil { - return "", fmt.Errorf("wallet not found for pubkey: %s", pubkeys[0]) + return "", fmt.Errorf("wallet not found for pubkey: %s", key[0]) } clientID = wallet.ClientID } else { @@ -157,7 +152,7 @@ func signHashWithAuth(hash, signatureScheme string, keys []sys.KeyPair, pubkeys return "", errors.New("authCommon is not set") } - rsp, err := sys.AuthCommon(string(data), pubkeys...) + rsp, err := sys.AuthCommon(string(data), key...) if err != nil { return "", err } @@ -223,39 +218,24 @@ func verifyEd25519With(pubKey, signature, hash string) (bool, error) { } // GetClientSysKeys reads wallets -> use RLock -func GetClientSysKeys(clients ...string) []sys.KeyPair { +func GetClientSysKeys(keys ...string) []sys.KeyPair { client.mu.RLock() defer client.mu.RUnlock() wallet := client.wallet - if len(clients) > 0 && clients[0] != "" && client.wallets != nil { - if w, ok := client.wallets[clients[0]]; ok && w != nil { + if len(keys) > 0 && keys[0] != "" && client.wallets != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { wallet = w } } - var keys []sys.KeyPair - for _, kv := range wallet.Keys { - keys = append(keys, sys.KeyPair{ - PrivateKey: kv.PrivateKey, - PublicKey: kv.PublicKey, - }) - } - - return keys -} - -func GetClientSysKeysByWallet(wallet *zcncrypto.Wallet) []sys.KeyPair { - if wallet == nil { - return GetClientSysKeys() - } - var keys []sys.KeyPair + var sysKeys []sys.KeyPair for _, kv := range wallet.Keys { - keys = append(keys, sys.KeyPair{ + sysKeys = append(sysKeys, sys.KeyPair{ PrivateKey: kv.PrivateKey, PublicKey: kv.PublicKey, }) } - return keys + return sysKeys } // SetWallet should be set before any transaction or client specific APIs @@ -267,17 +247,17 @@ func SetWallet(w zcncrypto.Wallet) { if client.wallets == nil { client.wallets = make(map[string]*zcncrypto.Wallet) } - client.wallets[w.ClientKey] = &w + client.wallets[w.ClientID] = &w } -// GetWalletByPubKey gets a wallet by client pubkey. -func GetWalletByPubKey(pubkey string) *zcncrypto.Wallet { +// GetWalletByKey gets a wallet by client pubkey. +func GetWalletByKey(key string) *zcncrypto.Wallet { client.mu.RLock() defer client.mu.RUnlock() if client.wallets == nil { return nil } - return client.wallets[pubkey] + return client.wallets[key] } // AddWallet adds a new wallet to the sdk. @@ -414,11 +394,11 @@ func IsWalletSet() bool { } // PublicKey lookup uses read lock -func PublicKey(clients ...string) string { - if len(clients) > 0 && clients[0] != "" { +func PublicKey(keys ...string) string { + if len(keys) > 0 && keys[0] != "" { client.mu.RLock() if client.wallets != nil { - if w, ok := client.wallets[clients[0]]; ok && w != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { k := w.Keys[0].PublicKey client.mu.RUnlock() return k @@ -441,11 +421,11 @@ func PrivateKey() string { return "" } -func Id(clients ...string) string { - if len(clients) > 0 && clients[0] != "" { +func Id(keys ...string) string { + if len(keys) > 0 && keys[0] != "" { client.mu.RLock() if client.wallets != nil { - if w, ok := client.wallets[clients[0]]; ok && w != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { id := w.ClientID client.mu.RUnlock() return id diff --git a/core/client/zauth.go b/core/client/zauth.go index 6eab8134d..25a4b5a4e 100644 --- a/core/client/zauth.go +++ b/core/client/zauth.go @@ -544,7 +544,7 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { c := GetClient() pubkey := c.Keys[0].PublicKey if len(pubkeys) > 0 { - c = GetWalletByPubKey(pubkeys[0]) + c = GetWalletByKey(pubkeys[0]) if c == nil { return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) } @@ -589,7 +589,7 @@ func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { c := GetClient() pubkey := c.Keys[0].PublicKey if len(pubkeys) > 0 { - c = GetWalletByPubKey(pubkeys[0]) + c = GetWalletByKey(pubkeys[0]) if c == nil { return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) } diff --git a/zboxcore/marker/readmarker.go b/zboxcore/marker/readmarker.go index 77afac4a4..44204f59b 100644 --- a/zboxcore/marker/readmarker.go +++ b/zboxcore/marker/readmarker.go @@ -4,23 +4,23 @@ import ( "fmt" "github.com/0chain/errors" + "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/core/encryption" "github.com/0chain/gosdk/core/sys" - "github.com/0chain/gosdk/core/client" ) type ReadMarker struct { - ClientID string `json:"client_id"` - ClientPublicKey string `json:"client_public_key"` - BlobberID string `json:"blobber_id"` - AllocationID string `json:"allocation_id"` - OwnerID string `json:"owner_id"` - Timestamp common.Timestamp `json:"timestamp"` - ReadCounter int64 `json:"counter"` - Signature string `json:"signature"` - SessionRC int64 `json:"session_rc"` - IsSignUnderMultiWallet bool `json:"is_sign_under_multi_wallet"` + ClientID string `json:"client_id"` + ClientPublicKey string `json:"client_public_key"` + BlobberID string `json:"blobber_id"` + AllocationID string `json:"allocation_id"` + OwnerID string `json:"owner_id"` + Timestamp common.Timestamp `json:"timestamp"` + ReadCounter int64 `json:"counter"` + Signature string `json:"signature"` + SessionRC int64 `json:"session_rc"` + IsSignUnderMultiWallet bool `json:"is_sign_under_multi_wallet"` } func (rm *ReadMarker) GetHash() string { @@ -32,7 +32,7 @@ func (rm *ReadMarker) GetHash() string { func (rm *ReadMarker) Sign() error { var err error - wallet := client.GetWalletByPubKey(rm.ClientPublicKey) + wallet := client.GetWalletByKey(rm.ClientPublicKey) if wallet == nil { return errors.New("sign_rm", "wallet not found for public key "+rm.ClientPublicKey) } diff --git a/zboxcore/marker/writemarker.go b/zboxcore/marker/writemarker.go index 55a4ad3b4..950af095c 100644 --- a/zboxcore/marker/writemarker.go +++ b/zboxcore/marker/writemarker.go @@ -21,6 +21,7 @@ type WriteMarker struct { BlobberID string `json:"blobber_id"` Timestamp int64 `json:"timestamp"` ClientID string `json:"client_id"` + Pubkey string `json:"pub_key"` Signature string `json:"signature"` } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index c3ffe6abf..91f30fa78 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1139,31 +1139,31 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul switch op.OperationType { case constants.FileOperationRename: - var clientId string - if mo.Wallet != nil { - clientId = mo.Wallet.ClientID + var pubkey string + if mo.Pubkey != "" { + pubkey = mo.Pubkey } else { - clientId = mo.allocationObj.Owner + pubkey = mo.allocationObj.Owner } - operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, clientId) + operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, pubkey) case constants.FileOperationCopy: - var clientId string - if mo.Wallet != nil { - clientId = mo.Wallet.ClientID + var pubkey string + if mo.Pubkey != "" { + pubkey = mo.Pubkey } else { - clientId = mo.allocationObj.Owner + pubkey = mo.allocationObj.Owner } - operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly, clientId) + operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly, pubkey) case constants.FileOperationMove: - var clientId string - if mo.Wallet != nil { - clientId = mo.Wallet.ClientID + var pubkey string + if mo.Pubkey != "" { + pubkey = mo.Pubkey } else { - clientId = mo.allocationObj.Owner + pubkey = mo.allocationObj.Owner } - operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, clientId) + operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, pubkey) case constants.FileOperationInsert: cancelLock.Lock() @@ -1172,17 +1172,17 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationDelete: - var clientId string - if mo.Wallet != nil { - clientId = mo.Wallet.ClientID + var pubkey string + if mo.Pubkey != "" { + pubkey = mo.Pubkey } else { - clientId = mo.allocationObj.Owner + pubkey = mo.allocationObj.Owner } if op.Mask != nil { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, clientId) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, pubkey) } else { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, clientId) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, pubkey) } case constants.FileOperationUpdate: @@ -1192,7 +1192,7 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, true, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationCreateDir: - operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.Wallet) + operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.Pubkey) default: return errors.New("invalid_operation", "Operation is not valid") @@ -1500,7 +1500,7 @@ func (a *Allocation) addAndGenerateDownloadRequest( opt(downloadReq) } if downloadReq.Pubkey != "" { - wallet := client.GetWalletByPubKey(downloadReq.Pubkey) + wallet := client.GetWalletByKey(downloadReq.Pubkey) var err error var sk []byte sk, err = GenerateOwnerSigningKey(downloadReq.Pubkey, wallet.ClientID) diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index b24d645a5..4d490f5bd 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -368,7 +368,7 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string) (ed25519.PrivateKey } hashData := fmt.Sprintf("%s:%s", ownerPublicKey, "owner_signing_public_key") pubkey := client.PublicKey() - sig, err := client.SignByMultiWallet(encryption.Hash(hashData), pubkey, ownerID) + sig, err := client.SignByMultiWallet(encryption.Hash(hashData), pubkey) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) return nil, err diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index 005898a41..80c5c7e1e 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -72,8 +72,8 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( eg, _ := errgroup.WithContext(ctx) clientID := su.allocationObj.Owner - if su.wallet != nil { - clientID = su.wallet.ClientID + if su.pubkey != nil { + clientID = su.pubkey.ClientID } for dataInd := 0; dataInd < len(dataBuffers); dataInd++ { ind := dataInd diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index cc103cd6e..92ff3f53a 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -187,12 +187,12 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ActualFileHashSignature = hex.EncodeToString(sig) } else { - var pubkey string + pubkey := client.Wallet().ClientKey if len(clients) > 0 && clients[0] != "" { pubkey = client.PublicKey(clients...) } - sig, err := client.SignByMultiWallet(fileMeta.ActualHash, pubkey, clients...) + sig, err := client.SignByMultiWallet(fileMeta.ActualHash, pubkey) if err != nil { return res, err } diff --git a/zboxcore/sdk/chunked_upload_model.go b/zboxcore/sdk/chunked_upload_model.go index db26f0407..68a66d4bd 100644 --- a/zboxcore/sdk/chunked_upload_model.go +++ b/zboxcore/sdk/chunked_upload_model.go @@ -11,7 +11,6 @@ import ( "time" "github.com/0chain/gosdk/core/common" - "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/encryption" "github.com/0chain/gosdk/zboxcore/fileref" @@ -98,7 +97,7 @@ type ChunkedUpload struct { processMap map[int]zboxutil.Uint128 //nolint:unused //used in wasm check chunked_upload_process_js.go processMapLock sync.Mutex //nolint:unused - wallet *zcncrypto.Wallet + pubkey string } // FileMeta metadata of stream input/local diff --git a/zboxcore/sdk/chunked_upload_option.go b/zboxcore/sdk/chunked_upload_option.go index 89b7d5835..e6dd9c5df 100644 --- a/zboxcore/sdk/chunked_upload_option.go +++ b/zboxcore/sdk/chunked_upload_option.go @@ -40,7 +40,7 @@ func WithThumbnail(buf []byte) ChunkedUploadOption { func WithWallet(w *zcncrypto.Wallet) ChunkedUploadOption { return func(su *ChunkedUpload) { - su.wallet = w + su.pubkey = w } } diff --git a/zboxcore/sdk/chunked_upload_process.go b/zboxcore/sdk/chunked_upload_process.go index 5f2680e8b..cf38353ee 100644 --- a/zboxcore/sdk/chunked_upload_process.go +++ b/zboxcore/sdk/chunked_upload_process.go @@ -107,11 +107,11 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, defer wg.Done() var uploadData blobberData var err error - if su.wallet != nil { + if su.pubkey != nil { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, - fileShards[pos], thumbnailChunkData, su.shardSize, su.wallet.ClientID) + fileShards[pos], thumbnailChunkData, su.shardSize, su.pubkey.ClientID) } else { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index 44d0a2324..f6815261c 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -20,7 +20,6 @@ import ( thrown "github.com/0chain/errors" "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/encryption" - "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" @@ -91,7 +90,7 @@ type CommitRequestV2 struct { commitMask zboxutil.Uint128 changeIndex uint64 isRepair bool - wallet *zcncrypto.Wallet + pubkey string } var ( @@ -441,8 +440,8 @@ func (commitReq *CommitRequestV2) processCommit() { trie *wmpt.WeightedMerkleTrie err error ) - if commitReq.wallet != nil { - trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu, commitReq.wallet.ClientID) + if commitReq.pubkey != "" { + trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu, commitReq.pubkey) } else { trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) } @@ -590,8 +589,8 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh wm.AllocationID = req.allocationObj.ID wm.FileMetaRoot = fileMetaRoot wm.ClientID = client.Id() - if req.wallet != nil { - wm.ClientID = req.wallet.ClientID + if req.pubkey != "" { + wm.Pubkey = req.pubkey } err = wm.Sign() if err != nil { @@ -604,8 +603,8 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh return err } - if req.wallet != nil { - err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion, req.wallet.ClientID) + if req.pubkey != "" { + err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion, req.pubkey) } else { err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion) } @@ -639,7 +638,7 @@ func getFormWritter(connectionID string, wmData, fileIDMetaData []byte, body *by return formWriter, nil } -func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, clientIds ...string) (*wmpt.WeightedMerkleTrie, error) { +func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocationTx, sig string, paths []string, success *bool, mu *sync.Mutex, keys ...string) (*wmpt.WeightedMerkleTrie, error) { if len(paths) == 0 || blobber.LatestWM == nil || blobber.LatestWM.ChainSize == 0 { var node wmpt.Node if blobber.LatestWM != nil && len(blobber.LatestWM.FileMetaRoot) > 0 && blobber.LatestWM.ChainSize > 0 { @@ -658,7 +657,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio for retries := 0; retries < 3; retries++ { err, shouldContinue = func() (err error, shouldContinue bool) { var req *http.Request - req, err = zboxutil.NewReferencePathRequestV2(blobber.Baseurl, allocationID, allocationTx, sig, paths, false, clientIds...) + req, err = zboxutil.NewReferencePathRequestV2(blobber.Baseurl, allocationID, allocationTx, sig, paths, false, keys...) if err != nil { l.Logger.Error("Creating ref path req", err) return @@ -731,12 +730,12 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio trie := wmpt.New(nil, nil) if lR.LatestWM != nil { var useClientID string - if len(clientIds) > 0 && clientIds[0] != "" { - useClientID = clientIds[0] + if len(keys) > 0 && keys[0] != "" { + useClientID = keys[0] } else { useClientID = client.Id() } - wallet := client.GetWalletByPubKey(useClientID) + wallet := client.GetWalletByKey(useClientID) if wallet == nil { return nil, errors.New("wallet not found", useClientID) } @@ -762,7 +761,7 @@ func getReferencePathV2(blobber *blockchain.StorageNode, allocationID, allocatio return trie, nil } -func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int, clientIds ...string) (err error) { +func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, connectionID, allocationID, allocationTx string, apiVersion int, keys ...string) (err error) { var ( resp *http.Response shouldContinue bool @@ -775,7 +774,7 @@ func submitWriteMarker(wmData, metaData []byte, blobber *blockchain.StorageNode, l.Logger.Error("Creating form writer failed: ", err) return } - httpreq, err := zboxutil.NewCommitRequest(blobber.Baseurl, allocationID, allocationTx, body, apiVersion, clientIds...) + httpreq, err := zboxutil.NewCommitRequest(blobber.Baseurl, allocationID, allocationTx, body, apiVersion, keys...) if err != nil { l.Logger.Error("Error creating commit req: ", err) return diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index 73b304c5b..8659d475d 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -630,12 +630,12 @@ func (req *DeleteRequest) deleteSubDirectories() error { } if req.clientId != "" { clientId := req.clientId - wallet := client.GetWalletByPubKey(clientId) + wallet := client.GetWalletByKey(clientId) if wallet == nil { return errors.New("client_not_found", clientId) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Wallet = wallet + mo.Pubkey = wallet }) } else { err = req.allocationObj.DoMultiOperation(ops) @@ -675,12 +675,12 @@ func (req *DeleteRequest) deleteSubDirectories() error { } if req.clientId != "" { clientId := req.clientId - wallet := client.GetWalletByPubKey(clientId) + wallet := client.GetWalletByKey(clientId) if wallet == nil { return errors.New("client_not_found", clientId) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Wallet = wallet + mo.Pubkey = wallet }) } else { err = req.allocationObj.DoMultiOperation(ops) diff --git a/zboxcore/sdk/dirworker.go b/zboxcore/sdk/dirworker.go index bdca91bdb..d333daa9e 100644 --- a/zboxcore/sdk/dirworker.go +++ b/zboxcore/sdk/dirworker.go @@ -16,7 +16,6 @@ import ( "github.com/0chain/errors" "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/core/util" - "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" @@ -46,7 +45,7 @@ type DirRequest struct { timestamp int64 alreadyExists map[uint64]bool customMeta string - wallet *zcncrypto.Wallet + pubkey string Consensus } @@ -192,8 +191,8 @@ func (req *DirRequest) createDirInBlobber(blobber *blockchain.StorageNode, pos u var ( httpreq *http.Request ) - if req.wallet != nil { - httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.wallet.ClientID) + if req.pubkey != "" { + httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.pubkey) } else { httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) } @@ -291,7 +290,7 @@ type DirOperation struct { maskMU *sync.Mutex customMeta string alreadyExists map[uint64]bool - wallet *zcncrypto.Wallet + pubkey string Consensus } @@ -313,7 +312,7 @@ func (dirOp *DirOperation) Process(allocObj *Allocation, connectionID string) ([ wg: &sync.WaitGroup{}, alreadyExists: make(map[uint64]bool), customMeta: dirOp.customMeta, - wallet: dirOp.wallet, + pubkey: dirOp.pubkey, } dR.Consensus = Consensus{ RWMutex: &sync.RWMutex{}, @@ -375,7 +374,7 @@ func (dirOp *DirOperation) Error(allocObj *Allocation, consensus int, err error) } -func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, wallet *zcncrypto.Wallet) *DirOperation { +func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, pubkey string) *DirOperation { dirOp := &DirOperation{} dirOp.remotePath = zboxutil.RemoteClean(remotePath) dirOp.dirMask = dirMask @@ -383,7 +382,7 @@ func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, ma dirOp.consensusThresh = consensusTh dirOp.fullconsensus = fullConsensus dirOp.customMeta = customMeta - dirOp.wallet = wallet + dirOp.pubkey = pubkey dirOp.ctx, dirOp.ctxCncl = context.WithCancel(ctx) dirOp.alreadyExists = make(map[uint64]bool) return dirOp diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index 9c64e6b8a..94e9a47bb 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -847,7 +847,7 @@ func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageN clientID := client.Id(req.ClientId) clientPublicKey := client.PublicKey() if req.Pubkey != "" { - wallet := client.GetWalletByPubKey(req.Pubkey) + wallet := client.GetWalletByKey(req.Pubkey) if wallet == nil { return fmt.Errorf("wallet not found for public key: %s", req.Pubkey) } diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index b70883049..9a7417050 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -16,7 +16,6 @@ import ( "github.com/0chain/gosdk/core/common" "github.com/0chain/gosdk/core/util" - "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/fileref" "github.com/0chain/gosdk/zboxcore/logger" @@ -64,7 +63,7 @@ type MultiOperation struct { changes [][]allocationchange.AllocationChange changesV2 []allocationchange.AllocationChangeV2 isRepair bool - Wallet *zcncrypto.Wallet + Pubkey string } func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { @@ -97,8 +96,8 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { formWriter.Close() var httpreq *http.Request - if mo.Wallet != nil { - httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.Wallet.ClientID) + if mo.Pubkey != "" { + httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.Pubkey) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating new connection request by wallet", err) return err, false @@ -278,8 +277,8 @@ func (mo *MultiOperation) Process() error { start = time.Now() status := Commit if !mo.isRepair && !mo.allocationObj.checkStatus { - if mo.Wallet != nil { - status, _, err = mo.allocationObj.CheckAllocStatus(mo.Wallet.ClientID) + if mo.Pubkey != "" { + status, _, err = mo.allocationObj.CheckAllocStatus(mo.Pubkey) } else { status, _, err = mo.allocationObj.CheckAllocStatus() } @@ -438,7 +437,7 @@ func (mo *MultiOperation) commitV2() error { consensusThresh: threshold, changes: changes, isRepair: mo.isRepair, - wallet: mo.Wallet, + pubkey: mo.Pubkey, } commitReqs[counter] = commitReq counter++ diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 1369c6185..63240e506 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -62,21 +62,21 @@ type BlobberStatus struct { Status string } -func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, clientId ...string) (*LatestPrevWriteMarker, error) { +func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, keys ...string) (*LatestPrevWriteMarker, error) { var lpm LatestPrevWriteMarker - var useClientID string - if len(clientId) > 0 && clientId[0] != "" { - useClientID = clientId[0] + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } else { - useClientID = client.Id() + key = client.Id() } - wallet := client.GetWalletByPubKey(useClientID) + wallet := client.GetWalletByKey(key) if wallet == nil { - return nil, errors.New("wallet not found : " + useClientID) + return nil, errors.New("wallet not found : " + key) } - req, err := zboxutil.NewWritemarkerRequest(baseUrl, allocID, allocTx, sig, clientId...) + req, err := zboxutil.NewWritemarkerRequest(baseUrl, allocID, allocTx, sig, keys...) if err != nil { return nil, err } @@ -279,13 +279,13 @@ func (rb *RollbackBlobber) processRollback(ctx context.Context, tx string) error // CheckAllocStatus checks the status of the allocation // and returns the status of the allocation and its blobbers. -func (a *Allocation) CheckAllocStatus(clientId ...string) (AllocStatus, []BlobberStatus, error) { +func (a *Allocation) CheckAllocStatus(keys ...string) (AllocStatus, []BlobberStatus, error) { - var useClientID string - if len(clientId) > 0 && clientId[0] != "" { - useClientID = clientId[0] + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } else { - useClientID = a.Owner + key = a.Owner } wg := &sync.WaitGroup{} @@ -303,7 +303,7 @@ func (a *Allocation) CheckAllocStatus(clientId ...string) (AllocStatus, []Blobbe ID: blobber.ID, Status: "available", } - wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, useClientID) + wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, key) if err != nil { atomic.AddInt32(&errCnt, 1) markerError = err diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 0b018bca4..560751985 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -1572,7 +1572,7 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin OperationType: constants.FileOperationInsert, Opts: options, Workdir: workdir, - RemotePath: fileMeta.RemotePath, + RemotePath: fileMeta.RemotePath, } if isUpdate[idx] { @@ -1583,9 +1583,9 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin } } - - setWalletOpt := func (mo *MultiOperation) { - mo.Wallet = &wallet + + setWalletOpt := func(mo *MultiOperation) { + mo.Pubkey = &wallet } return a.DoMultiOperation(operationRequests, setWalletOpt) } diff --git a/zboxcore/sdk/upload_worker.go b/zboxcore/sdk/upload_worker.go index 285443c1e..e405e504f 100644 --- a/zboxcore/sdk/upload_worker.go +++ b/zboxcore/sdk/upload_worker.go @@ -35,7 +35,9 @@ func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([ if f, ok := uo.chunkedUpload.fileReader.(sys.File); ok { err := allocObj.DownloadFileToFileHandler(f, uo.chunkedUpload.fileMeta.RemotePath, false, nil, true, WithFileCallback(func() { f.Close() //nolint:errcheck - })) + }), func(dr *DownloadRequest) { + dr.Pubkey = uo.chunkedUpload.pubkey + }) if err != nil { l.Logger.Error("DownloadFileToFileHandler Failed", zap.String("path", uo.chunkedUpload.fileMeta.RemotePath), zap.Error(err)) return nil, uo.chunkedUpload.uploadMask, err diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index d4e1ffc44..f2e460a41 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -198,11 +198,11 @@ func NewHTTPRequest(method string, url string, data []byte) (*http.Request, cont return req, ctx, cncl, err } -func setClientInfo(req *http.Request, clientIds ...string) { - if len(clientIds) > 0 && clientIds[0] != "" { - wallet := client.GetWalletByPubKey(clientIds[0]) +func setClientInfo(req *http.Request, keys ...string) { + if len(keys) > 0 && keys[0] != "" { + wallet := client.GetWalletByKey(keys[0]) if wallet == nil { - panic("wallet not found : " + clientIds[0]) + panic("wallet not found : " + keys[0]) } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) @@ -212,16 +212,16 @@ func setClientInfo(req *http.Request, clientIds ...string) { req.Header.Set("X-App-Client-Key", client.PublicKey()) } -func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, clients ...string) error { - var clientID string - if len(clients) > 0 && clients[0] != "" { - clientID = clients[0] +func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, keys ...string) error { + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } else { - clientID = client.Id() + key = client.Id() } - wallet := client.GetWalletByPubKey(clientID) + wallet := client.GetWalletByKey(key) if wallet == nil { - return errors.New("wallet not found", clientID) + return errors.New("wallet not found", key) } fmt.Printf("setClientInfoWithSign: wallet details: %+v\n", *wallet) req.Header.Set("X-App-Client-ID", wallet.ClientID) @@ -229,20 +229,20 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, c req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) hashData := allocation + baseURL - sig2, ok := SignCache.Get(hashData + ":" + clientID) + sig2, ok := SignCache.Get(hashData + ":" + key) if !ok { var err error - sig2, err = client.Sign(encryption.Hash(hashData), clientID) + sig2, err = client.Sign(encryption.Hash(hashData), key) if err != nil { return err } - SignCache.Add(hashData+":"+clientID, sig2) + SignCache.Add(hashData+":"+key, sig2) } req.Header.Set(CLIENT_SIGNATURE_HEADER_V2, sig2) return nil } -func NewCommitRequest(baseUrl, allocationID string, allocationTx string, body io.Reader, apiVersion int, clients ...string) (*http.Request, error) { +func NewCommitRequest(baseUrl, allocationID string, allocationTx string, body io.Reader, apiVersion int, keys ...string) (*http.Request, error) { var ( u *url.URL err error @@ -260,7 +260,7 @@ func NewCommitRequest(baseUrl, allocationID string, allocationTx string, body io if err != nil { return nil, err } - setClientInfo(req, clients...) + setClientInfo(req, keys...) req.Header.Set(ALLOCATION_ID_HEADER, allocationID) @@ -296,7 +296,7 @@ func NewReferencePathRequest(baseUrl, allocationID string, allocationTx string, return req, nil } -func NewReferencePathRequestV2(baseUrl, allocationID, allocationTx, sig string, paths []string, loadOnly bool, clients ...string) (*http.Request, error) { +func NewReferencePathRequestV2(baseUrl, allocationID, allocationTx, sig string, paths []string, loadOnly bool, keys ...string) (*http.Request, error) { nurl, err := joinUrl(baseUrl, REFERENCE_ENDPOINT_V2, allocationTx) if err != nil { return nil, err @@ -318,7 +318,7 @@ func NewReferencePathRequestV2(baseUrl, allocationID, allocationTx, sig string, return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } @@ -674,7 +674,7 @@ func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string } else { clientID = client.Id() } - wallet := client.GetWalletByPubKey(clientID) + wallet := client.GetWalletByKey(clientID) if wallet == nil { return errors.New("wallet not found", clientID) } @@ -746,7 +746,7 @@ func NewUploadRequest(baseUrl, allocationID, allocationTx, sig string, body io.R // return req, nil // } -func NewConnectionRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, clients ...string) (*http.Request, error) { +func NewConnectionRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, keys ...string) (*http.Request, error) { l.Logger.Info(fmt.Sprintf("NewConnectionRequest: baseUrl: %s, allocationID: %s, allocationTx: %s, sig: %s", baseUrl, allocationID, allocationTx, sig)) u, err := joinUrl(baseUrl, CREATE_CONNECTION_ENDPOINT, allocationTx) if err != nil { @@ -757,7 +757,7 @@ func NewConnectionRequest(baseUrl, allocationID, allocationTx, sig string, body return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } @@ -905,7 +905,7 @@ func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *ur return req, nil } -func NewCreateDirRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, clients ...string) (*http.Request, error) { +func NewCreateDirRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, keys ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, DIR_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -916,7 +916,7 @@ func NewCreateDirRequest(baseUrl, allocationID, allocationTx, sig string, body i return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } @@ -965,7 +965,7 @@ func NewRevokeShareRequest(baseUrl, allocationID, allocationTx, sig string, quer return req, nil } -func NewWritemarkerRequest(baseUrl, allocationID, allocationTx, sig string, clients ...string) (*http.Request, error) { +func NewWritemarkerRequest(baseUrl, allocationID, allocationTx, sig string, keys ...string) (*http.Request, error) { nurl, err := joinUrl(baseUrl, LATEST_WRITE_MARKER_ENDPOINT, allocationTx) if err != nil { @@ -977,7 +977,7 @@ func NewWritemarkerRequest(baseUrl, allocationID, allocationTx, sig string, clie return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } From 4b5ca7b47c3908902d0063d0e91345556342dc83 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 28 Oct 2025 16:56:15 +0530 Subject: [PATCH 22/47] fix compilation --- zboxcore/marker/readmarker.go | 2 +- zboxcore/sdk/blobber_operations.go | 4 ++-- zboxcore/sdk/chunked_upload_form_builder.go | 20 ++++++++++---------- zboxcore/sdk/chunked_upload_process.go | 4 ++-- zboxcore/sdk/copyworker_test.go | 4 ++-- zboxcore/sdk/filestatsworker_test.go | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/zboxcore/marker/readmarker.go b/zboxcore/marker/readmarker.go index 44204f59b..2646914e9 100644 --- a/zboxcore/marker/readmarker.go +++ b/zboxcore/marker/readmarker.go @@ -37,7 +37,7 @@ func (rm *ReadMarker) Sign() error { return errors.New("sign_rm", "wallet not found for public key "+rm.ClientPublicKey) } if rm.IsSignUnderMultiWallet { - rm.Signature, err = client.SignByMultiWallet(rm.GetHash(), rm.ClientPublicKey) + rm.Signature, err = client.Sign(rm.GetHash(), rm.ClientPublicKey) return err } rm.Signature, err = client.Sign(rm.GetHash()) diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index 4d490f5bd..ad6c5cdec 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -197,7 +197,7 @@ func GetUpdateAllocTicket(allocationID, userID, operationType string, roundExpir payload := fmt.Sprintf("%s:%d:%s:%s", allocationID, roundExpiry, userID, operationType) pubkey := client.PublicKey() - signature, err := client.SignByMultiWallet(hex.EncodeToString([]byte(payload)), pubkey) + signature, err := client.Sign(hex.EncodeToString([]byte(payload)), pubkey) if err != nil { return "", err } @@ -368,7 +368,7 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string) (ed25519.PrivateKey } hashData := fmt.Sprintf("%s:%s", ownerPublicKey, "owner_signing_public_key") pubkey := client.PublicKey() - sig, err := client.SignByMultiWallet(encryption.Hash(hashData), pubkey) + sig, err := client.Sign(encryption.Hash(hashData), pubkey) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) return nil, err diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index 92ff3f53a..d21ad8f80 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -24,7 +24,7 @@ type ChunkedUploadFormBuilder interface { fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, clients ...string, + thumbnailChunkData []byte, shardSize int64, keys ...string, ) (blobberData, error) } @@ -59,7 +59,7 @@ func (b *chunkedUploadFormBuilder) Build( fileMeta *FileMeta, hasher Hasher, connectionID, blobberID string, chunkSize int64, chunkStartIndex, chunkEndIndex int, isFinal bool, encryptedKey, encryptedKeyPoint string, fileChunksData [][]byte, - thumbnailChunkData []byte, shardSize int64, clients ...string, + thumbnailChunkData []byte, shardSize int64, keys ...string, ) (blobberData, error) { metadata := ChunkedUploadFormMetadata{ @@ -187,12 +187,12 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ActualFileHashSignature = hex.EncodeToString(sig) } else { - pubkey := client.Wallet().ClientKey - if len(clients) > 0 && clients[0] != "" { - pubkey = client.PublicKey(clients...) + key := client.Wallet().ClientID + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } - sig, err := client.SignByMultiWallet(fileMeta.ActualHash, pubkey) + sig, err := client.Sign(fileMeta.ActualHash, key) if err != nil { return res, err } @@ -211,11 +211,11 @@ func (b *chunkedUploadFormBuilder) Build( } formData.ValidationRootSignature = hex.EncodeToString(sig) } else { - var pubkey string - if len(clients) > 0 && clients[0] != "" { - pubkey = client.PublicKey(clients...) + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } - rootSig, err := client.SignByMultiWallet(hash, pubkey, clients...) + rootSig, err := client.Sign(hash, key) if err != nil { return res, err } diff --git a/zboxcore/sdk/chunked_upload_process.go b/zboxcore/sdk/chunked_upload_process.go index cf38353ee..94dcb2515 100644 --- a/zboxcore/sdk/chunked_upload_process.go +++ b/zboxcore/sdk/chunked_upload_process.go @@ -107,11 +107,11 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, defer wg.Done() var uploadData blobberData var err error - if su.pubkey != nil { + if su.pubkey != "" { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, - fileShards[pos], thumbnailChunkData, su.shardSize, su.pubkey.ClientID) + fileShards[pos], thumbnailChunkData, su.shardSize, su.pubkey) } else { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, diff --git a/zboxcore/sdk/copyworker_test.go b/zboxcore/sdk/copyworker_test.go index fdc7a3496..a9d32437a 100644 --- a/zboxcore/sdk/copyworker_test.go +++ b/zboxcore/sdk/copyworker_test.go @@ -496,8 +496,8 @@ func TestCopyRequest_ProcessCopy(t *testing.T) { maskMU: &sync.Mutex{}, connectionID: mockConnectionId, } - pubkey := client.PublicKey() - sig, err := client.SignByMultiWallet(mockAllocationTxId, pubkey) + key := client.Id() + sig, err := client.Sign(mockAllocationTxId, key) require.NoError(err) req.sig = sig req.ctx, req.ctxCncl = context.WithCancel(context.TODO()) diff --git a/zboxcore/sdk/filestatsworker_test.go b/zboxcore/sdk/filestatsworker_test.go index a1a50f97a..75e590998 100644 --- a/zboxcore/sdk/filestatsworker_test.go +++ b/zboxcore/sdk/filestatsworker_test.go @@ -127,8 +127,8 @@ func TestListRequest_getFileStatsInfoFromBlobber(t *testing.T) { require.NoError(t, err) require.EqualValues(t, expected, string(actual)) - pubkey := client.PublicKey() - sign, _ := client.SignByMultiWallet(encryption.Hash(mockAllocationTxId), pubkey) + key := client.Id() + sign, _ := client.Sign(encryption.Hash(mockAllocationTxId), key) return req.URL.Path == "Test_Success"+zboxutil.FILE_STATS_ENDPOINT+mockAllocationTxId && req.Method == "POST" && req.Header.Get("X-App-Client-ID") == mockClientId && From 31f7236bac6f65a5bd18307a83e7cdeefe641fab Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 28 Oct 2025 17:15:22 +0530 Subject: [PATCH 23/47] fix compilation --- zboxcore/sdk/allocation.go | 10 ++++----- zboxcore/sdk/chunked_upload_blobber.go | 8 +++---- zboxcore/sdk/chunked_upload_option.go | 3 +-- zboxcore/sdk/deleteworker.go | 30 ++++++++++++-------------- zboxcore/sdk/sdk.go | 7 +++--- zboxcore/zboxutil/http.go | 28 ++++++++++++------------ 6 files changed, 41 insertions(+), 45 deletions(-) diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 91f30fa78..200c168d9 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1172,17 +1172,17 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) case constants.FileOperationDelete: - var pubkey string + var key string if mo.Pubkey != "" { - pubkey = mo.Pubkey + key = mo.Pubkey } else { - pubkey = mo.allocationObj.Owner + key = mo.allocationObj.Owner } if op.Mask != nil { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, pubkey) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, *op.Mask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, key) } else { - operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, pubkey) + operation = NewDeleteOperation(mo.ctx, op.RemotePath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, key) } case constants.FileOperationUpdate: diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index 80c5c7e1e..e9fbc53cb 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -71,9 +71,9 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( eg, _ := errgroup.WithContext(ctx) - clientID := su.allocationObj.Owner - if su.pubkey != nil { - clientID = su.pubkey.ClientID + key := su.allocationObj.Owner + if su.pubkey != "" { + key = su.pubkey } for dataInd := 0; dataInd < len(dataBuffers); dataInd++ { ind := dataInd @@ -84,7 +84,7 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( var req *fasthttp.Request for i := 0; i < 6; i++ { req, err = zboxutil.NewFastUploadRequest( - sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, dataBuffers[ind].Bytes(), su.httpMethod, clientID) + sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, dataBuffers[ind].Bytes(), su.httpMethod, key) if err != nil { return err } diff --git a/zboxcore/sdk/chunked_upload_option.go b/zboxcore/sdk/chunked_upload_option.go index e6dd9c5df..1ce015c45 100644 --- a/zboxcore/sdk/chunked_upload_option.go +++ b/zboxcore/sdk/chunked_upload_option.go @@ -7,7 +7,6 @@ import ( "os" "time" - "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/zboxutil" "github.com/klauspost/reedsolomon" ) @@ -38,7 +37,7 @@ func WithThumbnail(buf []byte) ChunkedUploadOption { } } -func WithWallet(w *zcncrypto.Wallet) ChunkedUploadOption { +func WithWallet(w string) ChunkedUploadOption { return func(su *ChunkedUpload) { su.pubkey = w } diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index 8659d475d..93a3a052a 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -44,7 +44,7 @@ type DeleteRequest struct { connectionID string consensus Consensus timestamp int64 - clientId string + key string } var errFileDeleted = errors.New("file_deleted", "file is already deleted") @@ -68,7 +68,7 @@ func (req *DeleteRequest) deleteBlobberFile( query.Add("connection_id", req.connectionID) query.Add("path", req.remotefilepath) - httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.clientId) + httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.key) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating delete request", err) return err @@ -358,7 +358,7 @@ type DeleteOperation struct { consensus Consensus lookupHash string refs []fileref.RefEntity - clientId string + key string } func (dop *DeleteOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { @@ -377,7 +377,7 @@ func (dop *DeleteOperation) Process(allocObj *Allocation, connectionID string) ( maskMu: dop.maskMu, wg: &sync.WaitGroup{}, consensus: Consensus{RWMutex: &sync.RWMutex{}}, - clientId: dop.clientId, + key: dop.key, } deleteReq.consensus.fullconsensus = dop.consensus.fullconsensus deleteReq.consensus.consensusThresh = dop.consensus.consensusThresh @@ -586,7 +586,7 @@ func (dop *DeleteOperation) Error(allocObj *Allocation, consensus int, err error } -func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int, clientIds ...string) *DeleteOperation { +func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxutil.Uint128, maskMu *sync.Mutex, consensusTh, fullConsensus int, keys ...string) *DeleteOperation { dop := &DeleteOperation{} dop.remotefilepath = zboxutil.RemoteClean(remotePath) dop.deleteMask = deleteMask @@ -594,7 +594,7 @@ func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxu dop.consensus.consensusThresh = consensusTh dop.consensus.fullconsensus = fullConsensus dop.ctx, dop.ctxCncl = context.WithCancel(ctx) - dop.clientId = clientIds[0] + dop.key = keys[0] return dop } @@ -628,14 +628,13 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - if req.clientId != "" { - clientId := req.clientId - wallet := client.GetWalletByKey(clientId) + if req.key != "" { + wallet := client.GetWalletByKey(req.key) if wallet == nil { - return errors.New("client_not_found", clientId) + return errors.New("client_not_found", req.key) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Pubkey = wallet + mo.Pubkey = req.key }) } else { err = req.allocationObj.DoMultiOperation(ops) @@ -673,14 +672,13 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - if req.clientId != "" { - clientId := req.clientId - wallet := client.GetWalletByKey(clientId) + if req.key != "" { + wallet := client.GetWalletByKey(req.key) if wallet == nil { - return errors.New("client_not_found", clientId) + return errors.New("client_not_found", req.key) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Pubkey = wallet + mo.Pubkey = req.key }) } else { err = req.allocationObj.DoMultiOperation(ops) diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 560751985..9cc460c20 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -20,7 +20,6 @@ import ( "github.com/0chain/gosdk/core/pathutil" "github.com/0chain/gosdk/core/screstapi" "github.com/0chain/gosdk/core/sys" - "github.com/0chain/gosdk/core/zcncrypto" // "github.com/0chain/gosdk/zcncore" "gopkg.in/natefinch/lumberjack.v2" @@ -1485,7 +1484,7 @@ func updateMaskBit(mask uint16, index uint8, value bool) uint16 { } // DoMultiUploadByWallet uploads multiple files to the allocation using the given wallet. -func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback) error { +func DoMultiUploadByWallet(pubkey string, a *Allocation, workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback) error { if len(localPaths) != len(thumbnailPaths) { return errors.New("invalid_value", "length of localpaths and thumbnailpaths must be equal") @@ -1565,7 +1564,7 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin options = append(options, WithThumbnail(buf)) } - options = append(options, WithWallet(&wallet)) + options = append(options, WithWallet(pubkey)) operationRequests[idx] = OperationRequest{ FileMeta: fileMeta, FileReader: fileReader, @@ -1585,7 +1584,7 @@ func DoMultiUploadByWallet(wallet zcncrypto.Wallet, a *Allocation, workdir strin } setWalletOpt := func(mo *MultiOperation) { - mo.Pubkey = &wallet + mo.Pubkey = pubkey } return a.DoMultiOperation(operationRequests, setWalletOpt) } diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index f2e460a41..9c4f34f3d 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -646,7 +646,7 @@ func NewWriteMarkerUnLockRequest( return req, nil } -func NewFastUploadRequest(baseURL, allocationID string, allocationTx string, body []byte, method string, clients ...string) (*fasthttp.Request, error) { +func NewFastUploadRequest(baseURL, allocationID string, allocationTx string, body []byte, method string, keys ...string) (*fasthttp.Request, error) { u, err := joinUrl(baseURL, UPLOAD_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -659,7 +659,7 @@ func NewFastUploadRequest(baseURL, allocationID string, allocationTx string, bod req.SetBodyRaw(body) // set header: X-App-Client-Signature - if err := setFastClientInfoWithSign(req, allocationTx, baseURL, clients...); err != nil { + if err := setFastClientInfoWithSign(req, allocationTx, baseURL, keys...); err != nil { return nil, err } @@ -667,30 +667,30 @@ func NewFastUploadRequest(baseURL, allocationID string, allocationTx string, bod return req, nil } -func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string, clients ...string) error { - var clientID string - if len(clients) > 0 && clients[0] != "" { - clientID = clients[0] +func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string, keys ...string) error { + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] } else { - clientID = client.Id() + key = client.Id() } - wallet := client.GetWalletByKey(clientID) + wallet := client.GetWalletByKey(key) if wallet == nil { - return errors.New("wallet not found", clientID) + return errors.New("wallet not found", key) } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) hashData := allocation + baseURL // clientID := client.Id() - sig2, ok := SignCache.Get(hashData + ":" + clientID) + sig2, ok := SignCache.Get(hashData + ":" + key) if !ok { var err error - sig2, err = client.Sign(encryption.Hash(hashData), clientID) + sig2, err = client.Sign(encryption.Hash(hashData), key) if err != nil { return err } - SignCache.Add(hashData+":"+clientID, sig2) + SignCache.Add(hashData+":"+key, sig2) } req.Header.Set(CLIENT_SIGNATURE_HEADER_V2, sig2) return nil @@ -884,7 +884,7 @@ func NewRedeemRequest(baseUrl, allocationID, allocationTx string, clients ...str return req, nil } -func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, clients ...string) (*http.Request, error) { +func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *url.Values, keys ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, UPLOAD_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -896,7 +896,7 @@ func NewDeleteRequest(baseUrl, allocationID, allocationTx, sig string, query *ur return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } From 7888d32c609ac639e66daf8d2a33e91d2c62e56a Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 31 Oct 2025 15:28:11 +0530 Subject: [PATCH 24/47] fix compilation --- core/client/set.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/client/set.go b/core/client/set.go index 1ce201b2a..43d26dd8f 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -260,6 +260,10 @@ func GetWalletByKey(key string) *zcncrypto.Wallet { return client.wallets[key] } +func GetWallet() *zcncrypto.Wallet { + return client.wallet +} + // AddWallet adds a new wallet to the sdk. func AddWallet(wallet zcncrypto.Wallet) { pubkey := wallet.Keys[0].PublicKey From e66a8a69274b593572bd7e57836d95e7bd2085ca Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 31 Oct 2025 15:36:21 +0530 Subject: [PATCH 25/47] init sdk --- core/client/set.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/core/client/set.go b/core/client/set.go index 43d26dd8f..44aeb5812 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -1,6 +1,7 @@ package client import ( + "context" "encoding/json" "errors" "fmt" @@ -8,6 +9,7 @@ import ( "sync" "github.com/0chain/gosdk/constants" + "github.com/0chain/gosdk/core/conf" "github.com/0chain/gosdk/core/sys" "github.com/0chain/gosdk/core/zcncrypto" ) @@ -113,6 +115,83 @@ var SignFn = func(hash string) (string, error) { return ss.Sign(hash) } +// InitSDK Initialize the storage SDK +// +// - walletJSON: Client's wallet JSON +// - blockWorker: Block worker URL (block worker refers to 0DNS) +// - chainID: ID of the blokcchain network +// - signatureScheme: Signature scheme that will be used for signing transactions +// - preferredBlobbers: List of preferred blobbers to use when creating an allocation. This is usually configured by the client in the configuration files +// - nonce: Initial nonce value for the transactions +// - fee: Preferred value for the transaction fee, just the first value is taken +func InitSDK(walletJSON string, + blockWorker, chainID, signatureScheme string, + nonce int64, addWallet bool, + options ...int) error { + + if addWallet { + wallet := zcncrypto.Wallet{} + err := json.Unmarshal([]byte(walletJSON), &wallet) + if err != nil { + return err + } + + SetWallet(wallet) + SetSignatureScheme(signatureScheme) + SetNonce(nonce) + if len(options) > 0 { + SetTxnFee(uint64(options[0])) + } + } + + var minConfirmation, minSubmit, confirmationChainLength, sharderConsensous int + if len(options) > 1 { + minConfirmation = options[1] + } + if len(options) > 2 { + minSubmit = options[2] + } + if len(options) > 3 { + confirmationChainLength = options[3] + } + if len(options) > 4 { + sharderConsensous = options[4] + } + + err := Init(context.Background(), conf.Config{ + BlockWorker: blockWorker, + SignatureScheme: signatureScheme, + ChainID: chainID, + MinConfirmation: minConfirmation, + MinSubmit: minSubmit, + ConfirmationChainLength: confirmationChainLength, + SharderConsensous: sharderConsensous, + }) + if err != nil { + return err + } + SetSdkInitialized(true) + return nil +} + +func InitSDKWithWebApp(params InitSdkOptions) error { + if params.MinConfirmation != nil && params.MinSubmit != nil && params.ConfirmationChainLength != nil && params.SharderConsensous != nil { + err := InitSDK(params.WalletJSON, params.BlockWorker, params.ChainID, params.SignatureScheme, params.Nonce, params.AddWallet, *params.MinConfirmation, *params.MinSubmit, *params.ConfirmationChainLength, *params.SharderConsensous) + if err != nil { + return err + } + } else { + err := InitSDK(params.WalletJSON, params.BlockWorker, params.ChainID, params.SignatureScheme, params.Nonce, params.AddWallet) + if err != nil { + return err + } + } + conf.SetZboxAppConfigs(params.ZboxHost, params.ZboxAppType) + SetIsAppFlow(true) + return nil +} + + func IsSDKInitialized() bool { return sdkInitialized } From f959b3e2b7a1def5162f05b7438da021b110c249 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sun, 2 Nov 2025 11:00:23 +0530 Subject: [PATCH 26/47] changes --- core/client/set.go | 2 ++ zboxcore/marker/readmarker.go | 5 +---- zboxcore/sdk/allocation.go | 11 +---------- zboxcore/sdk/downloadworker.go | 16 ++++++++++++++++ zboxcore/sdk/filemetaworker.go | 7 ++++++- zboxcore/sdk/listworker.go | 1 + zboxcore/zboxutil/http.go | 4 ++-- 7 files changed, 29 insertions(+), 17 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 44aeb5812..6b57221b2 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -81,6 +81,8 @@ func init() { } } + fmt.Print("wallet found: client_id: ", wallet.ClientID, "is_split: ", wallet.IsSplit, "pubkey: ", wallet.Keys[0].PublicKey) + if !wallet.IsSplit { return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(keys...)) } diff --git a/zboxcore/marker/readmarker.go b/zboxcore/marker/readmarker.go index 2646914e9..c56ef0e04 100644 --- a/zboxcore/marker/readmarker.go +++ b/zboxcore/marker/readmarker.go @@ -31,11 +31,8 @@ func (rm *ReadMarker) GetHash() string { } func (rm *ReadMarker) Sign() error { + fmt.Print("ReadMarker sign: ", rm.ClientID, rm.ClientPublicKey, rm.IsSignUnderMultiWallet) var err error - wallet := client.GetWalletByKey(rm.ClientPublicKey) - if wallet == nil { - return errors.New("sign_rm", "wallet not found for public key "+rm.ClientPublicKey) - } if rm.IsSignUnderMultiWallet { rm.Signature, err = client.Sign(rm.GetHash(), rm.ClientPublicKey) return err diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 200c168d9..25b36634b 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -1330,6 +1330,7 @@ func (a *Allocation) DownloadFile(localPath string, remotePath string, verifyDow })) err = a.addAndGenerateDownloadRequest(f, remotePath, DOWNLOAD_CONTENT_FULL, 1, 0, numBlockDownloads, verifyDownload, status, isFinal, localFilePath, downloadReqOpts...) + fmt.Print("err in addAndGenerateDownloadRequest: ", err) if err != nil { if !toKeep { os.Remove(localFilePath) //nolint: errcheck @@ -1499,16 +1500,6 @@ func (a *Allocation) addAndGenerateDownloadRequest( for _, opt := range downloadReqOpts { opt(downloadReq) } - if downloadReq.Pubkey != "" { - wallet := client.GetWalletByKey(downloadReq.Pubkey) - var err error - var sk []byte - sk, err = GenerateOwnerSigningKey(downloadReq.Pubkey, wallet.ClientID) - if err != nil { - return err - } - downloadReq.allocOwnerSigningPrivateKey = sk - } downloadReq.workdir = filepath.Join(downloadReq.workdir, ".zcn") hash := encryption.Hash(fmt.Sprintf("%s:%d:%d", remotePath, startBlock, endBlock)) a.downloadProgressMap[hash] = downloadReq diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index 94e9a47bb..1486e0675 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -437,6 +437,7 @@ func (req *DownloadRequest) getDecryptedDataForAuthTicket(result *downloadBlock, // start block, end block and number of blocks to download in single request. // This will also write data to the file handler and will verify content by calculating content hash. func (req *DownloadRequest) processDownload() { + fmt.Print("inside process download: pubkey", req.Pubkey, "\n") ctx := req.ctx if req.completedCallback != nil { defer req.completedCallback(req.remotefilepath, req.remotefilepathhash) @@ -841,6 +842,7 @@ func (req *DownloadRequest) submitReadMarker(blobber *blockchain.StorageNode, re } func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageNode, readCount int64) error { + l.Logger.Info("attemptSubmitReadMarker: pubKey:", req.Pubkey, "\n") lockBlobberReadCtr(req.allocationID, blobber.ID) defer unlockBlobberReadCtr(req.allocationID, blobber.ID) @@ -854,6 +856,7 @@ func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageN clientID = wallet.ClientID clientPublicKey = req.Pubkey } + l.Logger.Info("DownloadRequest: clientID:", clientID, " clientPublicKey:", clientPublicKey, "\n") rm := &marker.ReadMarker{ ClientID: clientID, ClientPublicKey: clientPublicKey, @@ -1218,9 +1221,12 @@ func (req *DownloadRequest) getFileRef() (fRef *fileref.FileRef, err error) { consensusThresh: req.consensusThresh, }, ctx: req.ctx, + Pubkey: req.Pubkey, } fMetaResp := listReq.getFileMetaFromBlobbers() + l.Logger.Info("fMetaResp length: ", len(fMetaResp), "\n") + fRef, err = req.getFileMetaConsensus(fMetaResp) if err != nil { @@ -1259,12 +1265,22 @@ func (req *DownloadRequest) getFileMetaConsensus(fMetaResp []*fileMetaResponse) actualFileHashSignature, actualHash, ) + l.Logger.Info("allocOwnerSigningPubKey: ", req.allocOwnerSigningPubKey, "\n") + l.Logger.Info("actualFileHashSignature: ", actualFileHashSignature, "\n") + l.Logger.Info("actualHash: ", actualHash, "\n") + l.Logger.Info("err: ", err, "\n") + l.Logger.Info("isValid: ", isValid, "\n") } else { isValid, err = sys.VerifyWith( req.allocOwnerPubKey, actualFileHashSignature, actualHash, ) + l.Logger.Info("allocOwnerPubKey: ", req.allocOwnerPubKey, "\n") + l.Logger.Info("actualFileHashSignature: ", actualFileHashSignature, "\n") + l.Logger.Info("actualHash: ", actualHash, "\n") + l.Logger.Info("err: ", err, "\n") + l.Logger.Info("isValid: ", isValid, "\n") } if err != nil { l.Logger.Error(err) diff --git a/zboxcore/sdk/filemetaworker.go b/zboxcore/sdk/filemetaworker.go index 1d614f7f8..d9c0fd22b 100644 --- a/zboxcore/sdk/filemetaworker.go +++ b/zboxcore/sdk/filemetaworker.go @@ -12,6 +12,7 @@ import ( "github.com/0chain/errors" "github.com/0chain/gosdk/constants" + "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" l "github.com/0chain/gosdk/zboxcore/logger" @@ -76,7 +77,11 @@ func (req *ListRequest) getFileMetaInfoFromBlobber(blobber *blockchain.StorageNo } formWriter.Close() - httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.ClientId) + key := client.Wallet().ClientID + if req.Pubkey != "" { + key = req.Pubkey + } + httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, key) if err != nil { l.Logger.Error("File meta info request error: ", err.Error()) return diff --git a/zboxcore/sdk/listworker.go b/zboxcore/sdk/listworker.go index 41b802aba..519621850 100644 --- a/zboxcore/sdk/listworker.go +++ b/zboxcore/sdk/listworker.go @@ -39,6 +39,7 @@ type ListRequest struct { pageLimit int storageVersion int dataShards int + Pubkey string Consensus } diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index 9c4f34f3d..9064c1f56 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -509,7 +509,7 @@ func DeleteCollaboratorRequest(baseUrl, allocationID, allocationTx, sig string, return req, nil } -func NewFileMetaRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, clients ...string) (*http.Request, error) { +func NewFileMetaRequest(baseUrl, allocationID, allocationTx, sig string, body io.Reader, keys ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, FILE_META_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -519,7 +519,7 @@ func NewFileMetaRequest(baseUrl, allocationID, allocationTx, sig string, body io return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } From ecae4223c8b9c262a7ed748b4ff83f87a8f99407 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Thu, 6 Nov 2025 23:44:01 +0530 Subject: [PATCH 27/47] download test --- core/client/set.go | 2 ++ zboxcore/sdk/blockdownloadworker.go | 9 ++++++++- zboxcore/sdk/downloadworker.go | 3 +++ zboxcore/zboxutil/http.go | 30 ++++++++++++++++++++--------- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 6b57221b2..0f5ed74a4 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -89,7 +89,9 @@ func init() { // split-key signing via auth <-sigC + fmt.Println("Sign: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeys(keys...)) sig, err := sys.SignWithAuth(hash, client.signatureScheme, GetClientSysKeys(keys...), wallet.Keys[0].PublicKey) + fmt.Println("Signature: ", sig) sigC <- struct{}{} return sig, err } diff --git a/zboxcore/sdk/blockdownloadworker.go b/zboxcore/sdk/blockdownloadworker.go index d05f90feb..56e705062 100644 --- a/zboxcore/sdk/blockdownloadworker.go +++ b/zboxcore/sdk/blockdownloadworker.go @@ -48,6 +48,7 @@ type BlockDownloadRequest struct { shouldVerify bool connectionID string respBuf []byte + Pubkey string } type downloadResponse struct { @@ -128,7 +129,13 @@ func (req *BlockDownloadRequest) downloadBlobberBlock(fastClient *fasthttp.Clien req.remotefilepathhash = fileref.GetReferenceLookup(req.allocationID, req.remotefilepath) } - httpreq, err := zboxutil.NewFastDownloadRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx) + var httpreq *fasthttp.Request + var err error + if len(req.Pubkey) > 0 { + httpreq, err = zboxutil.NewFastDownloadRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, req.Pubkey) + } else { + httpreq, err = zboxutil.NewFastDownloadRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx) + } if err != nil { req.result <- &downloadBlock{Success: false, idx: req.blobberIdx, err: errors.Wrap(err, "Error creating download request")} return diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index 1486e0675..8c5cb9a4b 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -271,6 +271,9 @@ func (req *DownloadRequest) downloadBlock( connectionID: req.connectionID, } + // propagate the public key (if multi-wallet / split-wallet scenario) + blockDownloadReq.Pubkey = req.Pubkey + if blockDownloadReq.blobber.IsSkip() { rspCh <- &downloadBlock{ Success: false, diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index 9064c1f56..796c95c0f 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -671,15 +671,18 @@ func setFastClientInfoWithSign(req *fasthttp.Request, allocation, baseURL string var key string if len(keys) > 0 && keys[0] != "" { key = keys[0] + wallet := client.GetWalletByKey(key) + if wallet == nil { + return errors.New("multi-wallet-settings err: ", "wallet not found : " + key) + } + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) } else { key = client.Id() + req.Header.Set("X-App-Client-ID", client.Id()) + req.Header.Set("X-App-Client-Key", client.PublicKey()) } - wallet := client.GetWalletByKey(key) - if wallet == nil { - return errors.New("wallet not found", key) - } - req.Header.Set("X-App-Client-ID", wallet.ClientID) - req.Header.Set("X-App-Client-Key", wallet.ClientKey) + hashData := allocation + baseURL // clientID := client.Id() @@ -853,7 +856,7 @@ func NewDownloadRequest(baseUrl, allocationID, allocationTx string, clients ...s return req, nil } -func NewFastDownloadRequest(baseUrl, allocationID, allocationTx string, clients ...string) (*fasthttp.Request, error) { +func NewFastDownloadRequest(baseUrl, allocationID, allocationTx string, keys ...string) (*fasthttp.Request, error) { u, err := joinUrl(baseUrl, DOWNLOAD_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -861,8 +864,17 @@ func NewFastDownloadRequest(baseUrl, allocationID, allocationTx string, clients req := fasthttp.AcquireRequest() req.SetRequestURI(u.String()) - req.Header.Set("X-App-Client-ID", client.Id()) - req.Header.Set("X-App-Client-Key", client.PublicKey()) + if len(keys) > 0 && keys[0] != "" { + wallet := client.GetWalletByKey(keys[0]) + if wallet == nil { + return nil, errors.New("multi-wallet-settings err: ", "wallet not found : " + keys[0]) + } + req.Header.Set("X-App-Client-ID", wallet.ClientID) + req.Header.Set("X-App-Client-Key", wallet.ClientKey) + } else { + req.Header.Set("X-App-Client-ID", client.Id()) + req.Header.Set("X-App-Client-Key", client.PublicKey()) + } req.Header.Set(ALLOCATION_ID_HEADER, allocationID) From 246b9df6700d942a36b4b800079650bedf3e7016 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 7 Nov 2025 21:40:59 +0530 Subject: [PATCH 28/47] upload complete --- zboxcore/marker/writemarker.go | 11 +++++++++- zboxcore/sdk/chunked_upload.go | 2 +- zboxcore/sdk/chunked_upload_blobber.go | 10 +++++++-- zboxcore/sdk/commitworker.go | 21 +++++++++++++++---- zboxcore/sdk/multi_operation_worker.go | 5 ++++- zboxcore/sdk/rollback.go | 25 ++++++++++++----------- zboxcore/sdk/writemarker_mutex.go | 16 ++++++++++++--- zboxcore/zboxutil/http.go | 28 +++++++++++++++----------- 8 files changed, 82 insertions(+), 36 deletions(-) diff --git a/zboxcore/marker/writemarker.go b/zboxcore/marker/writemarker.go index 950af095c..0d96562d5 100644 --- a/zboxcore/marker/writemarker.go +++ b/zboxcore/marker/writemarker.go @@ -49,7 +49,16 @@ func (wm *WriteMarker) GetHash() string { func (wm *WriteMarker) Sign() error { var err error - wm.Signature, err = client.Sign(wm.GetHash(), wm.ClientID) + // If Pubkey is set, use that wallet for signing and set ClientID accordingly. + if wm.Pubkey != "" { + // Use the provided pubkey to sign, but do not overwrite ClientID here. + wm.Signature, err = client.Sign(wm.GetHash(), wm.Pubkey) + return err + } + + // Default: sign with the current SDK wallet. Do not overwrite ClientID + // here either; callers should set ClientID to the allocation owner. + wm.Signature, err = client.Sign(wm.GetHash()) return err } diff --git a/zboxcore/sdk/chunked_upload.go b/zboxcore/sdk/chunked_upload.go index 7eab1b015..a316888aa 100644 --- a/zboxcore/sdk/chunked_upload.go +++ b/zboxcore/sdk/chunked_upload.go @@ -257,7 +257,7 @@ func CreateChunkedUpload( } - su.writeMarkerMutex, err = CreateWriteMarkerMutex(su.allocationObj) + su.writeMarkerMutex, err = CreateWriteMarkerMutex(su.allocationObj, su.pubkey) if err != nil { return nil, err } diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index e9fbc53cb..b9920b9b1 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -15,7 +15,6 @@ import ( "github.com/0chain/errors" thrown "github.com/0chain/errors" "github.com/0chain/gosdk/constants" - "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/zboxcore/allocationchange" "github.com/0chain/gosdk/zboxcore/blockchain" "github.com/0chain/gosdk/zboxcore/fileref" @@ -223,7 +222,14 @@ func (sb *ChunkedUploadBlobber) processCommit(ctx context.Context, su *ChunkedUp wm.BlobberID = sb.blobber.ID wm.Timestamp = timestamp - wm.ClientID = client.Id(su.allocationObj.Owner) + // ClientID should always be the allocation owner. If an operation-level + // pubkey is provided use it only for signing (set Pubkey) but do not + // overwrite ClientID — the blobber expects the write marker ClientID to + // match the allocation owner (the uploader identity). + wm.ClientID = su.allocationObj.Owner + if su.pubkey != "" { + wm.Pubkey = su.pubkey + } err = wm.Sign() if err != nil { logger.Logger.Error("Signing writemarker failed: ", err) diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index f6815261c..850ae835e 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -71,6 +71,7 @@ type CommitRequest struct { result *CommitResult timestamp int64 blobberInd uint64 + pubkey string } type CommitRequestInterface interface { @@ -148,7 +149,11 @@ func (commitreq *CommitRequest) processCommit() { } var req *http.Request var lR ReferencePathResult - req, err := zboxutil.NewReferencePathRequest(commitreq.blobber.Baseurl, commitreq.allocationID, commitreq.allocationTx, commitreq.sig, paths, commitreq.ClientId) + key := client.Id() + if commitreq.pubkey != "" { + key = commitreq.pubkey + } + req, err := zboxutil.NewReferencePathRequest(commitreq.blobber.Baseurl, commitreq.allocationID, commitreq.allocationTx, commitreq.sig, paths, key) if err != nil { l.Logger.Error("Creating ref path req", err) return @@ -284,7 +289,10 @@ func (req *CommitRequest) commitBlobber( wm.Size = size wm.BlobberID = req.blobber.ID wm.Timestamp = req.timestamp - wm.ClientID = client.Id(req.ClientId) + wm.ClientID = req.ClientId + if req.pubkey != "" { + wm.Pubkey = req.pubkey + } err = wm.Sign() if err != nil { l.Logger.Error("Signing writemarker failed: ", err) @@ -309,7 +317,12 @@ func (req *CommitRequest) commitBlobber( l.Logger.Error("Creating form writer failed: ", err) return } - httpreq, err := zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0) + var httpreq *http.Request + if req.pubkey != "" { + httpreq, err = zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0, req.pubkey) + } else { + httpreq, err = zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0) + } if err != nil { l.Logger.Error("Error creating commit req: ", err) return @@ -588,7 +601,7 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh wm.BlobberID = blobber.ID wm.AllocationID = req.allocationObj.ID wm.FileMetaRoot = fileMetaRoot - wm.ClientID = client.Id() + wm.ClientID = req.allocationObj.Owner if req.pubkey != "" { wm.Pubkey = req.pubkey } diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index 9a7417050..d9e9f7c01 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -255,7 +255,7 @@ func (mo *MultiOperation) Process() error { mo.changes = zboxutil.Transpose(mo.changes) } - writeMarkerMutex, err := CreateWriteMarkerMutex(mo.allocationObj) + writeMarkerMutex, err := CreateWriteMarkerMutex(mo.allocationObj, mo.Pubkey) if err != nil { for _, op := range mo.operations { op.Error(mo.allocationObj, 0, err) @@ -344,6 +344,8 @@ func (mo *MultiOperation) Process() error { timestamp := int64(common.Now()) for i := mo.operationMask; !i.Equals64(0); i = i.And(zboxutil.NewUint128(1).Lsh(pos).Not()) { pos = uint64(i.TrailingZeros()) + // ClientId must always be the allocation owner. Use Pubkey only for signing + // (stored in the commit request's pubkey field). commitReq := &CommitRequest{ ClientId: mo.allocationObj.Owner, allocationID: mo.allocationObj.ID, @@ -354,6 +356,7 @@ func (mo *MultiOperation) Process() error { wg: wg, timestamp: timestamp, blobberInd: pos, + pubkey: mo.Pubkey, } commitReq.changes = append(commitReq.changes, mo.changes[pos]...) diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 63240e506..3a9cee1b0 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -20,6 +20,7 @@ import ( "github.com/0chain/common/core/common" thrown "github.com/0chain/errors" "github.com/0chain/gosdk/core/client" + "github.com/0chain/gosdk/core/zcncrypto" "github.com/0chain/gosdk/zboxcore/blockchain" l "github.com/0chain/gosdk/zboxcore/logger" "github.com/0chain/gosdk/zboxcore/marker" @@ -65,16 +66,6 @@ type BlobberStatus struct { func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, keys ...string) (*LatestPrevWriteMarker, error) { var lpm LatestPrevWriteMarker - var key string - if len(keys) > 0 && keys[0] != "" { - key = keys[0] - } else { - key = client.Id() - } - wallet := client.GetWalletByKey(key) - if wallet == nil { - return nil, errors.New("wallet not found : " + key) - } req, err := zboxutil.NewWritemarkerRequest(baseUrl, allocID, allocTx, sig, keys...) if err != nil { @@ -113,12 +104,22 @@ func GetWritemarker(allocID, allocTx, sig, id, baseUrl string, keys ...string) ( return nil, err } if lpm.LatestWM != nil { - err = lpm.LatestWM.VerifySignature(wallet.ClientKey) + // pick wallet for verification + var walletForVerify *zcncrypto.Wallet + if len(keys) > 0 && keys[0] != "" { + walletForVerify = client.GetWalletByKey(keys[0]) + if walletForVerify == nil { + return nil, fmt.Errorf("multi-wallet-settings err: wallet not found : %s", keys[0]) + } + } else { + walletForVerify = client.GetWallet() + } + err = lpm.LatestWM.VerifySignature(walletForVerify.ClientKey) if err != nil { return nil, fmt.Errorf("signature verification failed for latest writemarker: %s", err.Error()) } if lpm.PrevWM != nil { - err = lpm.PrevWM.VerifySignature(wallet.ClientKey) + err = lpm.PrevWM.VerifySignature(walletForVerify.ClientKey) if err != nil { return nil, fmt.Errorf("signature verification failed for latest writemarker: %s", err.Error()) } diff --git a/zboxcore/sdk/writemarker_mutex.go b/zboxcore/sdk/writemarker_mutex.go index b0458f94c..36e1009f5 100644 --- a/zboxcore/sdk/writemarker_mutex.go +++ b/zboxcore/sdk/writemarker_mutex.go @@ -36,10 +36,11 @@ type WriteMarkerMutex struct { allocationObj *Allocation lockedBlobbers map[string]chan struct{} leadBlobberIndex int + Pubkey string } // CreateWriteMarkerMutex create WriteMarkerMutex for allocation -func CreateWriteMarkerMutex(allocationObj *Allocation) (*WriteMarkerMutex, error) { +func CreateWriteMarkerMutex(allocationObj *Allocation, keys ...string) (*WriteMarkerMutex, error) { if allocationObj == nil { return nil, errors.Throw(constants.ErrInvalidParameter, "allocationObj") } @@ -57,6 +58,7 @@ func CreateWriteMarkerMutex(allocationObj *Allocation) (*WriteMarkerMutex, error allocationObj: allocationObj, lockedBlobbers: lockedBlobbers, leadBlobberIndex: 0, + Pubkey: func() string { if len(keys)>0 { return keys[0] } ; return "" }(), }, nil } @@ -99,8 +101,12 @@ func (wmMu *WriteMarkerMutex) UnlockBlobber( }() var req *http.Request + key := wmMu.allocationObj.Owner + if wmMu.Pubkey != "" { + key = wmMu.Pubkey + } req, err = zboxutil.NewWriteMarkerUnLockRequest( - b.Baseurl, wmMu.allocationObj.ID, wmMu.allocationObj.Tx, wmMu.allocationObj.sig, connID, "", wmMu.allocationObj.Owner) + b.Baseurl, wmMu.allocationObj.ID, wmMu.allocationObj.Tx, wmMu.allocationObj.sig, connID, "", key) if err != nil { return } @@ -280,8 +286,12 @@ func (wmMu *WriteMarkerMutex) lockBlobber( }() var req *http.Request + key := wmMu.allocationObj.Owner + if wmMu.Pubkey != "" { + key = wmMu.Pubkey + } req, err = zboxutil.NewWriteMarkerLockRequest( - b.Baseurl, wmMu.allocationObj.ID, wmMu.allocationObj.Tx, wmMu.allocationObj.sig, connID, wmMu.allocationObj.Owner) + b.Baseurl, wmMu.allocationObj.ID, wmMu.allocationObj.Tx, wmMu.allocationObj.sig, connID, key) if err != nil { return } diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index 796c95c0f..f6cd1311d 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -198,18 +198,19 @@ func NewHTTPRequest(method string, url string, data []byte) (*http.Request, cont return req, ctx, cncl, err } -func setClientInfo(req *http.Request, keys ...string) { +func setClientInfo(req *http.Request, keys ...string) error { if len(keys) > 0 && keys[0] != "" { wallet := client.GetWalletByKey(keys[0]) if wallet == nil { - panic("wallet not found : " + keys[0]) + return errors.New("multi-wallet-settings err: ", "wallet not found : "+keys[0]) } req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) - return + return nil } req.Header.Set("X-App-Client-ID", client.Id()) req.Header.Set("X-App-Client-Key", client.PublicKey()) + return nil } func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, keys ...string) error { @@ -221,7 +222,7 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, k } wallet := client.GetWalletByKey(key) if wallet == nil { - return errors.New("wallet not found", key) + return errors.New("multi-wallet-settings err: ", "wallet not found : "+key) } fmt.Printf("setClientInfoWithSign: wallet details: %+v\n", *wallet) req.Header.Set("X-App-Client-ID", wallet.ClientID) @@ -267,7 +268,7 @@ func NewCommitRequest(baseUrl, allocationID string, allocationTx string, body io return req, nil } -func NewReferencePathRequest(baseUrl, allocationID string, allocationTx string, sig string, paths []string, clients ...string) (*http.Request, error) { +func NewReferencePathRequest(baseUrl, allocationID string, allocationTx string, sig string, paths []string, keys ...string) (*http.Request, error) { nurl, err := joinUrl(baseUrl, REFERENCE_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -287,7 +288,7 @@ func NewReferencePathRequest(baseUrl, allocationID string, allocationTx string, return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } @@ -599,7 +600,7 @@ func NewUploadRequestWithMethod(baseURL, allocationID, allocationTx, sig string, } func NewWriteMarkerLockRequest( - baseURL, allocationID, allocationTx, sig, connID string, clients ...string) (*http.Request, error) { + baseURL, allocationID, allocationTx, sig, connID string, keys ...string) (*http.Request, error) { u, err := joinUrl(baseURL, WM_LOCK_ENDPOINT, allocationTx) if err != nil { @@ -615,7 +616,7 @@ func NewWriteMarkerLockRequest( return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseURL, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseURL, keys...); err != nil { return nil, err } @@ -625,7 +626,7 @@ func NewWriteMarkerLockRequest( } func NewWriteMarkerUnLockRequest( - baseURL, allocationID, allocationTx, sig, connID, requestTime string, clients ...string) (*http.Request, error) { + baseURL, allocationID, allocationTx, sig, connID, requestTime string, keys ...string) (*http.Request, error) { u, err := joinUrl(baseURL, WM_LOCK_ENDPOINT, allocationTx, connID) if err != nil { @@ -637,7 +638,7 @@ func NewWriteMarkerUnLockRequest( return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseURL, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseURL, keys...); err != nil { return nil, err } @@ -998,7 +999,7 @@ func NewWritemarkerRequest(baseUrl, allocationID, allocationTx, sig string, keys return req, nil } -func NewRollbackRequest(baseUrl, allocationID string, allocationTx string, body io.Reader, clients ...string) (*http.Request, error) { +func NewRollbackRequest(baseUrl, allocationID string, allocationTx string, body io.Reader, keys ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, ROLLBACK_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -1008,7 +1009,10 @@ func NewRollbackRequest(baseUrl, allocationID string, allocationTx string, body if err != nil { return nil, err } - setClientInfo(req) + err = setClientInfo(req, keys...) + if err != nil { + return nil, err + } req.Header.Set(ALLOCATION_ID_HEADER, allocationID) From be361342f7fbd71b06da7296464a5240e0a4fb55 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sat, 8 Nov 2025 14:32:56 +0530 Subject: [PATCH 29/47] Download Dir test --- zboxcore/sdk/allocation.go | 48 ++++++++++++++++++++++++---------- zboxcore/sdk/downloadworker.go | 10 +++++++ zboxcore/sdk/filerefsworker.go | 22 +++++++++++++++- zboxcore/zboxutil/http.go | 4 +-- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 25b36634b..a90f1a865 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -3312,7 +3312,7 @@ repair: return alloc, hash, isRepairRequired, nil } -func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPath, authTicket string, sb StatusCallback) error { +func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPath, authTicket string, sb StatusCallback, pubkey ...string) error { if len(a.Blobbers) == 0 { return noBLOBBERS } @@ -3327,7 +3327,11 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat } defer sys.Files.RemoveAllDirectories() - oRefChan := a.ListObjects(ctx, remotePath, "", "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, WithAuthToken(authTicket)) + objOpts := []ObjectTreeRequestOption{WithAuthToken(authTicket)} + if len(pubkey) > 0 && pubkey[0] != "" { + objOpts = append(objOpts, WithObjectClientKey(pubkey[0])) + } + oRefChan := a.ListObjects(ctx, remotePath, "", "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, objOpts...) refSlice := make([]ORef, BatchSize) refIndex := 0 wg := &sync.WaitGroup{} @@ -3370,13 +3374,21 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat return err } if authTicket == "" { - _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == BatchSize-1, WithFileCallback(func() { - fh.Close() //nolint: errcheck - })) //nolint: errcheck + opts := []DownloadRequestOption{ + WithFileCallback(func() { fh.Close() }), + } + if len(pubkey) > 0 && pubkey[0] != "" { + opts = append(opts, WithPubKey(pubkey[0])) + } + _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == BatchSize-1, opts...) //nolint: errcheck } else { - _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == BatchSize-1, WithFileCallback(func() { - fh.Close() //nolint: errcheck - })) //nolint: errcheck + opts := []DownloadRequestOption{ + WithFileCallback(func() { fh.Close() }), + } + if len(pubkey) > 0 && pubkey[0] != "" { + opts = append(opts, WithPubKey(pubkey[0])) + } + _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == BatchSize-1, opts...) //nolint: errcheck } totalSize += int(ref.ActualFileSize) } @@ -3409,13 +3421,21 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat return err } if authTicket == "" { - _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == refIndex-1, WithFileCallback(func() { - fh.Close() //nolint: errcheck - })) //nolint: errcheck + opts := []DownloadRequestOption{ + WithFileCallback(func() { fh.Close() }), + } + if len(pubkey) > 0 && pubkey[0] != "" { + opts = append(opts, WithPubKey(pubkey[0])) + } + _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == refIndex-1, opts...) //nolint: errcheck } else { - _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == refIndex-1, WithFileCallback(func() { - fh.Close() //nolint: errcheck - })) //nolint: errcheck + opts := []DownloadRequestOption{ + WithFileCallback(func() { fh.Close() }), + } + if len(pubkey) > 0 && pubkey[0] != "" { + opts = append(opts, WithPubKey(pubkey[0])) + } + _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == refIndex-1, opts...) //nolint: errcheck } totalSize += int(ref.ActualFileSize) } diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index 8c5cb9a4b..7eae5c40b 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -67,6 +67,16 @@ func WithFileCallback(cb func()) DownloadRequestOption { } } +// WithPubKey sets the public key to be used for download request signing and +// header selection in multi-wallet scenarios. When set, read markers and +// fast download requests will use this pubkey to select the wallet used for +// signing and to populate client headers. +func WithPubKey(pubkey string) DownloadRequestOption { + return func(dr *DownloadRequest) { + dr.Pubkey = pubkey + } +} + type DownloadRequest struct { ClientId string allocationID string diff --git a/zboxcore/sdk/filerefsworker.go b/zboxcore/sdk/filerefsworker.go index c2e5a1e6d..c02cfa5ea 100644 --- a/zboxcore/sdk/filerefsworker.go +++ b/zboxcore/sdk/filerefsworker.go @@ -33,6 +33,7 @@ const INVALID_PATH = "invalid_path" type ObjectTreeRequest struct { ClientId string + PubKey string allocationID string allocationTx string sig string @@ -94,6 +95,17 @@ func WithAuthToken(token string) ObjectTreeRequestOption { } } +// WithObjectClientKey sets the client pubkey (or client id) to be used for signing +// the object tree / refs HTTP request. When set, the request helper will use this +// key to resolve the wallet and sign the request headers. Note: ClientId should +// remain the allocation owner; this option sets the signing pubkey to use for +// the HTTP request when performing refs/list operations. +func WithObjectClientKey(key string) ObjectTreeRequestOption { + return func(o *ObjectTreeRequest) { + o.PubKey = key + } +} + // Paginated tree should not be collected as this will stall the client // It should rather be handled by application that uses gosdk func (o *ObjectTreeRequest) GetRefs() (*ObjectTreeResult, error) { @@ -233,6 +245,14 @@ func (o *ObjectTreeRequest) getFileRefs(bUrl string, respChan chan *oTreeRespons oResult := ObjectTreeResult{} for i := 0; i < 3; i++ { + // Determine the client key to use for signing the refs request. Prefer + // the explicit PubKey when provided by the caller; otherwise fall back + // to ClientId (historical behavior). + clientKey := o.ClientId + if o.PubKey != "" { + clientKey = o.PubKey + } + oReq, err := zboxutil.NewRefsRequest( bUrl, o.allocationID, @@ -248,7 +268,7 @@ func (o *ObjectTreeRequest) getFileRefs(bUrl string, respChan chan *oTreeRespons o.refType, o.level, o.pageLimit, - o.ClientId, + clientKey, ) if err != nil { oTR.err = err diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index f6cd1311d..d7573925f 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -374,7 +374,7 @@ func NewObjectTreeRequest(baseUrl, allocationID string, allocationTx string, sig return req, nil } -func NewRefsRequest(baseUrl, allocationID, sig, allocationTx, path, pathHash, authToken, offsetPath, updatedDate, offsetDate, fileType, refType string, level, pageLimit int, clients ...string) (*http.Request, error) { +func NewRefsRequest(baseUrl, allocationID, sig, allocationTx, path, pathHash, authToken, offsetPath, updatedDate, offsetDate, fileType, refType string, level, pageLimit int, keys ...string) (*http.Request, error) { nUrl, err := joinUrl(baseUrl, REFS_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -398,7 +398,7 @@ func NewRefsRequest(baseUrl, allocationID, sig, allocationTx, path, pathHash, au req.Header.Set(ALLOCATION_ID_HEADER, allocationID) - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } From 3b81f538a13c4f6377ba69709b562f53d8db3c7d Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Wed, 12 Nov 2025 12:26:51 +0530 Subject: [PATCH 30/47] file operations and transaction signing --- core/client/set.go | 20 +++ core/transaction/entity.go | 48 +++++-- core/transaction/transaction.go | 37 +++--- zboxcore/marker/writemarker.go | 6 +- zboxcore/sdk/allocation.go | 176 ++++++++++++++++--------- zboxcore/sdk/blobber_operations.go | 64 ++++++--- zboxcore/sdk/chunked_upload_blobber.go | 16 ++- zboxcore/sdk/commitworker.go | 85 ++++++------ zboxcore/sdk/common.go | 51 ++++--- zboxcore/sdk/copyworker.go | 165 ++++++++++++++--------- zboxcore/sdk/deleteworker.go | 122 +++++++++-------- zboxcore/sdk/dirworker.go | 31 ++--- zboxcore/sdk/downloadworker.go | 33 ++--- zboxcore/sdk/filemetaworker.go | 10 +- zboxcore/sdk/filerefsworker.go | 12 +- zboxcore/sdk/listworker.go | 44 ++++--- zboxcore/sdk/moveworker.go | 163 +++++++++++++---------- zboxcore/sdk/multi_operation_worker.go | 58 ++++---- zboxcore/sdk/renameworker.go | 162 ++++++++++++----------- zboxcore/sdk/repairworker.go | 7 +- zboxcore/sdk/rollback.go | 23 +++- zboxcore/sdk/sdk.go | 6 +- zboxcore/sdk/upload_worker.go | 2 +- zboxcore/zboxutil/http.go | 14 +- 24 files changed, 816 insertions(+), 539 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 0f5ed74a4..87cef30c1 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -523,6 +523,26 @@ func Id(keys ...string) string { return client.wallet.ClientID } +// IsWalletSplit returns whether the wallet identified by keys[0] (pubkey or id) +// is a split-key wallet. If no key is provided the default SDK wallet's split +// flag is returned. +func IsWalletSplit(keys ...string) bool { + client.mu.RLock() + defer client.mu.RUnlock() + + if len(keys) > 0 && keys[0] != "" && client.wallets != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { + return w.IsSplit + } + } + + if client.wallet != nil { + return client.wallet.IsSplit + } + + return false +} + // VerifySignature ... func VerifySignature(signature string, msg string) (bool, error) { ss := zcncrypto.NewSignatureScheme(client.signatureScheme) diff --git a/core/transaction/entity.go b/core/transaction/entity.go index b79b5b965..944e59b7c 100644 --- a/core/transaction/entity.go +++ b/core/transaction/entity.go @@ -211,6 +211,14 @@ func (t *Transaction) getAuthorize() (string, error) { return "", errors.New("not_initialized", "no authorize func is set, define it in native code and set in sys") } + if t.MultiWalletSupportKey != "" { + authorize, err := sys.Authorize(string(jsonByte), t.MultiWalletSupportKey) + if err != nil { + return "", err + } + return authorize, nil + } + authorize, err := sys.Authorize(string(jsonByte)) if err != nil { return "", err @@ -530,21 +538,24 @@ func SmartContractTxnValue(scAddress string, sn SmartContractTxnData, value uint } func SmartContractTxnValueFeeWithRetry(scAddress string, sn SmartContractTxnData, - value, fee uint64, verifyTxn bool, clients ...string) (hash, out string, nonce int64, t *Transaction, err error) { - hash, out, nonce, t, err = SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, clients...) + value, fee uint64, verifyTxn bool, keys ...string) (hash, out string, nonce int64, t *Transaction, err error) { + hash, out, nonce, t, err = SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, keys...) if err != nil && (strings.Contains(err.Error(), "invalid transaction nonce") || strings.Contains(err.Error(), "invalid future transaction")) { - return SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, clients...) + return SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, keys...) } return } func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, - value, fee uint64, verifyTxn bool, clients ...string) (hash, out string, nonce int64, t *Transaction, err error) { + value, fee uint64, verifyTxn bool, keys ...string) (hash, out string, nonce int64, t *Transaction, err error) { + // Determine client identifier/public key to use for signing. If an explicit key is + // provided in keys varargs, prefer it; otherwise default to SDK client id. clientId := client.Id() - if len(clients) > 0 && clients[0] != "" { - clientId = clients[0] + if len(keys) > 0 && keys[0] != "" { + // keys[0] may be a client public key or client id. Let client.Id resolve it. + clientId = client.Id(keys[0]) } var requestBytes []byte @@ -572,8 +583,8 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, txn.TransactionType = TxnTypeSmartContract txn.ClientID = clientId - if len(clients) > 1 { - txn.ToClientID = clients[1] + if len(keys) > 1 { + txn.ToClientID = keys[1] txn.TransactionType = TxnTypeSend } @@ -593,16 +604,25 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, txn.TransactionNonce = client.Cache.GetNextNonce(txn.ClientID) } - err = txn.ComputeHashAndSign(client.SignFn) - if err != nil { - return - } - - if client.GetClient().IsSplit { + if client.IsWalletSplit(keys...) { + if len(keys) > 0 && keys[0] != "" { + txn.MultiWalletSupportKey = keys[0] + } + txn.ComputeHashData() txn.Signature, err = txn.getAuthorize() if err != nil { return } + } else { + // Use a sign wrapper that forwards the provided keys to client.Sign so the + // signing happens under the intended wallet/public key when keys are provided. + err = txn.ComputeHashAndSign(func(hash string) (string, error) { + // forward original keys varargs so client.Sign can pick the correct wallet + return client.Sign(hash, keys...) + }) + if err != nil { + return + } } ok, err := txn.VerifySigWith(txn.PublicKey, sys.VerifyWith) diff --git a/core/transaction/transaction.go b/core/transaction/transaction.go index 985e2f37c..cf6b74743 100644 --- a/core/transaction/transaction.go +++ b/core/transaction/transaction.go @@ -2,20 +2,25 @@ package transaction // Transaction entity that encapsulates the transaction related data and meta data type Transaction struct { - Hash string `json:"hash,omitempty"` - Version string `json:"version,omitempty"` - ClientID string `json:"client_id,omitempty"` - PublicKey string `json:"public_key,omitempty"` - ToClientID string `json:"to_client_id,omitempty"` - ChainID string `json:"chain_id,omitempty"` - TransactionData string `json:"transaction_data"` - Value uint64 `json:"transaction_value"` - Signature string `json:"signature,omitempty"` - CreationDate int64 `json:"creation_date,omitempty"` - TransactionType int `json:"transaction_type"` - TransactionOutput string `json:"transaction_output,omitempty"` - TransactionFee uint64 `json:"transaction_fee"` - TransactionNonce int64 `json:"transaction_nonce"` - OutputHash string `json:"txn_output_hash"` - Status int `json:"transaction_status"` + Hash string `json:"hash,omitempty"` + Version string `json:"version,omitempty"` + ClientID string `json:"client_id,omitempty"` + PublicKey string `json:"public_key,omitempty"` + // MultiWalletSupportKey is set when the transaction needs external + // authorization (split-key wallets). It is embedded in the marshaled + // transaction so the external authorizer (sys.Authorize) can know which + // public key the signature should be associated with. + MultiWalletSupportKey string `json:"authorizer_public_key,omitempty"` + ToClientID string `json:"to_client_id,omitempty"` + ChainID string `json:"chain_id,omitempty"` + TransactionData string `json:"transaction_data"` + Value uint64 `json:"transaction_value"` + Signature string `json:"signature,omitempty"` + CreationDate int64 `json:"creation_date,omitempty"` + TransactionType int `json:"transaction_type"` + TransactionOutput string `json:"transaction_output,omitempty"` + TransactionFee uint64 `json:"transaction_fee"` + TransactionNonce int64 `json:"transaction_nonce"` + OutputHash string `json:"txn_output_hash"` + Status int `json:"transaction_status"` } diff --git a/zboxcore/marker/writemarker.go b/zboxcore/marker/writemarker.go index 0d96562d5..b50da4462 100644 --- a/zboxcore/marker/writemarker.go +++ b/zboxcore/marker/writemarker.go @@ -21,7 +21,7 @@ type WriteMarker struct { BlobberID string `json:"blobber_id"` Timestamp int64 `json:"timestamp"` ClientID string `json:"client_id"` - Pubkey string `json:"pub_key"` + MultiWalletSupportKey string `json:"pub_key"` Signature string `json:"signature"` } @@ -50,9 +50,9 @@ func (wm *WriteMarker) GetHash() string { func (wm *WriteMarker) Sign() error { var err error // If Pubkey is set, use that wallet for signing and set ClientID accordingly. - if wm.Pubkey != "" { + if wm.MultiWalletSupportKey != "" { // Use the provided pubkey to sign, but do not overwrite ClientID here. - wm.Signature, err = client.Sign(wm.GetHash(), wm.Pubkey) + wm.Signature, err = client.Sign(wm.GetHash(), wm.MultiWalletSupportKey) return err } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index a90f1a865..9c1b071c7 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -299,6 +299,8 @@ type Allocation struct { // Owner ecdsa public key OwnerSigningPublicKey string `json:"owner_signing_public_key"` + // MultiWalletSupportKey holds an allocation-level default signing pubkey used + MultiWalletSupportKey string `json:"multi_wallet_support_key,omitempty"` // FileOptions to define file restrictions on an allocation for third-parties // default 00000000 for all crud operations suggesting only owner has the below listed abilities. @@ -413,13 +415,20 @@ func (a *Allocation) GetStats() *AllocationStats { } // GetBlobberStats returns the statistics of the blobbers in the allocation. -func (a *Allocation) GetBlobberStats() map[string]*BlobberAllocationStats { +func (a *Allocation) GetBlobberStats(keys ...string) map[string]*BlobberAllocationStats { + // Allow caller to provide an explicit client key (e.g., signing pubkey) to use + // when requesting allocation info from blobbers. If provided, use that as the + // client id passed to blobbers; otherwise default to the allocation owner id. + clientKey := a.Owner + if len(keys) > 0 && keys[0] != "" { + clientKey = keys[0] + } numList := len(a.Blobbers) wg := &sync.WaitGroup{} wg.Add(numList) rspCh := make(chan *BlobberAllocationStats, numList) for _, blobber := range a.Blobbers { - go getAllocationDataFromBlobber(blobber, a.ID, a.Tx, rspCh, wg, a.Owner) + go getAllocationDataFromBlobber(blobber, a.ID, a.Tx, rspCh, wg, clientKey) } wg.Wait() result := make(map[string]*BlobberAllocationStats, len(a.Blobbers)) @@ -462,7 +471,7 @@ func (a *Allocation) InitAllocation() { a.startWorker(a.ctx) InitCommitWorker(a.Blobbers) InitBlockDownloader(a.Blobbers, downloadWorkerCount) - if a.StorageVersion == StorageV2 && a.OwnerPublicKey == client.PublicKey() { + if a.StorageVersion == StorageV2 && a.OwnerPublicKey == client.PublicKey(a.Owner) { a.CheckAllocStatus() //nolint:errcheck } a.initialized = true @@ -574,7 +583,7 @@ func (a *Allocation) UploadFile(workdir, localpath string, remotepath string, // - statusCallback: a callback function to get the status of the repair. // - mask: the mask of the repair descriping the blobbers to repair. // - ref: the file reference, a representation of the file in the database. -func (a *Allocation) RepairFile(file sys.File, remotepath string, statusCallback StatusCallback, mask zboxutil.Uint128, ref *fileref.FileRef) *OperationRequest { +func (a *Allocation) RepairFile(file sys.File, remotepath string, statusCallback StatusCallback, mask zboxutil.Uint128, ref *fileref.FileRef, uploadOpts ...ChunkedUploadOption) *OperationRequest { idr, _ := homedir.Dir() if Workdir != "" { idr = Workdir @@ -605,6 +614,11 @@ func (a *Allocation) RepairFile(file sys.File, remotepath string, statusCallback WithChunkNumber(RepairBlocks), } } + // append any additional upload options provided by caller + if len(uploadOpts) > 0 { + opts = append(opts, uploadOpts...) + } + op := &OperationRequest{ OperationType: constants.FileOperationInsert, IsRepair: true, @@ -1071,6 +1085,7 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul consensusThresh: a.consensusThreshold, fullconsensus: a.fullconsensus, } + mo.MultiWalletSupportKey = a.MultiWalletSupportKey for _, opt := range opts { opt(&mo) } @@ -1139,42 +1154,29 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul switch op.OperationType { case constants.FileOperationRename: - var pubkey string - if mo.Pubkey != "" { - pubkey = mo.Pubkey - } else { - pubkey = mo.allocationObj.Owner - } - operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, pubkey) + operation = NewRenameOperation(op.RemotePath, op.DestName, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.allocationObj.Owner, mo.MultiWalletSupportKey) case constants.FileOperationCopy: - var pubkey string - if mo.Pubkey != "" { - pubkey = mo.Pubkey - } else { - pubkey = mo.allocationObj.Owner - } - operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly, pubkey) + operation = NewCopyOperation(mo.ctx, op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, op.CopyDirOnly, mo.allocationObj.Owner, mo.MultiWalletSupportKey) case constants.FileOperationMove: - var pubkey string - if mo.Pubkey != "" { - pubkey = mo.Pubkey - } else { - pubkey = mo.allocationObj.Owner - } - operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, pubkey) + operation = NewMoveOperation(op.RemotePath, op.DestPath, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.allocationObj.Owner, mo.MultiWalletSupportKey) case constants.FileOperationInsert: cancelLock.Lock() CancelOpCtx[op.FileMeta.RemotePath] = mo.ctxCncl cancelLock.Unlock() - operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) + // Ensure upload uses operation-level signing key when provided. + uploadOpts := op.Opts + if mo.MultiWalletSupportKey != "" { + uploadOpts = append(uploadOpts, WithWallet(mo.MultiWalletSupportKey)) + } + operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, false, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, uploadOpts...) case constants.FileOperationDelete: var key string - if mo.Pubkey != "" { - key = mo.Pubkey + if mo.MultiWalletSupportKey != "" { + key = mo.MultiWalletSupportKey } else { key = mo.allocationObj.Owner } @@ -1189,10 +1191,14 @@ func (a *Allocation) DoMultiOperation(operations []OperationRequest, opts ...Mul cancelLock.Lock() CancelOpCtx[op.FileMeta.RemotePath] = mo.ctxCncl cancelLock.Unlock() - operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, true, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, op.Opts...) + updOpts := op.Opts + if mo.MultiWalletSupportKey != "" { + updOpts = append(updOpts, WithWallet(mo.MultiWalletSupportKey)) + } + operation, newConnectionID, err = NewUploadOperation(mo.ctx, op.Workdir, mo.allocationObj, mo.connectionID, op.FileMeta, op.FileReader, true, op.IsWebstreaming, op.IsRepair, op.DownloadFile, op.StreamUpload, updOpts...) case constants.FileOperationCreateDir: - operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.Pubkey) + operation = NewDirOperation(op.RemotePath, op.FileMeta.CustomMeta, mo.operationMask, mo.maskMU, mo.consensusThresh, mo.fullconsensus, mo.ctx, mo.MultiWalletSupportKey) default: return errors.New("invalid_operation", "Operation is not valid") @@ -1385,16 +1391,18 @@ func (a *Allocation) DownloadFileByBlock( // - verifyDownload: a flag to verify the download. If true, the download should be verified against the client keys. // - status: the status callback function. Will be used to gather the status of the download operation. // - isFinal: a flag to indicate if the download is the final download, meaning no more downloads are expected. It triggers the finalization of the download operation. -func (a *Allocation) DownloadThumbnail(localPath string, remotePath string, verifyDownload bool, status StatusCallback, isFinal bool) error { +func (a *Allocation) DownloadThumbnail(localPath string, remotePath string, verifyDownload bool, status StatusCallback, isFinal bool, downloadReqOpts ...DownloadRequestOption) error { f, localFilePath, toKeep, err := a.prepareAndOpenLocalFile(localPath, remotePath) if err != nil { return err } + // append the file callback into the provided options, then pass all options through + downloadReqOpts = append(downloadReqOpts, WithFileCallback(func() { + f.Close() //nolint: errcheck + })) err = a.addAndGenerateDownloadRequest(f, remotePath, DOWNLOAD_CONTENT_THUMB, 1, 0, - numBlockDownloads, verifyDownload, status, isFinal, localFilePath, WithFileCallback(func() { - f.Close() //nolint: errcheck - })) + numBlockDownloads, verifyDownload, status, isFinal, localFilePath, downloadReqOpts...) if err != nil { if !toKeep { os.Remove(localFilePath) //nolint: errcheck @@ -1429,11 +1437,27 @@ func (a *Allocation) generateDownloadRequest( downloadReq.allocOwnerPubKey = a.OwnerPublicKey downloadReq.allocOwnerSigningPubKey = a.OwnerSigningPublicKey if len(a.privateSigningKey) == 0 { - sk, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) - if err != nil { - return nil, err + // If allocation has a MultiWalletSupportKey configured, prefer the + // corresponding wallet for generating the owner signing key. This + // provides allocation-level default signing behavior for multi-wallet + // setups. Otherwise fallback to the client/owner key. + if a.MultiWalletSupportKey != "" { + if w := client.GetWalletByKey(a.MultiWalletSupportKey); w != nil && len(w.Keys) > 0 { + sk, err := GenerateOwnerSigningKey(w.ClientKey, w.ClientID, a.MultiWalletSupportKey) + if err != nil { + return nil, err + } + downloadReq.allocOwnerSigningPrivateKey = sk + } else { + return nil, errors.New("multi-wallet-settings err: ", "wallet not found : "+a.MultiWalletSupportKey) + } + } else { + sk, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) + if err != nil { + return nil, err + } + downloadReq.allocOwnerSigningPrivateKey = sk } - downloadReq.allocOwnerSigningPrivateKey = sk } else { downloadReq.allocOwnerSigningPrivateKey = a.privateSigningKey } @@ -1470,6 +1494,10 @@ func (a *Allocation) generateDownloadRequest( } downloadReq.isEnterprise = a.IsEnterprise + if a.MultiWalletSupportKey != "" { + downloadReq.MultiWalletSupportKey = a.MultiWalletSupportKey + } + return downloadReq, nil } @@ -1682,6 +1710,9 @@ func (a *Allocation) ListDirFromAuthTicket(authTicket string, lookupHash string, listReq.ctx = a.ctx listReq.remotefilepathhash = lookupHash listReq.authToken = at + if a.MultiWalletSupportKey != "" { + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey + } for _, opt := range opts { opt(listReq) } @@ -1697,6 +1728,15 @@ func (a *Allocation) ListDirFromAuthTicket(authTicket string, lookupHash string, return nil, errors.New("list_request_failed", "Failed to get list response from the blobbers") } +// WithListRequestPubKey sets the public key to be used for list request signing and +// header selection in multi-wallet scenarios. When set, list requests will use +// this pubkey to select the wallet used for signing and to populate client headers. +func WithListRequestPubKey(pubkey string) ListRequestOptions { + return func(lr *ListRequest) { + lr.MultiWalletSupportKey = pubkey + } +} + // ListDir lists the allocation directory. // - path: the path of the directory to list. // - opts: the options of the list request as operation functions that customize the list request. @@ -1722,6 +1762,9 @@ func (a *Allocation) ListDir(path string, opts ...ListRequestOptions) (*ListResu listReq.consensusThresh = a.DataShards listReq.ctx = a.ctx listReq.remotefilepath = path + if a.MultiWalletSupportKey != "" { + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey + } for _, opt := range opts { opt(listReq) } @@ -1759,6 +1802,7 @@ func (a *Allocation) getRefs(path, pathHash, authToken, offsetPath, updatedDate, refType: refType, ctx: a.ctx, reqMask: zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1), + MultiWalletSupportKey: a.MultiWalletSupportKey, } oTreeReq.fullconsensus = a.fullconsensus oTreeReq.consensusThresh = a.DataShards @@ -2872,12 +2916,32 @@ func (a *Allocation) downloadFromAuthTicket(fileHandler sys.File, authTicket str downloadReq.allocOwnerID = a.Owner downloadReq.allocOwnerPubKey = a.OwnerPublicKey downloadReq.allocOwnerSigningPubKey = a.OwnerSigningPublicKey - //for auth ticket set your own signing key - sk, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) - if err != nil { - return err + if a.MultiWalletSupportKey != "" { + if w := client.GetWalletByKey(a.MultiWalletSupportKey); w != nil { + if len(w.Keys) > 0 { + sk, err := GenerateOwnerSigningKey(w.ClientKey, w.ClientID, a.MultiWalletSupportKey) + if err != nil { + return err + } + downloadReq.allocOwnerSigningPrivateKey = sk + } else { + return errors.New("multi-wallet-settings err: ", "wallet not found for signing public key "+downloadReq.MultiWalletSupportKey) + } + } else { + // wallet not found for pubkey; fallback to current client wallet + sk, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) + if err != nil { + return err + } + downloadReq.allocOwnerSigningPrivateKey = sk + } + } else { + sk, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) + if err != nil { + return err + } + downloadReq.allocOwnerSigningPrivateKey = sk } - downloadReq.allocOwnerSigningPrivateKey = sk downloadReq.ctx, downloadReq.ctxCncl = context.WithCancel(a.ctx) downloadReq.fileHandler = fileHandler downloadReq.localFilePath = localFilePath @@ -3312,7 +3376,7 @@ repair: return alloc, hash, isRepairRequired, nil } -func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPath, authTicket string, sb StatusCallback, pubkey ...string) error { +func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPath, authTicket string, sb StatusCallback) error { if len(a.Blobbers) == 0 { return noBLOBBERS } @@ -3328,9 +3392,6 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat defer sys.Files.RemoveAllDirectories() objOpts := []ObjectTreeRequestOption{WithAuthToken(authTicket)} - if len(pubkey) > 0 && pubkey[0] != "" { - objOpts = append(objOpts, WithObjectClientKey(pubkey[0])) - } oRefChan := a.ListObjects(ctx, remotePath, "", "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, objOpts...) refSlice := make([]ORef, BatchSize) refIndex := 0 @@ -3377,17 +3438,13 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat opts := []DownloadRequestOption{ WithFileCallback(func() { fh.Close() }), } - if len(pubkey) > 0 && pubkey[0] != "" { - opts = append(opts, WithPubKey(pubkey[0])) - } + _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == BatchSize-1, opts...) //nolint: errcheck } else { opts := []DownloadRequestOption{ WithFileCallback(func() { fh.Close() }), } - if len(pubkey) > 0 && pubkey[0] != "" { - opts = append(opts, WithPubKey(pubkey[0])) - } + _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == BatchSize-1, opts...) //nolint: errcheck } totalSize += int(ref.ActualFileSize) @@ -3424,17 +3481,13 @@ func (a *Allocation) DownloadDirectory(ctx context.Context, remotePath, localPat opts := []DownloadRequestOption{ WithFileCallback(func() { fh.Close() }), } - if len(pubkey) > 0 && pubkey[0] != "" { - opts = append(opts, WithPubKey(pubkey[0])) - } + _ = a.DownloadFileToFileHandler(fh, ref.Path, false, downloadStatusBar, ind == refIndex-1, opts...) //nolint: errcheck } else { opts := []DownloadRequestOption{ WithFileCallback(func() { fh.Close() }), } - if len(pubkey) > 0 && pubkey[0] != "" { - opts = append(opts, WithPubKey(pubkey[0])) - } + _ = a.DownloadFileToFileHandlerFromAuthTicket(fh, authTicket, ref.LookupHash, ref.Path, false, downloadStatusBar, ind == refIndex-1, opts...) //nolint: errcheck } totalSize += int(ref.ActualFileSize) @@ -3499,7 +3552,10 @@ func (a *Allocation) DownloadObject(ctx context.Context, remotePath string, rang downloadStatusBar := &StatusBar{ wg: wg, } - err = a.DownloadByBlocksToFileHandler(pipeFile, remotePath, startBlock, endBlock, numBlockDownloads, false, downloadStatusBar, true) + // Prepare optional download request options (e.g., signing pubkey) + var dlOpts []DownloadRequestOption + + err = a.DownloadByBlocksToFileHandler(pipeFile, remotePath, startBlock, endBlock, numBlockDownloads, false, downloadStatusBar, true, dlOpts...) if err != nil { return nil, err } diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index ad6c5cdec..ebf82747e 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -35,6 +35,7 @@ func CreateAllocationForOwner( dataShards, parityShards int, size int64, readPrice, writePrice PriceRange, lock uint64, preferredBlobberIds, blobberAuthTickets []string, thirdPartyExtendable, IsEnterprise, force bool, fileOptionsParams *FileOptionsParameters, authRoundExpiry int64, + keys ...string, ) (hash string, nonce int64, txn *transaction.Transaction, err error) { if lock > math.MaxInt64 { @@ -79,7 +80,7 @@ func CreateAllocationForOwner( Name: transaction.NEW_ALLOCATION_REQUEST, InputArgs: allocationRequest, } - hash, _, nonce, txn, err = storageSmartContractTxnValue(sn, lock) + hash, _, nonce, txn, err = storageSmartContractTxnValue(sn, lock, keys...) return } @@ -88,12 +89,16 @@ func CreateAllocationForOwner( // - value is the value of the free allocation. // // returns the hash of the transaction, the nonce of the transaction and an error if any. -func CreateFreeAllocation(marker string, value uint64) (string, int64, error) { +func CreateFreeAllocation(marker string, value uint64, keys ...string) (string, int64, error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } + // allow overriding the signing/public key via keys varargs recipientPublicKey := client.PublicKey() + if len(keys) > 0 && keys[0] != "" { + recipientPublicKey = client.PublicKey(keys[0]) + } var input = map[string]interface{}{ "recipient_public_key": recipientPublicKey, @@ -111,7 +116,7 @@ func CreateFreeAllocation(marker string, value uint64) (string, int64, error) { Name: transaction.NEW_FREE_ALLOCATION, InputArgs: input, } - hash, _, n, _, err := storageSmartContractTxnValue(sn, value) + hash, _, n, _, err := storageSmartContractTxnValue(sn, value, keys...) return hash, n, err } @@ -134,10 +139,16 @@ func UpdateAllocation( allocationID string, lock uint64, addBlobberId, addBlobberAuthTicket, removeBlobberId, ownerID, ownerSigninPublicKey string, - setThirdPartyExtendable bool, fileOptionsParams *FileOptionsParameters, ticket string, + setThirdPartyExtendable bool, fileOptionsParams *FileOptionsParameters, ticket string, keys ...string, ) (hash string, nonce int64, err error) { + + // prefer explicit owner id derived from provided pubkey when available + var key string + if len(keys) > 0 && keys[0] != "" { + key = keys[0] + } if ownerID == "" { - ownerID = client.Id() + ownerID = client.Id(key) } if lock > math.MaxInt64 { @@ -155,7 +166,8 @@ func UpdateAllocation( updateAllocationRequest := make(map[string]interface{}) updateAllocationRequest["owner_id"] = ownerID - updateAllocationRequest["owner_public_key"] = "" + // set owner_public_key based on provided pubkey (if any) to ensure downstream signing/verification + updateAllocationRequest["owner_public_key"] = client.PublicKey(key) updateAllocationRequest["id"] = allocationID updateAllocationRequest["size"] = size updateAllocationRequest["extend"] = extend @@ -189,15 +201,20 @@ func UpdateAllocation( Name: transaction.STORAGESC_UPDATE_ALLOCATION, InputArgs: updateAllocationRequest, } - hash, _, nonce, _, err = storageSmartContractTxnValue(sn, lock) + // Use explicit pubkey/client identifier for signing if provided + if key != "" { + hash, _, nonce, _, err = storageSmartContractTxnValue(sn, lock, key) + } else { + hash, _, nonce, _, err = storageSmartContractTxnValue(sn, lock) + } return } -func GetUpdateAllocTicket(allocationID, userID, operationType string, roundExpiry int64) (string, error) { +func GetUpdateAllocTicket(allocationID, userID, operationType string, roundExpiry int64, keys ...string) (string, error) { payload := fmt.Sprintf("%s:%d:%s:%s", allocationID, roundExpiry, userID, operationType) - pubkey := client.PublicKey() - signature, err := client.Sign(hex.EncodeToString([]byte(payload)), pubkey) + // forward keys to client.Sign so multi-wallet or explicit-key signing is used when provided + signature, err := client.Sign(hex.EncodeToString([]byte(payload)), keys...) if err != nil { return "", err } @@ -213,7 +230,7 @@ func GetUpdateAllocTicket(allocationID, userID, operationType string, roundExpir // - providerID: provider ID // - value: value to lock // - fee: transaction fee -func StakePoolLock(providerType ProviderType, providerID string, value, fee uint64) (hash string, nonce int64, err error) { +func StakePoolLock(providerType ProviderType, providerID string, value, fee uint64, keys ...string) (hash string, nonce int64, err error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } @@ -250,7 +267,7 @@ func StakePoolLock(providerType ProviderType, providerID string, value, fee uint return "", 0, errors.Newf("stake_pool_lock", "unsupported provider type: %v", providerType) } - hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(scAddress, sn, value, fee, true) + hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(scAddress, sn, value, fee, true, keys...) return } @@ -263,7 +280,7 @@ func StakePoolLock(providerType ProviderType, providerID string, value, fee uint // - providerType: provider type // - providerID: provider ID // - fee: transaction fee -func StakePoolUnlock(providerType ProviderType, providerID, clientID string, fee uint64) (unstake int64, nonce int64, err error) { +func StakePoolUnlock(providerType ProviderType, providerID, clientID string, fee uint64, keys ...string) (unstake int64, nonce int64, err error) { if !client.IsSDKInitialized() { return 0, 0, sdkNotInitialized } @@ -302,7 +319,7 @@ func StakePoolUnlock(providerType ProviderType, providerID, clientID string, fee } var out string - if _, out, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(scAddress, sn, 0, fee, true); err != nil { + if _, out, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(scAddress, sn, 0, fee, true, keys...); err != nil { return // an error } @@ -318,7 +335,7 @@ func StakePoolUnlock(providerType ProviderType, providerID, clientID string, fee // - allocID: allocation ID // - tokens: number of tokens to lock // - fee: transaction fee -func WritePoolLock(allocID string, tokens, fee uint64) (hash string, nonce int64, err error) { +func WritePoolLock(allocID string, tokens, fee uint64, keys ...string) (hash string, nonce int64, err error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } @@ -335,14 +352,14 @@ func WritePoolLock(allocID string, tokens, fee uint64) (hash string, nonce int64 InputArgs: &req, } - hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, tokens, fee, true) + hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, tokens, fee, true, keys...) return } // WritePoolUnlock unlocks ALL tokens of a write pool. Needs to be cancelled first. // - allocID: allocation ID // - fee: transaction fee -func WritePoolUnlock(allocID string, fee uint64) (hash string, nonce int64, err error) { +func WritePoolUnlock(allocID string, fee uint64, keys ...string) (hash string, nonce int64, err error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } @@ -358,17 +375,22 @@ func WritePoolUnlock(allocID string, fee uint64) (hash string, nonce int64, err Name: transaction.STORAGESC_WRITE_POOL_UNLOCK, InputArgs: &req, } - hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, 0, fee, true) + hash, _, nonce, _, err = transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, 0, fee, true, keys...) return } -func GenerateOwnerSigningKey(ownerPublicKey, ownerID string) (ed25519.PrivateKey, error) { +func GenerateOwnerSigningKey(ownerPublicKey, ownerID string, signingPubKey ...string) (ed25519.PrivateKey, error) { if ownerPublicKey == "" { return nil, errors.New("owner_public_key_required", "owner public key is required") } hashData := fmt.Sprintf("%s:%s", ownerPublicKey, "owner_signing_public_key") - pubkey := client.PublicKey() - sig, err := client.Sign(encryption.Hash(hashData), pubkey) + // prefer explicit signing pubkey when provided (for split-wallet scenarios) + pubkeyToUse := client.PublicKey() + if len(signingPubKey) > 0 && signingPubKey[0] != "" { + pubkeyToUse = signingPubKey[0] + } + + sig, err := client.Sign(encryption.Hash(hashData), pubkeyToUse) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) return nil, err diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index b9920b9b1..5e3761b43 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -228,7 +228,7 @@ func (sb *ChunkedUploadBlobber) processCommit(ctx context.Context, su *ChunkedUp // match the allocation owner (the uploader identity). wm.ClientID = su.allocationObj.Owner if su.pubkey != "" { - wm.Pubkey = su.pubkey + wm.MultiWalletSupportKey = su.pubkey } err = wm.Sign() if err != nil { @@ -266,7 +266,12 @@ func (sb *ChunkedUploadBlobber) processCommit(ctx context.Context, su *ChunkedUp formWriter.Close() - req, err := zboxutil.NewCommitRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, body, 0, su.allocationObj.Owner) + // choose signing key: prefer per-operation pubkey if set, otherwise allocation owner + key := su.allocationObj.Owner + if su.pubkey != "" { + key = su.pubkey + } + req, err := zboxutil.NewCommitRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, body, 0, key) if err != nil { logger.Logger.Error("Error creating commit req: ", err) return err @@ -355,7 +360,12 @@ func (sb *ChunkedUploadBlobber) processWriteMarker( } var lR ReferencePathResult - req, err := zboxutil.NewReferencePathRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, su.allocationObj.sig, paths, su.allocationObj.Owner) + // choose signing key for reference request: prefer per-operation pubkey if set + refKey := su.allocationObj.Owner + if su.pubkey != "" { + refKey = su.pubkey + } + req, err := zboxutil.NewReferencePathRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, su.allocationObj.sig, paths, refKey) if err != nil || len(paths) == 0 { logger.Logger.Error("Creating ref path req", err) return nil, nil, 0, nil, err diff --git a/zboxcore/sdk/commitworker.go b/zboxcore/sdk/commitworker.go index 850ae835e..8ab0f531b 100644 --- a/zboxcore/sdk/commitworker.go +++ b/zboxcore/sdk/commitworker.go @@ -60,18 +60,18 @@ func SuccessCommitResult() *CommitResult { const MARKER_VERSION = "v2" type CommitRequest struct { - ClientId string - changes []allocationchange.AllocationChange - blobber *blockchain.StorageNode - allocationID string - allocationTx string - connectionID string - sig string - wg *sync.WaitGroup - result *CommitResult - timestamp int64 - blobberInd uint64 - pubkey string + ClientId string + changes []allocationchange.AllocationChange + blobber *blockchain.StorageNode + allocationID string + allocationTx string + connectionID string + sig string + wg *sync.WaitGroup + result *CommitResult + timestamp int64 + blobberInd uint64 + multiWalletSupportKey string } type CommitRequestInterface interface { @@ -80,18 +80,18 @@ type CommitRequestInterface interface { } type CommitRequestV2 struct { - changes []allocationchange.AllocationChangeV2 - allocationObj *Allocation - connectionID string - sig string - wg *sync.WaitGroup - result *CommitResult - timestamp int64 - consensusThresh int - commitMask zboxutil.Uint128 - changeIndex uint64 - isRepair bool - pubkey string + changes []allocationchange.AllocationChangeV2 + allocationObj *Allocation + connectionID string + sig string + wg *sync.WaitGroup + result *CommitResult + timestamp int64 + consensusThresh int + commitMask zboxutil.Uint128 + changeIndex uint64 + isRepair bool + multiWalletSupportKey string } var ( @@ -150,8 +150,8 @@ func (commitreq *CommitRequest) processCommit() { var req *http.Request var lR ReferencePathResult key := client.Id() - if commitreq.pubkey != "" { - key = commitreq.pubkey + if commitreq.multiWalletSupportKey != "" { + key = commitreq.multiWalletSupportKey } req, err := zboxutil.NewReferencePathRequest(commitreq.blobber.Baseurl, commitreq.allocationID, commitreq.allocationTx, commitreq.sig, paths, key) if err != nil { @@ -199,7 +199,18 @@ func (commitreq *CommitRequest) processCommit() { } hasher := sha256.New() if lR.LatestWM != nil { - err = lR.LatestWM.VerifySignature(client.PublicKey()) + // Prefer verification using the MultiWalletSupportKey from the write + // marker (if present). Otherwise fall back to the client's public key. + if lR.LatestWM.MultiWalletSupportKey != "" { + if w := client.GetWalletByKey(lR.LatestWM.MultiWalletSupportKey); w != nil { + err = lR.LatestWM.VerifySignature(w.ClientKey) + } else { + commitreq.result = ErrorCommitResult("multi-wallet-settings err: wallet not found for signing public key " + lR.LatestWM.MultiWalletSupportKey) + return + } + } else { + err = lR.LatestWM.VerifySignature(client.PublicKey()) + } if err != nil { e := errors.New("signature_verification_failed", err.Error()) commitreq.result = ErrorCommitResult(e.Error()) @@ -290,8 +301,8 @@ func (req *CommitRequest) commitBlobber( wm.BlobberID = req.blobber.ID wm.Timestamp = req.timestamp wm.ClientID = req.ClientId - if req.pubkey != "" { - wm.Pubkey = req.pubkey + if req.multiWalletSupportKey != "" { + wm.MultiWalletSupportKey = req.multiWalletSupportKey } err = wm.Sign() if err != nil { @@ -318,8 +329,8 @@ func (req *CommitRequest) commitBlobber( return } var httpreq *http.Request - if req.pubkey != "" { - httpreq, err = zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0, req.pubkey) + if req.multiWalletSupportKey != "" { + httpreq, err = zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0, req.multiWalletSupportKey) } else { httpreq, err = zboxutil.NewCommitRequest(req.blobber.Baseurl, req.allocationID, req.allocationTx, body, 0) } @@ -453,8 +464,8 @@ func (commitReq *CommitRequestV2) processCommit() { trie *wmpt.WeightedMerkleTrie err error ) - if commitReq.pubkey != "" { - trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu, commitReq.pubkey) + if commitReq.multiWalletSupportKey != "" { + trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu, commitReq.multiWalletSupportKey) } else { trie, err = getReferencePathV2(blobber, commitReq.allocationObj.ID, commitReq.allocationObj.Tx, commitReq.sig, paths, &success, mu) } @@ -602,8 +613,8 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh wm.AllocationID = req.allocationObj.ID wm.FileMetaRoot = fileMetaRoot wm.ClientID = req.allocationObj.Owner - if req.pubkey != "" { - wm.Pubkey = req.pubkey + if req.multiWalletSupportKey != "" { + wm.MultiWalletSupportKey = req.multiWalletSupportKey } err = wm.Sign() if err != nil { @@ -616,8 +627,8 @@ func (req *CommitRequestV2) commitBlobber(rootHash []byte, rootWeight, prevWeigh return err } - if req.pubkey != "" { - err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion, req.pubkey) + if req.multiWalletSupportKey != "" { + err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion, req.multiWalletSupportKey) } else { err = submitWriteMarker(wmData, nil, blobber, req.connectionID, req.allocationObj.ID, req.allocationObj.Tx, req.allocationObj.StorageVersion) } diff --git a/zboxcore/sdk/common.go b/zboxcore/sdk/common.go index 3f9b698b6..9bf94f561 100644 --- a/zboxcore/sdk/common.go +++ b/zboxcore/sdk/common.go @@ -20,8 +20,8 @@ import ( "github.com/0chain/gosdk/zboxcore/zboxutil" ) -func getObjectTreeFromBlobber(ctx context.Context, allocationID, allocationTx, sig string, remoteFilePath string, blobber *blockchain.StorageNode, clientId ...string) (fileref.RefEntity, error) { - httpreq, err := zboxutil.NewObjectTreeRequest(blobber.Baseurl, allocationID, allocationTx, sig, remoteFilePath) +func getObjectTreeFromBlobber(ctx context.Context, allocationID, allocationTx, sig string, remoteFilePath string, blobber *blockchain.StorageNode, keys ...string) (fileref.RefEntity, error) { + httpreq, err := zboxutil.NewObjectTreeRequest(blobber.Baseurl, allocationID, allocationTx, sig, remoteFilePath, keys...) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating object tree request", err) return nil, err @@ -63,9 +63,9 @@ func getObjectTreeFromBlobber(ctx context.Context, allocationID, allocationTx, s return lR.GetRefFromObjectTree(allocationID) } -func getAllocationDataFromBlobber(blobber *blockchain.StorageNode, allocationId string, allocationTx string, respCh chan<- *BlobberAllocationStats, wg *sync.WaitGroup, clientId ...string) { +func getAllocationDataFromBlobber(blobber *blockchain.StorageNode, allocationId string, allocationTx string, respCh chan<- *BlobberAllocationStats, wg *sync.WaitGroup, keys ...string) { defer wg.Done() - httpreq, err := zboxutil.NewAllocationRequest(blobber.Baseurl, allocationId, allocationTx, clientId...) + httpreq, err := zboxutil.NewAllocationRequest(blobber.Baseurl, allocationId, allocationTx, keys...) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating allocation request", err) return @@ -123,14 +123,15 @@ func ValidateRemoteFileName(remotePath string) error { } type subDirRequest struct { - opType string - subOpType string - remotefilepath string - destPath string - allocationObj *Allocation - ctx context.Context - consensusThresh int - mask zboxutil.Uint128 + opType string + subOpType string + remotefilepath string + destPath string + allocationObj *Allocation + ctx context.Context + consensusThresh int + mask zboxutil.Uint128 + MultiWalletSupportKey string } func (req *subDirRequest) processSubDirectories() error { @@ -140,7 +141,13 @@ func (req *subDirRequest) processSubDirectories() error { ) for { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, WithObjectContext(req.ctx), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true), WithObjectMask(req.mask)) + // Build options for GetRefs; include operation-level client key when provided so + // the underlying object tree / refs requests are signed with the correct wallet. + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true), WithObjectMask(req.mask)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, objOpts...) if err != nil { return err } @@ -171,7 +178,11 @@ func (req *subDirRequest) processSubDirectories() error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } @@ -188,7 +199,11 @@ func (req *subDirRequest) processSubDirectories() error { } for pathLevel > level { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, WithObjectContext(req.ctx), WithObjectMask(req.mask), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)) + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectMask(req.mask), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, objOpts...) if err != nil { return err } @@ -216,7 +231,11 @@ func (req *subDirRequest) processSubDirectories() error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } diff --git a/zboxcore/sdk/copyworker.go b/zboxcore/sdk/copyworker.go index 5e7d1bbd9..674c8eb5e 100644 --- a/zboxcore/sdk/copyworker.go +++ b/zboxcore/sdk/copyworker.go @@ -31,22 +31,23 @@ import ( ) type CopyRequest struct { - allocationObj *Allocation - allocationID string - allocationTx string - sig string - blobbers []*blockchain.StorageNode - remotefilepath string - destPath string - ctx context.Context - ctxCncl context.CancelFunc - copyMask zboxutil.Uint128 - maskMU *sync.Mutex - connectionID string - timestamp int64 - dirOnly bool - destLookupHash string - clientId string + allocationObj *Allocation + allocationID string + allocationTx string + sig string + blobbers []*blockchain.StorageNode + remotefilepath string + destPath string + ctx context.Context + ctxCncl context.CancelFunc + copyMask zboxutil.Uint128 + maskMU *sync.Mutex + connectionID string + timestamp int64 + dirOnly bool + destLookupHash string + clientId string + MultiWalletSupportKey string Consensus } @@ -55,16 +56,24 @@ var errNoChange = errors.New("no_change", "No change in the operation") const objAlreadyExists = "Object Already exists" func (req *CopyRequest) getObjectTreeFromBlobber(blobber *blockchain.StorageNode) (fileref.RefEntity, error) { - return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner) + key := req.clientId + if key == "" { + key = req.allocationObj.Owner + } + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey + } + return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, key) } func (req *CopyRequest) getFileMetaFromBlobber(pos int) (fileRef *fileref.FileRef, err error) { listReq := &ListRequest{ - allocationID: req.allocationID, - allocationTx: req.allocationTx, - blobbers: req.blobbers, - remotefilepath: req.remotefilepath, - ctx: req.ctx, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + blobbers: req.blobbers, + remotefilepath: req.remotefilepath, + ctx: req.ctx, + MultiWalletSupportKey: req.MultiWalletSupportKey, } respChan := make(chan *fileMetaResponse) go listReq.getFileMetaInfoFromBlobber(req.blobbers[pos], int(pos), respChan) @@ -131,11 +140,14 @@ func (req *CopyRequest) copyBlobberObject( cncl context.CancelFunc ) - clientId := req.clientId - if clientId == "" { - clientId = req.allocationObj.Owner + key := req.clientId + if key == "" { + key = req.allocationObj.Owner + } + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey } - httpreq, err = zboxutil.NewCopyRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) + httpreq, err = zboxutil.NewCopyRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, key) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -324,7 +336,7 @@ func (req *CopyRequest) ProcessCopy() error { req.Consensus.consensusThresh, req.Consensus.consensus)) } - writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj) + writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj, req.MultiWalletSupportKey) if err != nil { return fmt.Errorf("Copy failed: %s", err.Error()) } @@ -374,14 +386,15 @@ func (req *CopyRequest) ProcessCopy() error { newChange.Operation = constants.FileOperationCopy newChange.Size = 0 commitReq := &CommitRequest{ - ClientId: req.allocationObj.Owner, - allocationID: req.allocationID, - allocationTx: req.allocationTx, - sig: req.sig, - blobber: req.blobbers[pos], - connectionID: req.connectionID, - wg: wg, - timestamp: req.timestamp, + ClientId: req.allocationObj.Owner, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + sig: req.sig, + blobber: req.blobbers[pos], + connectionID: req.connectionID, + wg: wg, + timestamp: req.timestamp, + multiWalletSupportKey: req.MultiWalletSupportKey, } commitReq.changes = append(commitReq.changes, newChange) @@ -413,16 +426,17 @@ func (req *CopyRequest) ProcessCopy() error { } type CopyOperation struct { - remotefilepath string - destPath string - destLookupHash string - dirOnly bool - ctx context.Context - ctxCncl context.CancelFunc - copyMask zboxutil.Uint128 - maskMU *sync.Mutex - objectTreeRefs []fileref.RefEntity - clientId string + remotefilepath string + destPath string + destLookupHash string + dirOnly bool + ctx context.Context + ctxCncl context.CancelFunc + copyMask zboxutil.Uint128 + maskMU *sync.Mutex + objectTreeRefs []fileref.RefEntity + clientId string + MultiWalletSupportKey string Consensus } @@ -430,21 +444,22 @@ type CopyOperation struct { func (co *CopyOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { // make copyRequest object cR := &CopyRequest{ - allocationObj: allocObj, - allocationID: allocObj.ID, - allocationTx: allocObj.Tx, - sig: allocObj.sig, - connectionID: connectionID, - blobbers: allocObj.Blobbers, - remotefilepath: co.remotefilepath, - destPath: co.destPath, - ctx: co.ctx, - ctxCncl: co.ctxCncl, - copyMask: co.copyMask, - maskMU: co.maskMU, - dirOnly: co.dirOnly, - Consensus: Consensus{RWMutex: &sync.RWMutex{}}, - clientId: co.clientId, + allocationObj: allocObj, + allocationID: allocObj.ID, + allocationTx: allocObj.Tx, + sig: allocObj.sig, + connectionID: connectionID, + blobbers: allocObj.Blobbers, + remotefilepath: co.remotefilepath, + destPath: co.destPath, + ctx: co.ctx, + ctxCncl: co.ctxCncl, + copyMask: co.copyMask, + maskMU: co.maskMU, + dirOnly: co.dirOnly, + Consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: co.clientId, + MultiWalletSupportKey: co.MultiWalletSupportKey, } cR.consensusThresh = co.consensusThresh @@ -524,7 +539,7 @@ func (co *CopyOperation) Error(allocObj *Allocation, consensus int, err error) { } -func NewCopyOperation(ctx context.Context, remotePath string, destPath string, copyMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh, fullConsensus int, copyDirOnly bool, clientId string) *CopyOperation { +func NewCopyOperation(ctx context.Context, remotePath string, destPath string, copyMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh, fullConsensus int, copyDirOnly bool, clientId string, keys ...string) *CopyOperation { co := &CopyOperation{} co.remotefilepath = zboxutil.RemoteClean(remotePath) co.copyMask = copyMask @@ -538,6 +553,10 @@ func NewCopyOperation(ctx context.Context, remotePath string, destPath string, c co.ctx, co.ctxCncl = context.WithCancel(ctx) co.dirOnly = copyDirOnly co.clientId = clientId + co.MultiWalletSupportKey = "" + if len(keys) > 0 { + co.MultiWalletSupportKey = keys[0] + } return co } @@ -573,7 +592,11 @@ func (req *CopyRequest) copySubDirectoriees(dirOnly bool) error { for { if !dirOnly { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, WithObjectContext(req.ctx), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)) + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, objOpts...) if err != nil { return err } @@ -599,7 +622,11 @@ func (req *CopyRequest) copySubDirectoriees(dirOnly bool) error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } @@ -617,7 +644,11 @@ func (req *CopyRequest) copySubDirectoriees(dirOnly bool) error { } for pathLevel > level { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, WithObjectContext(req.ctx), WithObjectMask(req.copyMask), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)) + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectMask(req.copyMask), WithObjectConsensusThresh(req.consensusThresh), WithSingleBlobber(true)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, objOpts...) if err != nil { return err } @@ -641,7 +672,11 @@ func (req *CopyRequest) copySubDirectoriees(dirOnly bool) error { } ops = append(ops, op) } - err = req.allocationObj.DoMultiOperation(ops) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation(ops) + } if err != nil { return err } diff --git a/zboxcore/sdk/deleteworker.go b/zboxcore/sdk/deleteworker.go index 93a3a052a..bf76bb47f 100644 --- a/zboxcore/sdk/deleteworker.go +++ b/zboxcore/sdk/deleteworker.go @@ -30,21 +30,21 @@ import ( ) type DeleteRequest struct { - allocationObj *Allocation - allocationID string - allocationTx string - sig string - blobbers []*blockchain.StorageNode - remotefilepath string - ctx context.Context - ctxCncl context.CancelFunc - wg *sync.WaitGroup - deleteMask zboxutil.Uint128 - maskMu *sync.Mutex - connectionID string - consensus Consensus - timestamp int64 - key string + allocationObj *Allocation + allocationID string + allocationTx string + sig string + blobbers []*blockchain.StorageNode + remotefilepath string + ctx context.Context + ctxCncl context.CancelFunc + wg *sync.WaitGroup + deleteMask zboxutil.Uint128 + maskMu *sync.Mutex + connectionID string + consensus Consensus + timestamp int64 + MultiWalletSupportKey string } var errFileDeleted = errors.New("file_deleted", "file is already deleted") @@ -68,7 +68,7 @@ func (req *DeleteRequest) deleteBlobberFile( query.Add("connection_id", req.connectionID) query.Add("path", req.remotefilepath) - httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.key) + httpreq, err := zboxutil.NewDeleteRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, query, req.MultiWalletSupportKey) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating delete request", err) return err @@ -175,10 +175,14 @@ func (req *DeleteRequest) getObjectTreeFromBlobber(pos uint64) ( req.maskMu.Unlock() } }() - + + key := req.allocationObj.Owner + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey + } fRefEntity, err = getObjectTreeFromBlobber( req.ctx, req.allocationID, req.allocationTx, req.sig, - req.remotefilepath, req.blobbers[pos], req.allocationObj.Owner) + req.remotefilepath, req.blobbers[pos], key) return } @@ -197,6 +201,7 @@ func (req *DeleteRequest) getFileMetaFromBlobber(pos uint64) (fileRef *fileref.F blobbers: req.blobbers, remotefilepath: req.remotefilepath, ctx: req.ctx, + MultiWalletSupportKey: req.MultiWalletSupportKey, } respChan := make(chan *fileMetaResponse) go listReq.getFileMetaInfoFromBlobber(req.blobbers[pos], int(pos), respChan) @@ -283,7 +288,7 @@ func (req *DeleteRequest) ProcessDelete() (err error) { req.consensus.consensusThresh, req.consensus.getConsensus())) } - writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj) + writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj, req.MultiWalletSupportKey) if err != nil { return fmt.Errorf("Delete failed: %s", err.Error()) } @@ -319,6 +324,7 @@ func (req *DeleteRequest) ProcessDelete() (err error) { connectionID: req.connectionID, wg: wg, timestamp: req.timestamp, + multiWalletSupportKey: req.MultiWalletSupportKey, } commitReq.changes = append(commitReq.changes, newChange) @@ -350,34 +356,34 @@ func (req *DeleteRequest) ProcessDelete() (err error) { } type DeleteOperation struct { - remotefilepath string - ctx context.Context - ctxCncl context.CancelFunc - deleteMask zboxutil.Uint128 - maskMu *sync.Mutex - consensus Consensus - lookupHash string - refs []fileref.RefEntity - key string + remotefilepath string + ctx context.Context + ctxCncl context.CancelFunc + deleteMask zboxutil.Uint128 + maskMu *sync.Mutex + consensus Consensus + lookupHash string + refs []fileref.RefEntity + MultiWalletSupportKey string } func (dop *DeleteOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { l.Logger.Info("Started Delete Process with Connection Id", connectionID) deleteReq := &DeleteRequest{ - allocationObj: allocObj, - allocationID: allocObj.ID, - allocationTx: allocObj.Tx, - sig: allocObj.sig, - connectionID: connectionID, - blobbers: allocObj.Blobbers, - remotefilepath: dop.remotefilepath, - ctx: dop.ctx, - ctxCncl: dop.ctxCncl, - deleteMask: dop.deleteMask, - maskMu: dop.maskMu, - wg: &sync.WaitGroup{}, - consensus: Consensus{RWMutex: &sync.RWMutex{}}, - key: dop.key, + allocationObj: allocObj, + allocationID: allocObj.ID, + allocationTx: allocObj.Tx, + sig: allocObj.sig, + connectionID: connectionID, + blobbers: allocObj.Blobbers, + remotefilepath: dop.remotefilepath, + ctx: dop.ctx, + ctxCncl: dop.ctxCncl, + deleteMask: dop.deleteMask, + maskMu: dop.maskMu, + wg: &sync.WaitGroup{}, + consensus: Consensus{RWMutex: &sync.RWMutex{}}, + MultiWalletSupportKey: dop.MultiWalletSupportKey, } deleteReq.consensus.fullconsensus = dop.consensus.fullconsensus deleteReq.consensus.consensusThresh = dop.consensus.consensusThresh @@ -594,7 +600,9 @@ func NewDeleteOperation(ctx context.Context, remotePath string, deleteMask zboxu dop.consensus.consensusThresh = consensusTh dop.consensus.fullconsensus = fullConsensus dop.ctx, dop.ctxCncl = context.WithCancel(ctx) - dop.key = keys[0] + if len(keys) > 0 { + dop.MultiWalletSupportKey = keys[0] + } return dop } @@ -605,7 +613,11 @@ func (req *DeleteRequest) deleteSubDirectories() error { pathLevel int ) for { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, WithObjectContext(req.ctx), WithObjectMask(req.deleteMask), WithObjectConsensusThresh(req.consensus.consensusThresh), WithSingleBlobber(true)) + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectMask(req.deleteMask), WithObjectConsensusThresh(req.consensus.consensusThresh), WithSingleBlobber(true)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.FILE, fileref.REGULAR, 0, getRefPageLimit, objOpts...) if err != nil { return err } @@ -628,13 +640,13 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - if req.key != "" { - wallet := client.GetWalletByKey(req.key) + if req.MultiWalletSupportKey != "" { + wallet := client.GetWalletByKey(req.MultiWalletSupportKey) if wallet == nil { - return errors.New("client_not_found", req.key) + return errors.New("multi-wallet-settings err: ", req.MultiWalletSupportKey) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Pubkey = req.key + mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) } else { err = req.allocationObj.DoMultiOperation(ops) @@ -655,7 +667,11 @@ func (req *DeleteRequest) deleteSubDirectories() error { } // list all directories by descending order of path level for pathLevel > level { - oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, WithObjectContext(req.ctx), WithObjectMask(req.deleteMask), WithObjectConsensusThresh(req.consensus.consensusThresh), WithSingleBlobber(true)) + objOpts := []ObjectTreeRequestOption{WithObjectContext(req.ctx), WithObjectMask(req.deleteMask), WithObjectConsensusThresh(req.consensus.consensusThresh), WithSingleBlobber(true)} + if req.MultiWalletSupportKey != "" { + objOpts = append(objOpts, WithObjectClientKey(req.MultiWalletSupportKey)) + } + oResult, err := req.allocationObj.GetRefs(req.remotefilepath, offsetPath, "", "", fileref.DIRECTORY, fileref.REGULAR, pathLevel, getRefPageLimit, objOpts...) if err != nil { return err } @@ -672,13 +688,13 @@ func (req *DeleteRequest) deleteSubDirectories() error { } ops = append(ops, op) } - if req.key != "" { - wallet := client.GetWalletByKey(req.key) + if req.MultiWalletSupportKey != "" { + wallet := client.GetWalletByKey(req.MultiWalletSupportKey) if wallet == nil { - return errors.New("client_not_found", req.key) + return errors.New("multi-wallet-settings err: ", req.MultiWalletSupportKey) } err = req.allocationObj.DoMultiOperation(ops, func(mo *MultiOperation) { - mo.Pubkey = req.key + mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) } else { err = req.allocationObj.DoMultiOperation(ops) diff --git a/zboxcore/sdk/dirworker.go b/zboxcore/sdk/dirworker.go index d333daa9e..61ba33b57 100644 --- a/zboxcore/sdk/dirworker.go +++ b/zboxcore/sdk/dirworker.go @@ -45,7 +45,7 @@ type DirRequest struct { timestamp int64 alreadyExists map[uint64]bool customMeta string - pubkey string + multiWalletSupportKey string Consensus } @@ -87,7 +87,7 @@ func (req *DirRequest) ProcessDir(a *Allocation) error { return errors.New("consensus_not_met", "directory creation failed due to consensus not met") } - writeMarkerMU, err := CreateWriteMarkerMutex(a) + writeMarkerMU, err := CreateWriteMarkerMutex(a, req.multiWalletSupportKey) if err != nil { return fmt.Errorf("directory creation failed. Err: %s", err.Error()) } @@ -134,6 +134,7 @@ func (req *DirRequest) commitRequest(existingDirCount int) error { commitReq.connectionID = req.connectionID commitReq.wg = wg commitReq.timestamp = req.timestamp + commitReq.multiWalletSupportKey = req.multiWalletSupportKey commitReqs[c] = commitReq c++ go AddCommitRequest(commitReq) @@ -191,8 +192,8 @@ func (req *DirRequest) createDirInBlobber(blobber *blockchain.StorageNode, pos u var ( httpreq *http.Request ) - if req.pubkey != "" { - httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.pubkey) + if req.multiWalletSupportKey != "" { + httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.multiWalletSupportKey) } else { httpreq, err = zboxutil.NewCreateDirRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) } @@ -283,14 +284,14 @@ func (req *DirRequest) createDirInBlobber(blobber *blockchain.StorageNode, pos u } type DirOperation struct { - remotePath string - ctx context.Context - ctxCncl context.CancelFunc - dirMask zboxutil.Uint128 - maskMU *sync.Mutex - customMeta string - alreadyExists map[uint64]bool - pubkey string + remotePath string + ctx context.Context + ctxCncl context.CancelFunc + dirMask zboxutil.Uint128 + maskMU *sync.Mutex + customMeta string + alreadyExists map[uint64]bool + multiWalletSupportKey string Consensus } @@ -312,7 +313,7 @@ func (dirOp *DirOperation) Process(allocObj *Allocation, connectionID string) ([ wg: &sync.WaitGroup{}, alreadyExists: make(map[uint64]bool), customMeta: dirOp.customMeta, - pubkey: dirOp.pubkey, + multiWalletSupportKey: dirOp.multiWalletSupportKey, } dR.Consensus = Consensus{ RWMutex: &sync.RWMutex{}, @@ -374,7 +375,7 @@ func (dirOp *DirOperation) Error(allocObj *Allocation, consensus int, err error) } -func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, pubkey string) *DirOperation { +func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, key string) *DirOperation { dirOp := &DirOperation{} dirOp.remotePath = zboxutil.RemoteClean(remotePath) dirOp.dirMask = dirMask @@ -382,7 +383,7 @@ func NewDirOperation(remotePath, customMeta string, dirMask zboxutil.Uint128, ma dirOp.consensusThresh = consensusTh dirOp.fullconsensus = fullConsensus dirOp.customMeta = customMeta - dirOp.pubkey = pubkey + dirOp.multiWalletSupportKey = key dirOp.ctx, dirOp.ctxCncl = context.WithCancel(ctx) dirOp.alreadyExists = make(map[uint64]bool) return dirOp diff --git a/zboxcore/sdk/downloadworker.go b/zboxcore/sdk/downloadworker.go index 7eae5c40b..e5ceb4a58 100644 --- a/zboxcore/sdk/downloadworker.go +++ b/zboxcore/sdk/downloadworker.go @@ -73,7 +73,7 @@ func WithFileCallback(cb func()) DownloadRequestOption { // signing and to populate client headers. func WithPubKey(pubkey string) DownloadRequestOption { return func(dr *DownloadRequest) { - dr.Pubkey = pubkey + dr.MultiWalletSupportKey = pubkey } } @@ -130,7 +130,7 @@ type DownloadRequest struct { allocOwnerSigningPubKey string // in case of auth ticket, this key will be of the shared user rather than the owner of the allocation allocOwnerSigningPrivateKey ed25519.PrivateKey - Pubkey string // in case of multi-wallet settings, this will be the public key of the wallet used for downloading + MultiWalletSupportKey string // in case of multi-wallet settings, this will be the public key of the wallet used for downloading } type downloadPriority struct { @@ -281,8 +281,8 @@ func (req *DownloadRequest) downloadBlock( connectionID: req.connectionID, } - // propagate the public key (if multi-wallet / split-wallet scenario) - blockDownloadReq.Pubkey = req.Pubkey + // propagate the public key (if multi-wallet / split-wallet scenario) + blockDownloadReq.Pubkey = req.MultiWalletSupportKey if blockDownloadReq.blobber.IsSkip() { rspCh <- &downloadBlock{ @@ -450,7 +450,7 @@ func (req *DownloadRequest) getDecryptedDataForAuthTicket(result *downloadBlock, // start block, end block and number of blocks to download in single request. // This will also write data to the file handler and will verify content by calculating content hash. func (req *DownloadRequest) processDownload() { - fmt.Print("inside process download: pubkey", req.Pubkey, "\n") + fmt.Print("inside process download: pubkey", req.MultiWalletSupportKey, "\n") ctx := req.ctx if req.completedCallback != nil { defer req.completedCallback(req.remotefilepath, req.remotefilepathhash) @@ -855,19 +855,19 @@ func (req *DownloadRequest) submitReadMarker(blobber *blockchain.StorageNode, re } func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageNode, readCount int64) error { - l.Logger.Info("attemptSubmitReadMarker: pubKey:", req.Pubkey, "\n") + l.Logger.Info("attemptSubmitReadMarker: pubKey:", req.MultiWalletSupportKey, "\n") lockBlobberReadCtr(req.allocationID, blobber.ID) defer unlockBlobberReadCtr(req.allocationID, blobber.ID) clientID := client.Id(req.ClientId) clientPublicKey := client.PublicKey() - if req.Pubkey != "" { - wallet := client.GetWalletByKey(req.Pubkey) + if req.MultiWalletSupportKey != "" { + wallet := client.GetWalletByKey(req.MultiWalletSupportKey) if wallet == nil { - return fmt.Errorf("wallet not found for public key: %s", req.Pubkey) + return fmt.Errorf("wallet not found for public key: %s", req.MultiWalletSupportKey) } clientID = wallet.ClientID - clientPublicKey = req.Pubkey + clientPublicKey = wallet.ClientKey } l.Logger.Info("DownloadRequest: clientID:", clientID, " clientPublicKey:", clientPublicKey, "\n") rm := &marker.ReadMarker{ @@ -879,7 +879,7 @@ func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageN Timestamp: common.Now(), ReadCounter: getBlobberReadCtr(req.allocationID, blobber.ID) + readCount, SessionRC: readCount, - IsSignUnderMultiWallet: req.Pubkey != "", + IsSignUnderMultiWallet: req.MultiWalletSupportKey != "", } err := rm.Sign() if err != nil { @@ -890,7 +890,7 @@ func (req *DownloadRequest) attemptSubmitReadMarker(blobber *blockchain.StorageN if err != nil { return fmt.Errorf("error marshaling read marker: %w", err) } - httpreq, err := zboxutil.NewRedeemRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.allocOwnerID) + httpreq, err := zboxutil.NewRedeemRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.allocOwnerID, req.MultiWalletSupportKey) if err != nil { return fmt.Errorf("error creating download request: %w", err) } @@ -1201,6 +1201,7 @@ func GetFileRefFromBlobber(allocationID, blobberId, remotePath string) (fRef *fi ctx := context.Background() listReq := &ListRequest{} + listReq.ClientId = a.Owner listReq.allocationID = a.ID listReq.allocationTx = a.Tx listReq.sig = a.sig @@ -1211,6 +1212,9 @@ func GetFileRefFromBlobber(allocationID, blobberId, remotePath string) (fRef *fi listReq.consensusThresh = 1 listReq.ctx = ctx listReq.remotefilepath = remotePath + if a.MultiWalletSupportKey != "" { + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey + } rspCh := make(chan *fileMetaResponse, 1) go listReq.getFileMetaInfoFromBlobber(listReq.blobbers[0], 0, rspCh) @@ -1233,13 +1237,12 @@ func (req *DownloadRequest) getFileRef() (fRef *fileref.FileRef, err error) { fullconsensus: req.fullconsensus, consensusThresh: req.consensusThresh, }, - ctx: req.ctx, - Pubkey: req.Pubkey, + ctx: req.ctx, + MultiWalletSupportKey: req.MultiWalletSupportKey, } fMetaResp := listReq.getFileMetaFromBlobbers() l.Logger.Info("fMetaResp length: ", len(fMetaResp), "\n") - fRef, err = req.getFileMetaConsensus(fMetaResp) if err != nil { diff --git a/zboxcore/sdk/filemetaworker.go b/zboxcore/sdk/filemetaworker.go index d9c0fd22b..fcfaa8d0a 100644 --- a/zboxcore/sdk/filemetaworker.go +++ b/zboxcore/sdk/filemetaworker.go @@ -78,8 +78,8 @@ func (req *ListRequest) getFileMetaInfoFromBlobber(blobber *blockchain.StorageNo formWriter.Close() key := client.Wallet().ClientID - if req.Pubkey != "" { - key = req.Pubkey + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey } httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, key) if err != nil { @@ -146,7 +146,11 @@ func (req *ListRequest) getFileMetaByNameInfoFromBlobber(blobber *blockchain.Sto } } formWriter.Close() - httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.ClientId) + key := client.Wallet().ClientID + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey + } + httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, key) if err != nil { l.Logger.Error("File meta info request error: ", err.Error()) return diff --git a/zboxcore/sdk/filerefsworker.go b/zboxcore/sdk/filerefsworker.go index c02cfa5ea..c9ed9caf4 100644 --- a/zboxcore/sdk/filerefsworker.go +++ b/zboxcore/sdk/filerefsworker.go @@ -33,7 +33,7 @@ const INVALID_PATH = "invalid_path" type ObjectTreeRequest struct { ClientId string - PubKey string + MultiWalletSupportKey string allocationID string allocationTx string sig string @@ -102,7 +102,7 @@ func WithAuthToken(token string) ObjectTreeRequestOption { // the HTTP request when performing refs/list operations. func WithObjectClientKey(key string) ObjectTreeRequestOption { return func(o *ObjectTreeRequest) { - o.PubKey = key + o.MultiWalletSupportKey = key } } @@ -248,9 +248,9 @@ func (o *ObjectTreeRequest) getFileRefs(bUrl string, respChan chan *oTreeRespons // Determine the client key to use for signing the refs request. Prefer // the explicit PubKey when provided by the caller; otherwise fall back // to ClientId (historical behavior). - clientKey := o.ClientId - if o.PubKey != "" { - clientKey = o.PubKey + key := o.ClientId + if o.MultiWalletSupportKey != "" { + key = o.MultiWalletSupportKey } oReq, err := zboxutil.NewRefsRequest( @@ -268,7 +268,7 @@ func (o *ObjectTreeRequest) getFileRefs(bUrl string, respChan chan *oTreeRespons o.refType, o.level, o.pageLimit, - clientKey, + key, ) if err != nil { oTR.err = err diff --git a/zboxcore/sdk/listworker.go b/zboxcore/sdk/listworker.go index 519621850..c89c3163e 100644 --- a/zboxcore/sdk/listworker.go +++ b/zboxcore/sdk/listworker.go @@ -23,23 +23,23 @@ import ( const CHUNK_SIZE = 64 * 1024 type ListRequest struct { - ClientId string - allocationID string - allocationTx string - sig string - blobbers []*blockchain.StorageNode - remotefilepathhash string - remotefilepath string - filename string - authToken *marker.AuthTicket - ctx context.Context - forRepair bool - listOnly bool - offset int - pageLimit int - storageVersion int - dataShards int - Pubkey string + ClientId string + allocationID string + allocationTx string + sig string + blobbers []*blockchain.StorageNode + remotefilepathhash string + remotefilepath string + filename string + authToken *marker.AuthTicket + ctx context.Context + forRepair bool + listOnly bool + offset int + pageLimit int + storageVersion int + dataShards int + MultiWalletSupportKey string Consensus } @@ -132,7 +132,15 @@ func (req *ListRequest) getListInfoFromBlobber(blobber *blockchain.StorageNode, if req.forRepair { req.listOnly = true } - httpreq, err := zboxutil.NewListRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.remotefilepath, req.remotefilepathhash, string(authTokenBytes), req.listOnly, req.offset, req.pageLimit, req.ClientId) + // Choose signing key for the HTTP request: prefer operation-level + // MultiWalletSupportKey if present, otherwise fall back to the request ClientId. + var clientKey string + if req.MultiWalletSupportKey != "" { + clientKey = req.MultiWalletSupportKey + } else { + clientKey = req.ClientId + } + httpreq, err := zboxutil.NewListRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.remotefilepath, req.remotefilepathhash, string(authTokenBytes), req.listOnly, req.offset, req.pageLimit, clientKey) if err != nil { l.Logger.Error("List info request error: ", err.Error()) return diff --git a/zboxcore/sdk/moveworker.go b/zboxcore/sdk/moveworker.go index 2294e09c0..b96499319 100644 --- a/zboxcore/sdk/moveworker.go +++ b/zboxcore/sdk/moveworker.go @@ -31,39 +31,44 @@ import ( ) type MoveRequest struct { - allocationObj *Allocation - allocationID string - allocationTx string - sig string - blobbers []*blockchain.StorageNode - remotefilepath string - destPath string - ctx context.Context - ctxCncl context.CancelFunc - moveMask zboxutil.Uint128 - maskMU *sync.Mutex - connectionID string - timestamp int64 - destLookupHash string - clientId string + allocationObj *Allocation + allocationID string + allocationTx string + sig string + blobbers []*blockchain.StorageNode + remotefilepath string + destPath string + ctx context.Context + ctxCncl context.CancelFunc + moveMask zboxutil.Uint128 + maskMU *sync.Mutex + connectionID string + timestamp int64 + destLookupHash string + clientId string + MultiWalletSupportKey string Consensus } func (req *MoveRequest) getObjectTreeFromBlobber(blobber *blockchain.StorageNode) (fileref.RefEntity, error) { - clientId := req.clientId - if clientId == "" { - clientId = req.allocationObj.Owner + key := req.clientId + if key == "" { + key = req.allocationObj.Owner } - return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner, clientId) + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey + } + return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, key) } func (req *MoveRequest) getFileMetaFromBlobber(pos int) (fileRef *fileref.FileRef, err error) { listReq := &ListRequest{ - allocationID: req.allocationID, - allocationTx: req.allocationTx, - blobbers: req.blobbers, - remotefilepath: req.remotefilepath, - ctx: req.ctx, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + blobbers: req.blobbers, + remotefilepath: req.remotefilepath, + ctx: req.ctx, + MultiWalletSupportKey: req.MultiWalletSupportKey, } respChan := make(chan *fileMetaResponse) go listReq.getFileMetaInfoFromBlobber(req.blobbers[pos], int(pos), respChan) @@ -127,11 +132,14 @@ func (req *MoveRequest) moveBlobberObject( cncl context.CancelFunc ) - clientId := req.clientId - if clientId == "" { - clientId = req.allocationObj.Owner + key := req.clientId + if key == "" { + key = req.allocationObj.Owner + } + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey } - httpreq, err = zboxutil.NewMoveRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) + httpreq, err = zboxutil.NewMoveRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, key) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -267,14 +275,15 @@ func (req *MoveRequest) ProcessWithBlobbersV2() ([]fileref.RefEntity, error) { } } subRequest := &subDirRequest{ - allocationObj: req.allocationObj, - remotefilepath: req.remotefilepath, - destPath: req.destPath, - ctx: req.ctx, - consensusThresh: req.consensusThresh, - opType: constants.FileOperationMove, - subOpType: constants.FileOperationMove, - mask: req.moveMask, + allocationObj: req.allocationObj, + remotefilepath: req.remotefilepath, + destPath: req.destPath, + ctx: req.ctx, + consensusThresh: req.consensusThresh, + opType: constants.FileOperationMove, + subOpType: constants.FileOperationMove, + mask: req.moveMask, + MultiWalletSupportKey: req.MultiWalletSupportKey, } err := subRequest.processSubDirectories() if err != nil { @@ -284,7 +293,11 @@ func (req *MoveRequest) ProcessWithBlobbersV2() ([]fileref.RefEntity, error) { OperationType: constants.FileOperationDelete, RemotePath: req.remotefilepath, } - err = req.allocationObj.DoMultiOperation([]OperationRequest{op}) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation([]OperationRequest{op}, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation([]OperationRequest{op}) + } if err != nil { return nil, err } @@ -335,7 +348,7 @@ func (req *MoveRequest) ProcessMove() error { req.Consensus.consensusThresh, req.Consensus.consensus)) } - writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj) + writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj, req.MultiWalletSupportKey) if err != nil { return fmt.Errorf("Move failed: %s", err.Error()) } @@ -382,14 +395,15 @@ func (req *MoveRequest) ProcessMove() error { moveChange.Operation = constants.FileOperationMove moveChange.Size = 0 commitReq := &CommitRequest{ - ClientId: req.allocationObj.Owner, - allocationID: req.allocationID, - allocationTx: req.allocationTx, - sig: req.sig, - blobber: req.blobbers[pos], - connectionID: req.connectionID, - wg: wg, - timestamp: req.timestamp, + ClientId: req.allocationObj.Owner, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + sig: req.sig, + blobber: req.blobbers[pos], + connectionID: req.connectionID, + wg: wg, + timestamp: req.timestamp, + multiWalletSupportKey: req.MultiWalletSupportKey, } // commitReq.change = moveChange commitReq.changes = append(commitReq.changes, moveChange) @@ -421,35 +435,37 @@ func (req *MoveRequest) ProcessMove() error { } type MoveOperation struct { - remotefilepath string - destPath string - srcLookupHash string - destLookupHash string - ctx context.Context - ctxCncl context.CancelFunc - moveMask zboxutil.Uint128 - maskMU *sync.Mutex - consensus Consensus - objectTreeRefs []fileref.RefEntity - clientId string + remotefilepath string + destPath string + srcLookupHash string + destLookupHash string + ctx context.Context + ctxCncl context.CancelFunc + moveMask zboxutil.Uint128 + maskMU *sync.Mutex + consensus Consensus + objectTreeRefs []fileref.RefEntity + clientId string + MultiWalletSupportKey string } func (mo *MoveOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { mR := &MoveRequest{ - allocationObj: allocObj, - allocationID: allocObj.ID, - allocationTx: allocObj.Tx, - sig: allocObj.sig, - connectionID: connectionID, - blobbers: allocObj.Blobbers, - remotefilepath: mo.remotefilepath, - ctx: mo.ctx, - ctxCncl: mo.ctxCncl, - moveMask: mo.moveMask, - maskMU: mo.maskMU, - destPath: mo.destPath, - Consensus: Consensus{RWMutex: &sync.RWMutex{}}, - clientId: mo.clientId, + allocationObj: allocObj, + allocationID: allocObj.ID, + allocationTx: allocObj.Tx, + sig: allocObj.sig, + connectionID: connectionID, + blobbers: allocObj.Blobbers, + remotefilepath: mo.remotefilepath, + ctx: mo.ctx, + ctxCncl: mo.ctxCncl, + moveMask: mo.moveMask, + maskMU: mo.maskMU, + destPath: mo.destPath, + Consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: mo.clientId, + MultiWalletSupportKey: mo.MultiWalletSupportKey, } mR.Consensus.fullconsensus = mo.consensus.fullconsensus mR.Consensus.consensusThresh = mo.consensus.consensusThresh @@ -529,7 +545,7 @@ func (mo *MoveOperation) Error(allocObj *Allocation, consensus int, err error) { } -func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string) *MoveOperation { +func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string, keys ...string) *MoveOperation { mo := &MoveOperation{} mo.remotefilepath = zboxutil.RemoteClean(remotePath) if destPath != "/" { @@ -542,6 +558,9 @@ func NewMoveOperation(remotePath string, destPath string, moveMask zboxutil.Uint mo.consensus.fullconsensus = fullConsensus mo.ctx, mo.ctxCncl = context.WithCancel(ctx) mo.clientId = clientId + if len(keys) > 0 && keys[0] != "" { + mo.MultiWalletSupportKey = keys[0] + } return mo } diff --git a/zboxcore/sdk/multi_operation_worker.go b/zboxcore/sdk/multi_operation_worker.go index d9e9f7c01..d583bcfdf 100644 --- a/zboxcore/sdk/multi_operation_worker.go +++ b/zboxcore/sdk/multi_operation_worker.go @@ -60,10 +60,10 @@ type MultiOperation struct { operationMask zboxutil.Uint128 maskMU *sync.Mutex Consensus - changes [][]allocationchange.AllocationChange - changesV2 []allocationchange.AllocationChangeV2 - isRepair bool - Pubkey string + changes [][]allocationchange.AllocationChange + changesV2 []allocationchange.AllocationChangeV2 + isRepair bool + MultiWalletSupportKey string } func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { @@ -96,8 +96,8 @@ func (mo *MultiOperation) createConnectionObj(blobberIdx int) (err error) { formWriter.Close() var httpreq *http.Request - if mo.Pubkey != "" { - httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.Pubkey) + if mo.MultiWalletSupportKey != "" { + httpreq, err = zboxutil.NewConnectionRequest(blobber.Baseurl, mo.allocationObj.ID, mo.allocationObj.Tx, mo.allocationObj.sig, body, mo.MultiWalletSupportKey) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating new connection request by wallet", err) return err, false @@ -255,7 +255,7 @@ func (mo *MultiOperation) Process() error { mo.changes = zboxutil.Transpose(mo.changes) } - writeMarkerMutex, err := CreateWriteMarkerMutex(mo.allocationObj, mo.Pubkey) + writeMarkerMutex, err := CreateWriteMarkerMutex(mo.allocationObj, mo.MultiWalletSupportKey) if err != nil { for _, op := range mo.operations { op.Error(mo.allocationObj, 0, err) @@ -277,8 +277,8 @@ func (mo *MultiOperation) Process() error { start = time.Now() status := Commit if !mo.isRepair && !mo.allocationObj.checkStatus { - if mo.Pubkey != "" { - status, _, err = mo.allocationObj.CheckAllocStatus(mo.Pubkey) + if mo.MultiWalletSupportKey != "" { + status, _, err = mo.allocationObj.CheckAllocStatus(mo.MultiWalletSupportKey) } else { status, _, err = mo.allocationObj.CheckAllocStatus() } @@ -347,16 +347,16 @@ func (mo *MultiOperation) Process() error { // ClientId must always be the allocation owner. Use Pubkey only for signing // (stored in the commit request's pubkey field). commitReq := &CommitRequest{ - ClientId: mo.allocationObj.Owner, - allocationID: mo.allocationObj.ID, - allocationTx: mo.allocationObj.Tx, - sig: mo.allocationObj.sig, - blobber: mo.allocationObj.Blobbers[pos], - connectionID: mo.connectionID, - wg: wg, - timestamp: timestamp, - blobberInd: pos, - pubkey: mo.Pubkey, + ClientId: mo.allocationObj.Owner, + allocationID: mo.allocationObj.ID, + allocationTx: mo.allocationObj.Tx, + sig: mo.allocationObj.sig, + blobber: mo.allocationObj.Blobbers[pos], + connectionID: mo.connectionID, + wg: wg, + timestamp: timestamp, + blobberInd: pos, + multiWalletSupportKey: mo.MultiWalletSupportKey, } commitReq.changes = append(commitReq.changes, mo.changes[pos]...) @@ -431,16 +431,16 @@ func (mo *MultiOperation) commitV2() error { threshold = mask.CountOnes() } commitReq := &CommitRequestV2{ - allocationObj: mo.allocationObj, - connectionID: mo.connectionID, - sig: mo.allocationObj.sig, - wg: wg, - timestamp: timestamp, - commitMask: mask, - consensusThresh: threshold, - changes: changes, - isRepair: mo.isRepair, - pubkey: mo.Pubkey, + allocationObj: mo.allocationObj, + connectionID: mo.connectionID, + sig: mo.allocationObj.sig, + wg: wg, + timestamp: timestamp, + commitMask: mask, + consensusThresh: threshold, + changes: changes, + isRepair: mo.isRepair, + multiWalletSupportKey: mo.MultiWalletSupportKey, } commitReqs[counter] = commitReq counter++ diff --git a/zboxcore/sdk/renameworker.go b/zboxcore/sdk/renameworker.go index f83dc75ac..aa923e70c 100644 --- a/zboxcore/sdk/renameworker.go +++ b/zboxcore/sdk/renameworker.go @@ -30,39 +30,44 @@ import ( ) type RenameRequest struct { - allocationObj *Allocation - allocationID string - allocationTx string - sig string - blobbers []*blockchain.StorageNode - remotefilepath string - newName string - ctx context.Context - ctxCncl context.CancelFunc - wg *sync.WaitGroup - renameMask zboxutil.Uint128 - maskMU *sync.Mutex - connectionID string - consensus Consensus - timestamp int64 - clientId string + allocationObj *Allocation + allocationID string + allocationTx string + sig string + blobbers []*blockchain.StorageNode + remotefilepath string + newName string + ctx context.Context + ctxCncl context.CancelFunc + wg *sync.WaitGroup + renameMask zboxutil.Uint128 + maskMU *sync.Mutex + connectionID string + consensus Consensus + timestamp int64 + clientId string + MultiWalletSupportKey string } func (req *RenameRequest) getObjectTreeFromBlobber(blobber *blockchain.StorageNode) (fileref.RefEntity, error) { - clientId := req.clientId - if clientId == "" { - clientId = req.allocationObj.Owner + key := req.clientId + if key == "" { + key = req.allocationObj.Owner } - return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, req.allocationObj.Owner, clientId) + if req.MultiWalletSupportKey != "" { + key = req.MultiWalletSupportKey + } + return getObjectTreeFromBlobber(req.ctx, req.allocationID, req.allocationTx, req.sig, req.remotefilepath, blobber, key) } func (req *RenameRequest) getFileMetaFromBlobber(pos int) (fileRef *fileref.FileRef, err error) { listReq := &ListRequest{ - allocationID: req.allocationID, - allocationTx: req.allocationTx, - blobbers: req.blobbers, - remotefilepath: req.remotefilepath, - ctx: req.ctx, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + blobbers: req.blobbers, + remotefilepath: req.remotefilepath, + ctx: req.ctx, + MultiWalletSupportKey: req.MultiWalletSupportKey, } respChan := make(chan *fileMetaResponse) go listReq.getFileMetaInfoFromBlobber(req.blobbers[pos], int(pos), respChan) @@ -122,11 +127,11 @@ func (req *RenameRequest) renameBlobberObject( formWriter.Close() var httpreq *http.Request - clientId := req.clientId - if clientId == "" { - clientId = req.allocationObj.Owner + if req.MultiWalletSupportKey != "" { + httpreq, err = zboxutil.NewRenameRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.MultiWalletSupportKey) + } else { + httpreq, err = zboxutil.NewRenameRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner) } - httpreq, err = zboxutil.NewRenameRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body, req.allocationObj.Owner, clientId) if err != nil { l.Logger.Error(blobber.Baseurl, "Error creating rename request", err) return @@ -262,14 +267,15 @@ func (req *RenameRequest) ProcessWithBlobbersV2() ([]fileref.RefEntity, error) { } } subRequest := &subDirRequest{ - allocationObj: req.allocationObj, - remotefilepath: req.remotefilepath, - destPath: path.Join(path.Dir(req.remotefilepath), req.newName), - ctx: req.ctx, - consensusThresh: req.consensus.consensusThresh, - opType: constants.FileOperationMove, - subOpType: constants.FileOperationRename, - mask: req.renameMask, + allocationObj: req.allocationObj, + remotefilepath: req.remotefilepath, + destPath: path.Join(path.Dir(req.remotefilepath), req.newName), + ctx: req.ctx, + consensusThresh: req.consensus.consensusThresh, + opType: constants.FileOperationMove, + subOpType: constants.FileOperationRename, + mask: req.renameMask, + MultiWalletSupportKey: req.MultiWalletSupportKey, } err := subRequest.processSubDirectories() if err != nil { @@ -280,7 +286,11 @@ func (req *RenameRequest) ProcessWithBlobbersV2() ([]fileref.RefEntity, error) { RemotePath: req.remotefilepath, Mask: &req.renameMask, } - err = req.allocationObj.DoMultiOperation([]OperationRequest{op}) + if req.MultiWalletSupportKey != "" { + err = req.allocationObj.DoMultiOperation([]OperationRequest{op}, func(mo *MultiOperation) { mo.MultiWalletSupportKey = req.MultiWalletSupportKey }) + } else { + err = req.allocationObj.DoMultiOperation([]OperationRequest{op}) + } if err != nil { return nil, err } @@ -325,7 +335,7 @@ func (req *RenameRequest) ProcessRename() error { req.consensus.consensusThresh, req.consensus.getConsensus())) } - writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj) + writeMarkerMutex, err := CreateWriteMarkerMutex(req.allocationObj, req.MultiWalletSupportKey) if err != nil { return fmt.Errorf("rename failed: %s", err.Error()) } @@ -338,7 +348,7 @@ func (req *RenameRequest) ProcessRename() error { defer writeMarkerMutex.Unlock(req.ctx, req.renameMask, req.blobbers, time.Minute, req.connectionID) //nolint: errcheck //Check if the allocation is to be repaired or rolled back - status, _, err := req.allocationObj.CheckAllocStatus() + status, _, err := req.allocationObj.CheckAllocStatus(req.MultiWalletSupportKey) if err != nil { logger.Logger.Error("Error checking allocation status: ", err) return fmt.Errorf("rename failed: %s", err.Error()) @@ -375,14 +385,15 @@ func (req *RenameRequest) ProcessRename() error { newChange.Size = 0 commitReq := &CommitRequest{ - ClientId: req.allocationObj.Owner, - allocationID: req.allocationID, - allocationTx: req.allocationTx, - sig: req.sig, - blobber: req.blobbers[pos], - connectionID: req.connectionID, - wg: wg, - timestamp: req.timestamp, + ClientId: req.allocationObj.Owner, + allocationID: req.allocationID, + allocationTx: req.allocationTx, + sig: req.sig, + blobber: req.blobbers[pos], + connectionID: req.connectionID, + wg: wg, + timestamp: req.timestamp, + multiWalletSupportKey: req.MultiWalletSupportKey, } commitReq.changes = append(commitReq.changes, newChange) commitReqs[counter] = commitReq @@ -418,16 +429,17 @@ func (req *RenameRequest) ProcessRename() error { } type RenameOperation struct { - remotefilepath string - srcLookupHash string - destLookupHash string - ctx context.Context - ctxCncl context.CancelFunc - renameMask zboxutil.Uint128 - newName string - maskMU *sync.Mutex - objectTreeRefs []fileref.RefEntity - clientId string + remotefilepath string + srcLookupHash string + destLookupHash string + ctx context.Context + ctxCncl context.CancelFunc + renameMask zboxutil.Uint128 + newName string + maskMU *sync.Mutex + objectTreeRefs []fileref.RefEntity + clientId string + MultiWalletSupportKey string consensus Consensus } @@ -435,21 +447,22 @@ type RenameOperation struct { func (ro *RenameOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { // make renameRequest object rR := &RenameRequest{ - allocationObj: allocObj, - allocationID: allocObj.ID, - allocationTx: allocObj.Tx, - sig: allocObj.sig, - connectionID: connectionID, - blobbers: allocObj.Blobbers, - remotefilepath: ro.remotefilepath, - newName: ro.newName, - ctx: ro.ctx, - ctxCncl: ro.ctxCncl, - renameMask: ro.renameMask, - maskMU: ro.maskMU, - wg: &sync.WaitGroup{}, - consensus: Consensus{RWMutex: &sync.RWMutex{}}, - clientId: ro.clientId, + allocationObj: allocObj, + allocationID: allocObj.ID, + allocationTx: allocObj.Tx, + sig: allocObj.sig, + connectionID: connectionID, + blobbers: allocObj.Blobbers, + remotefilepath: ro.remotefilepath, + newName: ro.newName, + ctx: ro.ctx, + ctxCncl: ro.ctxCncl, + renameMask: ro.renameMask, + maskMU: ro.maskMU, + wg: &sync.WaitGroup{}, + consensus: Consensus{RWMutex: &sync.RWMutex{}}, + clientId: ro.clientId, + MultiWalletSupportKey: ro.MultiWalletSupportKey, } if filepath.Base(ro.remotefilepath) == ro.newName { return nil, ro.renameMask, errors.New("invalid_operation", "Cannot rename to same name") @@ -537,7 +550,7 @@ func (ro *RenameOperation) Error(allocObj *Allocation, consensus int, err error) } -func NewRenameOperation(remotePath string, destName string, renameMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string) *RenameOperation { +func NewRenameOperation(remotePath string, destName string, renameMask zboxutil.Uint128, maskMU *sync.Mutex, consensusTh int, fullConsensus int, ctx context.Context, clientId string, multiWalletKey string) *RenameOperation { ro := &RenameOperation{} ro.remotefilepath = zboxutil.RemoteClean(remotePath) ro.newName = path.Base(destName) @@ -547,6 +560,7 @@ func NewRenameOperation(remotePath string, destName string, renameMask zboxutil. ro.consensus.fullconsensus = fullConsensus ro.ctx, ro.ctxCncl = context.WithCancel(ctx) ro.clientId = clientId + ro.MultiWalletSupportKey = multiWalletKey return ro } diff --git a/zboxcore/sdk/repairworker.go b/zboxcore/sdk/repairworker.go index 319e23411..bd1cc3306 100644 --- a/zboxcore/sdk/repairworker.go +++ b/zboxcore/sdk/repairworker.go @@ -286,7 +286,12 @@ func (r *RepairRequest) repairFile(a *Allocation, file *ListResult) []OperationR } func (r *RepairRequest) repairOperation(a *Allocation, ops []OperationRequest) { - err := a.DoMultiOperation(ops, WithRepair()) + opts := []MultiOperationOption{WithRepair()} + if a.MultiWalletSupportKey != "" { + opts = append(opts, func(mo *MultiOperation) { mo.MultiWalletSupportKey = a.MultiWalletSupportKey }) + } + + err := a.DoMultiOperation(ops, opts...) if err != nil { l.Logger.Error("repair_file_failed", zap.Error(err)) status := r.statusCB != nil diff --git a/zboxcore/sdk/rollback.go b/zboxcore/sdk/rollback.go index 3a9cee1b0..005c723a3 100644 --- a/zboxcore/sdk/rollback.go +++ b/zboxcore/sdk/rollback.go @@ -51,11 +51,12 @@ var ( ) type RollbackBlobber struct { - ClientId string - blobber *blockchain.StorageNode - commitResult *CommitResult - lpm *LatestPrevWriteMarker - blobIndex int + ClientId string + MultiWalletSupportKey string + blobber *blockchain.StorageNode + commitResult *CommitResult + lpm *LatestPrevWriteMarker + blobIndex int } type BlobberStatus struct { @@ -137,7 +138,10 @@ func (rb *RollbackBlobber) processRollback(ctx context.Context, tx string) error wm.AllocationID = rb.lpm.LatestWM.AllocationID wm.Timestamp = rb.lpm.LatestWM.Timestamp wm.BlobberID = rb.lpm.LatestWM.BlobberID - wm.ClientID = client.Id() + if rb.MultiWalletSupportKey != "" { + wm.MultiWalletSupportKey = rb.MultiWalletSupportKey + } + wm.ClientID = rb.ClientId wm.Size = -rb.lpm.LatestWM.Size wm.ChainSize = wm.Size + rb.lpm.LatestWM.ChainSize @@ -189,7 +193,12 @@ func (rb *RollbackBlobber) processRollback(ctx context.Context, tx string) error return err } - req, err := zboxutil.NewRollbackRequest(rb.blobber.Baseurl, wm.AllocationID, tx, body, wm.ClientID) + var req *http.Request + if rb.MultiWalletSupportKey != "" { + req, err = zboxutil.NewRollbackRequest(rb.blobber.Baseurl, wm.AllocationID, tx, body, rb.MultiWalletSupportKey) + } else { + req, err = zboxutil.NewRollbackRequest(rb.blobber.Baseurl, wm.AllocationID, tx, body) + } if err != nil { l.Logger.Error("Creating rollback request failed: ", err) return err diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 9cc460c20..637b8caf3 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -1291,11 +1291,11 @@ func storageSmartContractTxn(sn transaction.SmartContractTxnData) ( return storageSmartContractTxnValue(sn, 0) } -func storageSmartContractTxnValue(sn transaction.SmartContractTxnData, value uint64) ( +func storageSmartContractTxnValue(sn transaction.SmartContractTxnData, value uint64, keys ...string) ( hash, out string, nonce int64, txn *transaction.Transaction, err error) { // Fee is set during sdk initialization. - return transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, value, client.TxnFee(), true) + return transaction.SmartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, value, client.TxnFee(), true, keys...) } func CommitToFabric(metaTxnData, fabricConfigJSON string) (string, error) { @@ -1584,7 +1584,7 @@ func DoMultiUploadByWallet(pubkey string, a *Allocation, workdir string, localPa } setWalletOpt := func(mo *MultiOperation) { - mo.Pubkey = pubkey + mo.MultiWalletSupportKey = pubkey } return a.DoMultiOperation(operationRequests, setWalletOpt) } diff --git a/zboxcore/sdk/upload_worker.go b/zboxcore/sdk/upload_worker.go index e405e504f..147b73fd7 100644 --- a/zboxcore/sdk/upload_worker.go +++ b/zboxcore/sdk/upload_worker.go @@ -36,7 +36,7 @@ func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([ err := allocObj.DownloadFileToFileHandler(f, uo.chunkedUpload.fileMeta.RemotePath, false, nil, true, WithFileCallback(func() { f.Close() //nolint:errcheck }), func(dr *DownloadRequest) { - dr.Pubkey = uo.chunkedUpload.pubkey + dr.MultiWalletSupportKey = uo.chunkedUpload.pubkey }) if err != nil { l.Logger.Error("DownloadFileToFileHandler Failed", zap.String("path", uo.chunkedUpload.fileMeta.RemotePath), zap.Error(err)) diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index d7573925f..baf25b000 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -224,7 +224,7 @@ func setClientInfoWithSign(req *http.Request, sig, allocation, baseURL string, k if wallet == nil { return errors.New("multi-wallet-settings err: ", "wallet not found : "+key) } - fmt.Printf("setClientInfoWithSign: wallet details: %+v\n", *wallet) + l.Logger.Info(fmt.Sprintf("setClientInfoWithSign: wallet details: %+v", *wallet)) req.Header.Set("X-App-Client-ID", wallet.ClientID) req.Header.Set("X-App-Client-Key", wallet.ClientKey) req.Header.Set(CLIENT_SIGNATURE_HEADER, sig) @@ -328,7 +328,7 @@ func NewReferencePathRequestV2(baseUrl, allocationID, allocationTx, sig string, return req, nil } -func NewCalculateHashRequest(baseUrl, allocationID string, allocationTx string, paths []string, clients ...string) (*http.Request, error) { +func NewCalculateHashRequest(baseUrl, allocationID string, allocationTx string, paths []string, keys ...string) (*http.Request, error) { nurl, err := joinUrl(baseUrl, CALCULATE_HASH_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -344,14 +344,14 @@ func NewCalculateHashRequest(baseUrl, allocationID string, allocationTx string, if err != nil { return nil, err } - setClientInfo(req) + setClientInfo(req, keys...) req.Header.Set(ALLOCATION_ID_HEADER, allocationID) return req, nil } -func NewObjectTreeRequest(baseUrl, allocationID string, allocationTx string, sig string, path string, clients ...string) (*http.Request, error) { +func NewObjectTreeRequest(baseUrl, allocationID string, allocationTx string, sig string, path string, keys ...string) (*http.Request, error) { nurl, err := joinUrl(baseUrl, OBJECT_TREE_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -365,7 +365,7 @@ func NewObjectTreeRequest(baseUrl, allocationID string, allocationTx string, sig return nil, err } - if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, clients...); err != nil { + if err := setClientInfoWithSign(req, sig, allocationTx, baseUrl, keys...); err != nil { return nil, err } @@ -882,7 +882,7 @@ func NewFastDownloadRequest(baseUrl, allocationID, allocationTx string, keys ... return req, nil } -func NewRedeemRequest(baseUrl, allocationID, allocationTx string, clients ...string) (*http.Request, error) { +func NewRedeemRequest(baseUrl, allocationID, allocationTx string, keys ...string) (*http.Request, error) { u, err := joinUrl(baseUrl, REDEEM_ENDPOINT, allocationTx) if err != nil { return nil, err @@ -892,7 +892,7 @@ func NewRedeemRequest(baseUrl, allocationID, allocationTx string, clients ...str if err != nil { return nil, err } - setClientInfo(req) + setClientInfo(req, keys...) req.Header.Set(ALLOCATION_ID_HEADER, allocationID) return req, nil } From 6720c7162a869382a244901fd16e1280a07eb7eb Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Thu, 13 Nov 2025 17:07:06 +0530 Subject: [PATCH 31/47] changes in allocation file and add wasm functions --- core/client/set.go | 21 ++++ wasmsdk/blobber_mw.go | 213 +++++++++++++++++++++++++++++++++ wasmsdk/cache.go | 4 +- zboxcore/marker/authticket.go | 3 +- zboxcore/sdk/allocation.go | 101 +++++++++++----- zboxcore/sdk/filerefsworker.go | 8 +- zboxcore/sdk/sdk.go | 4 +- zboxcore/sdk/sharerequest.go | 9 +- zboxcore/zboxutil/http.go | 4 +- 9 files changed, 328 insertions(+), 39 deletions(-) create mode 100644 wasmsdk/blobber_mw.go diff --git a/core/client/set.go b/core/client/set.go index 87cef30c1..09da56a59 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -501,6 +501,27 @@ func Mnemonic() string { return client.wallet.Mnemonic } +// GetWalletMnemonic returns the mnemonic for a wallet identified by pubkey. +// If the pubkey is empty or not found, it returns the SDK default wallet mnemonic. +func GetWalletMnemonic(pubkey string) string { + if pubkey != "" { + client.mu.RLock() + if client.wallets != nil { + if w, ok := client.wallets[pubkey]; ok && w != nil { + mn := w.Mnemonic + client.mu.RUnlock() + return mn + } + } + client.mu.RUnlock() + } + + if client.wallet != nil { + return client.wallet.Mnemonic + } + return "" +} + func PrivateKey() string { for _, kv := range client.wallet.Keys { return kv.PrivateKey diff --git a/wasmsdk/blobber_mw.go b/wasmsdk/blobber_mw.go new file mode 100644 index 000000000..1da4a4799 --- /dev/null +++ b/wasmsdk/blobber_mw.go @@ -0,0 +1,213 @@ +//go:build js && wasm +// +build js,wasm + +package main + +import ( + "encoding/json" + "errors" + + "github.com/0chain/gosdk/constants" + "github.com/0chain/gosdk/zboxcore/sdk" +) + +// NOTE: This file provides *MW suffixed* wrappers for several wasm blobber functions +// that accept an additional `key string` parameter (the MultiWalletSupportKey). +// Where the underlying SDK exposes a way to use a per-operation key, the wrapper +// forwards it. Where the SDK does not currently accept a key for that operation, +// the wrapper will either call the existing function (and ignore the key) or +// return an error indicating the key cannot be applied. + +// listObjectsMW lists allocation objects but signs the list request using `key` when provided. +func listObjectsMW(allocationID string, remotePath string, offset, pageLimit int, key string) (*sdk.ListResult, error) { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + if key != "" { + return alloc.ListDir(remotePath, sdk.WithListRequestOffset(offset), sdk.WithListRequestPageLimit(pageLimit), sdk.WithListRequestPubKey(key)) + } + return alloc.ListDir(remotePath, sdk.WithListRequestOffset(offset), sdk.WithListRequestPageLimit(pageLimit)) +} + +// listObjectsFromAuthTicketMW lists allocation objects using an auth ticket and an optional signing key. +func listObjectsFromAuthTicketMW(allocationID, authTicket, lookupHash string, offset, pageLimit int, key string) (*sdk.ListResult, error) { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + if key != "" { + return alloc.ListDirFromAuthTicket(authTicket, lookupHash, sdk.WithListRequestOffset(offset), sdk.WithListRequestPageLimit(pageLimit), sdk.WithListRequestPubKey(key)) + } + return alloc.ListDirFromAuthTicket(authTicket, lookupHash, sdk.WithListRequestOffset(offset), sdk.WithListRequestPageLimit(pageLimit)) +} + +// createDirMW creates a directory and uses the provided key for signing the multi-operation. +func createDirMW(allocationID, remotePath, key string) error { + if allocationID == "" { + return errors.New("allocationID required") + } + if remotePath == "" { + return errors.New("remotePath required") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return err + } + // Use DoMultiOperation and set the MultiWalletSupportKey on the MultiOperation + return allocationObj.DoMultiOperation([]sdk.OperationRequest{{ + OperationType: constants.FileOperationCreateDir, + RemotePath: remotePath, + }}, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) +} + +// DeleteMW deletes a file using the provided MultiWalletSupportKey. +func DeleteMW(allocationID, remotePath, key string) (*FileCommandResponse, error) { + if allocationID == "" { + return nil, RequiredArg("allocationID") + } + if remotePath == "" { + return nil, RequiredArg("remotePath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + + err = allocationObj.DoMultiOperation([]sdk.OperationRequest{{ + OperationType: constants.FileOperationDelete, + RemotePath: remotePath, + }}, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) + if err != nil { + return nil, err + } + resp := &FileCommandResponse{CommandSuccess: true} + return resp, nil +} + +// RenameMW renames a file using the provided key for signing. +func RenameMW(allocationID, remotePath, destName, key string) (*FileCommandResponse, error) { + if allocationID == "" { + return nil, RequiredArg("allocationID") + } + if remotePath == "" { + return nil, RequiredArg("remotePath") + } + if destName == "" { + return nil, RequiredArg("destName") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + + err = allocationObj.DoMultiOperation([]sdk.OperationRequest{{ + OperationType: constants.FileOperationRename, + RemotePath: remotePath, + DestName: destName, + }}, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) + if err != nil { + return nil, err + } + resp := &FileCommandResponse{CommandSuccess: true} + return resp, nil +} + +// CopyMW copies a file and signs using the provided key. +func CopyMW(allocationID, remotePath, destPath, key string) (*FileCommandResponse, error) { + if allocationID == "" { + return nil, RequiredArg("allocationID") + } + if remotePath == "" { + return nil, RequiredArg("remotePath") + } + if destPath == "" { + return nil, RequiredArg("destPath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + + err = allocationObj.DoMultiOperation([]sdk.OperationRequest{{ + OperationType: constants.FileOperationCopy, + RemotePath: remotePath, + DestPath: destPath, + }}, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) + if err != nil { + return nil, err + } + resp := &FileCommandResponse{CommandSuccess: true} + return resp, nil +} + +// MoveMW moves a file and signs using the provided key. +func MoveMW(allocationID, remotePath, destPath, key string) (*FileCommandResponse, error) { + if allocationID == "" { + return nil, RequiredArg("allocationID") + } + if remotePath == "" { + return nil, RequiredArg("remotePath") + } + if destPath == "" { + return nil, RequiredArg("destPath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + + err = allocationObj.DoMultiOperation([]sdk.OperationRequest{{ + OperationType: constants.FileOperationMove, + RemotePath: remotePath, + DestPath: destPath, + }}, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) + if err != nil { + return nil, err + } + resp := &FileCommandResponse{CommandSuccess: true} + return resp, nil +} + +// MultiOperationMW performs multiple operations and signs the whole multi-operation with `key`. +func MultiOperationMW(allocationID string, jsonMultiUploadOptions string, key string) error { + if allocationID == "" { + return errors.New("AllocationID is required") + } + if jsonMultiUploadOptions == "" { + return errors.New("operations are empty") + } + var options []MultiOperationOption + if err := json.Unmarshal([]byte(jsonMultiUploadOptions), &options); err != nil { + return err + } + + totalOp := len(options) + operations := make([]sdk.OperationRequest, totalOp) + for idx, op := range options { + operations[idx] = sdk.OperationRequest{ + OperationType: op.OperationType, + RemotePath: op.RemotePath, + DestName: op.DestName, + DestPath: op.DestPath, + } + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return err + } + return allocationObj.DoMultiOperation(operations, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) +} + +// For other functions in blobber.go that are primarily read-only or don't expose a +// way to set a per-operation signing key in the SDK (for example: GetFileStats, +// GetBlobbers, downloadBlocks, upload wrappers that don't accept a wallet option), +// the SDK currently does not provide a simple way to use the MultiWalletSupportKey. +// Such functions are not implemented here with key-aware behavior and will +// effectively ignore the `key` parameter if a MW wrapper were added that calls +// the existing API. + +// TODO: If you want, I can extend this file with additional MW wrappers (for +// example uploadMW that will use sdk.CreateChunkedUpload with sdk.WithWallet(key)), +// or implement key-aware variants for more of the blobber API. If so, tell me +// which specific functions you'd like prioritized. diff --git a/wasmsdk/cache.go b/wasmsdk/cache.go index 9089015b3..f22fa20e5 100644 --- a/wasmsdk/cache.go +++ b/wasmsdk/cache.go @@ -27,7 +27,7 @@ var ( // if not found in cache, fetch from blockchain // and store in cache // - allocationId is the allocation id -func getAllocation(allocationId string) (*sdk.Allocation, error) { +func getAllocation(allocationId string, keys ...string) (*sdk.Allocation, error) { it, ok := cachedAllocations.Get(allocationId) @@ -37,7 +37,7 @@ func getAllocation(allocationId string) (*sdk.Allocation, error) { } } sdk.SetWasm() - a, err := sdk.GetAllocation(allocationId) + a, err := sdk.GetAllocation(allocationId, keys...) if err != nil { return nil, err } diff --git a/zboxcore/marker/authticket.go b/zboxcore/marker/authticket.go index fd2bc9819..8ef4df08e 100644 --- a/zboxcore/marker/authticket.go +++ b/zboxcore/marker/authticket.go @@ -25,6 +25,7 @@ type AuthTicket struct { Encrypted bool `json:"encrypted"` Signature string `json:"signature"` EncryptionPublicKey string `json:"encryption_public_key"` + MultiWalletSupportKey string `json:"-"` } // NewAuthTicket returns the MPT hash of the AuthTicket @@ -49,6 +50,6 @@ func (at *AuthTicket) GetHashData() string { func (at *AuthTicket) Sign() error { var err error hash := encryption.Hash(at.GetHashData()) - at.Signature, err = client.Sign(hash) + at.Signature, err = client.Sign(hash, at.MultiWalletSupportKey) return err } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 9c1b071c7..540dd94e8 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -446,7 +446,7 @@ func SetDownloadWorkerCount(count int) { } // InitAllocation initializes the allocation. -func (a *Allocation) InitAllocation() { +func (a *Allocation) InitAllocation(keys ...string) { a.downloadChan = make(chan *DownloadRequest, 400) a.repairChan = make(chan *RepairRequest, 1) a.ctx, a.ctxCancelF = context.WithCancel(context.Background()) @@ -467,7 +467,10 @@ func (a *Allocation) InitAllocation() { for _, blobber := range a.Blobbers { addLogChan(blobber.Baseurl) } - a.generateAndSetOwnerSigningPublicKey() + if len(keys) > 0 && keys[0] != "" { + a.MultiWalletSupportKey = keys[0] + } + a.generateAndSetOwnerSigningPublicKey(keys...) a.startWorker(a.ctx) InitCommitWorker(a.Blobbers) InitBlockDownloader(a.Blobbers, downloadWorkerCount) @@ -477,12 +480,8 @@ func (a *Allocation) InitAllocation() { a.initialized = true } -func (a *Allocation) generateAndSetOwnerSigningPublicKey() { - //create ecdsa public key from signature - if a.OwnerPublicKey != client.PublicKey() { - return - } - privateSigningKey, err := GenerateOwnerSigningKey(a.OwnerPublicKey, a.Owner) +func (a *Allocation) generateAndSetOwnerSigningPublicKey(keys ...string) { + privateSigningKey, err := GenerateOwnerSigningKey(a.OwnerPublicKey, a.Owner, keys...) if err != nil { l.Logger.Error("Failed to generate owner signing key", zap.Error(err)) return @@ -490,7 +489,7 @@ func (a *Allocation) generateAndSetOwnerSigningPublicKey() { if a.OwnerSigningPublicKey == "" && !a.Finalized && !a.Canceled && client.Wallet().IsSplit { pubKey := privateSigningKey.Public().(ed25519.PublicKey) a.OwnerSigningPublicKey = hex.EncodeToString(pubKey) - hash, _, err := UpdateAllocation(0, 0, false, a.ID, 0, "", "", "", "", a.OwnerSigningPublicKey, false, nil, "") + hash, _, err := UpdateAllocation(0, 0, false, a.ID, 0, "", "", "", "", a.OwnerSigningPublicKey, false, nil, "", keys...) if err != nil { l.Logger.Error("Failed to update owner signing public key ", err, " allocationID: ", a.ID, " hash: ", hash) return @@ -713,7 +712,7 @@ func (a *Allocation) EncryptAndUploadFileWithThumbnail( // - status: the status callback function. Will be used to gather the status of the upload operations. // // Returns any error encountered during any of the upload operations, or during preparation of the upload operations. -func (a *Allocation) StartMultiUpload(workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback) error { +func (a *Allocation) StartMultiUpload(workdir string, localPaths []string, fileNames []string, thumbnailPaths []string, encrypts []bool, chunkNumbers []int, remotePaths []string, isUpdate []bool, isWebstreaming []bool, status StatusCallback, keys ...string) error { if len(localPaths) != len(thumbnailPaths) { return errors.New("invalid_value", "length of localpaths and thumbnailpaths must be equal") } @@ -809,6 +808,23 @@ func (a *Allocation) StartMultiUpload(workdir string, localPaths []string, fileN } } + + // Determine effective multi-wallet key: prefer allocation default, but + // allow caller-provided key to override when present. + effectiveKey := a.MultiWalletSupportKey + if len(keys) > 0 && keys[0] != "" { + effectiveKey = keys[0] + } + + if effectiveKey != "" { + err := a.DoMultiOperation(operationRequests, func(mo *MultiOperation) { mo.MultiWalletSupportKey = effectiveKey }) + if err != nil { + logger.Logger.Error("Error in multi upload ", err.Error()) + return err + } + return nil + } + err := a.DoMultiOperation(operationRequests) if err != nil { logger.Logger.Error("Error in multi upload ", err.Error()) @@ -931,7 +947,14 @@ func (a *Allocation) GetCurrentVersion() (bool, error) { go func(blobber *blockchain.StorageNode) { defer wg.Done() - wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, a.Owner) + // Prefer allocation-level MultiWalletSupportKey for getting writemarkers + // so that the writemarker returned corresponds to the wallet used for + // signing in multi-wallet setups. Fall back to the allocation owner id. + key := a.Owner + if a.MultiWalletSupportKey != "" { + key = a.MultiWalletSupportKey + } + wr, err := GetWritemarker(a.ID, a.Tx, a.sig, blobber.ID, blobber.Baseurl, key) if err != nil { atomic.AddInt32(&errCnt, 1) logger.Logger.Error("error during getWritemarke", zap.Error(err)) @@ -944,6 +967,7 @@ func (a *Allocation) GetCurrentVersion() (bool, error) { blobber: blobber, lpm: wr, commitResult: &CommitResult{}, + MultiWalletSupportKey: a.MultiWalletSupportKey, } } }(blobber) @@ -1045,6 +1069,7 @@ func (a *Allocation) RepairRequired(remotepath string) (zboxutil.Uint128, zboxut listReq.consensusThresh = a.DataShards listReq.ctx = a.ctx listReq.remotefilepath = remotepath + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey found, deleteMask, fileRef, _ := listReq.getFileConsensusFromBlobbers() if fileRef == nil { var repairErr error @@ -1785,23 +1810,23 @@ func (a *Allocation) getRefs(path, pathHash, authToken, offsetPath, updatedDate, } oTreeReq := &ObjectTreeRequest{ - ClientId: a.Owner, - allocationID: a.ID, - allocationTx: a.Tx, - sig: a.sig, - blobbers: a.Blobbers, - authToken: authToken, - pathHash: pathHash, - remotefilepath: path, - pageLimit: pageLimit, - level: level, - offsetPath: offsetPath, - updatedDate: updatedDate, - offsetDate: offsetDate, - fileType: fileType, - refType: refType, - ctx: a.ctx, - reqMask: zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1), + ClientId: a.Owner, + allocationID: a.ID, + allocationTx: a.Tx, + sig: a.sig, + blobbers: a.Blobbers, + authToken: authToken, + pathHash: pathHash, + remotefilepath: path, + pageLimit: pageLimit, + level: level, + offsetPath: offsetPath, + updatedDate: updatedDate, + offsetDate: offsetDate, + fileType: fileType, + refType: refType, + ctx: a.ctx, + reqMask: zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1), MultiWalletSupportKey: a.MultiWalletSupportKey, } oTreeReq.fullconsensus = a.fullconsensus @@ -2029,6 +2054,7 @@ func (a *Allocation) GetRecentlyAddedRefs(page int, fromDate int64, pageLimit in fullconsensus: a.fullconsensus, consensusThresh: a.consensusThreshold, }, + MultiWalletSupportKey: a.MultiWalletSupportKey, } return req.GetRecentlyAddedRefs() } @@ -2052,6 +2078,7 @@ func (a *Allocation) GetFileMeta(path string) (*ConsolidatedFileMeta, error) { listReq.consensusThresh = a.consensusThreshold listReq.ctx = a.ctx listReq.remotefilepath = path + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey _, _, ref, _ := listReq.getFileConsensusFromBlobbers() if ref != nil { result.Type = ref.Type @@ -2091,6 +2118,7 @@ func (a *Allocation) GetFileMetaByName(fileName string) ([]*ConsolidatedFileMeta listReq.consensusThresh = a.consensusThreshold listReq.ctx = a.ctx listReq.filename = fileName + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey _, _, refs, _ := listReq.getMultipleFileConsensusFromBlobbers() if len(refs) != 0 { for _, ref := range refs { @@ -2173,6 +2201,7 @@ func (a *Allocation) GetFileMetaFromAuthTicket(authTicket string, lookupHash str listReq.ctx = a.ctx listReq.remotefilepathhash = lookupHash listReq.authToken = at + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey _, _, ref, _ := listReq.getFileConsensusFromBlobbers() if ref != nil { result.Type = ref.Type @@ -2218,6 +2247,7 @@ func (a *Allocation) GetFileStats(path string) (map[string]*FileStats, error) { listReq.consensusThresh = a.consensusThreshold listReq.ctx = a.ctx listReq.remotefilepath = path + listReq.MultiWalletSupportKey = a.MultiWalletSupportKey ref := listReq.getFileStatsFromBlobbers() if ref != nil { return ref, nil @@ -2263,6 +2293,7 @@ func (a *Allocation) deleteFile(path string, threshConsensus, fullConsensus int, req.deleteMask = mask req.maskMu = &sync.Mutex{} req.timestamp = int64(common.Now()) + req.MultiWalletSupportKey = a.MultiWalletSupportKey err := req.ProcessDelete() return err } @@ -2300,6 +2331,7 @@ func (a *Allocation) createDir(remotePath string, threshConsensus, fullConsensus fullconsensus: fullConsensus, }, alreadyExists: make(map[uint64]bool), + multiWalletSupportKey: a.MultiWalletSupportKey, } req.ctx, req.ctxCncl = context.WithCancel(a.ctx) @@ -2346,7 +2378,11 @@ func (a *Allocation) RevokeShare(path string, refereeClientID string) error { query.Add("path", path) query.Add("refereeClientID", refereeClientID) - httpreq, err := zboxutil.NewRevokeShareRequest(baseUrl, a.ID, a.Tx, a.sig, query, a.Owner) + key := a.Owner + if a.MultiWalletSupportKey != "" { + key = a.MultiWalletSupportKey + } + httpreq, err := zboxutil.NewRevokeShareRequest(baseUrl, a.ID, a.Tx, a.sig, query, key) if err != nil { return err } @@ -2437,6 +2473,7 @@ func (a *Allocation) GetAuthTicket(path, filename string, remotefilepath: path, remotefilename: filename, signingPrivateKey: a.privateSigningKey, + MultiWalletSupportKey: a.MultiWalletSupportKey, } if referenceType == fileref.DIRECTORY { @@ -2499,7 +2536,11 @@ func (a *Allocation) UploadAuthTicketToBlobber(authTicket string, clientEncPubKe if err := formWriter.Close(); err != nil { return err } - httpreq, err := zboxutil.NewShareRequest(url, a.ID, a.Tx, a.sig, body, a.Owner) + key := a.Owner + if a.MultiWalletSupportKey != "" { + key = a.MultiWalletSupportKey + } + httpreq, err := zboxutil.NewShareRequest(url, a.ID, a.Tx, a.sig, body, key) if err != nil { return err } diff --git a/zboxcore/sdk/filerefsworker.go b/zboxcore/sdk/filerefsworker.go index c9ed9caf4..0c6bbcdec 100644 --- a/zboxcore/sdk/filerefsworker.go +++ b/zboxcore/sdk/filerefsworker.go @@ -365,6 +365,7 @@ type SimilarField struct { type RecentlyAddedRefRequest struct { ctx context.Context ClientId string + MultiWalletSupportKey string allocationID string allocationTx string sig string @@ -444,7 +445,12 @@ func (r *RecentlyAddedRefRequest) GetRecentlyAddedRefs() (*RecentlyAddedRefResul func (r *RecentlyAddedRefRequest) getRecentlyAddedRefs(resp *RecentlyAddedRefResponse, bUrl string) { defer r.wg.Done() - req, err := zboxutil.NewRecentlyAddedRefsRequest(bUrl, r.allocationID, r.allocationTx, r.sig, r.fromDate, r.offset, r.pageLimit, r.ClientId) + // Choose key used to sign the request: prefer MultiWalletSupportKey when set + key := r.ClientId + if r.MultiWalletSupportKey != "" { + key = r.MultiWalletSupportKey + } + req, err := zboxutil.NewRecentlyAddedRefsRequest(bUrl, r.allocationID, r.allocationTx, r.sig, r.fromDate, r.offset, r.pageLimit, key) if err != nil { resp.err = err return diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 637b8caf3..64f789754 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -631,7 +631,7 @@ func GetAllocationFromAuthTicket(authTicket string) (*Allocation, error) { // - allocationID: the allocation id // // returns the allocation instance and error if any -func GetAllocation(allocationID string) (*Allocation, error) { +func GetAllocation(allocationID string, keys ...string) (*Allocation, error) { if !client.IsSDKInitialized() { return nil, sdkNotInitialized } @@ -649,7 +649,7 @@ func GetAllocation(allocationID string) (*Allocation, error) { } allocationObj.numBlockDownloads = numBlockDownloads - allocationObj.InitAllocation() + allocationObj.InitAllocation(keys...) return allocationObj, nil } diff --git a/zboxcore/sdk/sharerequest.go b/zboxcore/sdk/sharerequest.go index 4c2a83071..ea0cda6c0 100644 --- a/zboxcore/sdk/sharerequest.go +++ b/zboxcore/sdk/sharerequest.go @@ -18,6 +18,7 @@ import ( type ShareRequest struct { ClientId string + MultiWalletSupportKey string allocationID string allocationTx string sig string @@ -43,6 +44,7 @@ func (req *ShareRequest) GetFileRef() (*fileref.FileRef, error) { blobbers: req.blobbers, ctx: req.ctx, Consensus: Consensus{RWMutex: &sync.RWMutex{}}, + MultiWalletSupportKey: req.MultiWalletSupportKey, } _, _, fileRef, _ = listReq.getFileConsensusFromBlobbers() if fileRef == nil { @@ -65,6 +67,7 @@ func (req *ShareRequest) getAuthTicket(clientID, encPublicKey string) (*marker.A FilePathHash: fileref.GetReferenceLookup(req.allocationID, req.remotefilepath), RefType: req.refType, ActualFileHash: fRef.ActualFileHash, + MultiWalletSupportKey: req.MultiWalletSupportKey, } at.Timestamp = int64(common.Now()) @@ -85,7 +88,11 @@ func (req *ShareRequest) getAuthTicket(clientID, encPublicKey string) (*marker.A } entropy = hex.EncodeToString(req.signingPrivateKey) } else { - entropy = client.Wallet().Mnemonic + if req.MultiWalletSupportKey != "" { + entropy = client.GetWalletMnemonic(req.MultiWalletSupportKey) + } else { + entropy = client.Wallet().Mnemonic + } } if entropy == "" { return nil, errors.New("wallet_error", "wallet mnemonic is empty") diff --git a/zboxcore/zboxutil/http.go b/zboxcore/zboxutil/http.go index baf25b000..599f6175f 100644 --- a/zboxcore/zboxutil/http.go +++ b/zboxcore/zboxutil/http.go @@ -405,7 +405,7 @@ func NewRefsRequest(baseUrl, allocationID, sig, allocationTx, path, pathHash, au return req, nil } -func NewRecentlyAddedRefsRequest(bUrl, allocID, allocTx, sig string, fromDate, offset int64, pageLimit int, clients ...string) (*http.Request, error) { +func NewRecentlyAddedRefsRequest(bUrl, allocID, allocTx, sig string, fromDate, offset int64, pageLimit int, keys ...string) (*http.Request, error) { nUrl, err := joinUrl(bUrl, RECENT_REFS_ENDPOINT, allocID) if err != nil { @@ -425,7 +425,7 @@ func NewRecentlyAddedRefsRequest(bUrl, allocID, allocTx, sig string, fromDate, o req.Header.Set(ALLOCATION_ID_HEADER, allocID) - if err = setClientInfoWithSign(req, sig, allocTx, bUrl, clients...); err != nil { + if err = setClientInfoWithSign(req, sig, allocTx, bUrl, keys...); err != nil { return nil, err } From b4232ca01383098c64403c245cf0204bf513228c Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 14 Nov 2025 11:32:18 +0530 Subject: [PATCH 32/47] refactor --- zboxcore/sdk/chunked_upload.go | 2 +- zboxcore/sdk/chunked_upload_blobber.go | 16 ++++++++-------- zboxcore/sdk/chunked_upload_model.go | 4 ++-- zboxcore/sdk/chunked_upload_option.go | 2 +- zboxcore/sdk/chunked_upload_process.go | 4 ++-- zboxcore/sdk/upload_worker.go | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/zboxcore/sdk/chunked_upload.go b/zboxcore/sdk/chunked_upload.go index a316888aa..d9fe5fbad 100644 --- a/zboxcore/sdk/chunked_upload.go +++ b/zboxcore/sdk/chunked_upload.go @@ -257,7 +257,7 @@ func CreateChunkedUpload( } - su.writeMarkerMutex, err = CreateWriteMarkerMutex(su.allocationObj, su.pubkey) + su.writeMarkerMutex, err = CreateWriteMarkerMutex(su.allocationObj, su.multiWalletSupportKey) if err != nil { return nil, err } diff --git a/zboxcore/sdk/chunked_upload_blobber.go b/zboxcore/sdk/chunked_upload_blobber.go index 5e3761b43..8fa06323e 100644 --- a/zboxcore/sdk/chunked_upload_blobber.go +++ b/zboxcore/sdk/chunked_upload_blobber.go @@ -71,8 +71,8 @@ func (sb *ChunkedUploadBlobber) sendUploadRequest( eg, _ := errgroup.WithContext(ctx) key := su.allocationObj.Owner - if su.pubkey != "" { - key = su.pubkey + if su.multiWalletSupportKey != "" { + key = su.multiWalletSupportKey } for dataInd := 0; dataInd < len(dataBuffers); dataInd++ { ind := dataInd @@ -227,8 +227,8 @@ func (sb *ChunkedUploadBlobber) processCommit(ctx context.Context, su *ChunkedUp // overwrite ClientID — the blobber expects the write marker ClientID to // match the allocation owner (the uploader identity). wm.ClientID = su.allocationObj.Owner - if su.pubkey != "" { - wm.MultiWalletSupportKey = su.pubkey + if su.multiWalletSupportKey != "" { + wm.MultiWalletSupportKey = su.multiWalletSupportKey } err = wm.Sign() if err != nil { @@ -268,8 +268,8 @@ func (sb *ChunkedUploadBlobber) processCommit(ctx context.Context, su *ChunkedUp // choose signing key: prefer per-operation pubkey if set, otherwise allocation owner key := su.allocationObj.Owner - if su.pubkey != "" { - key = su.pubkey + if su.multiWalletSupportKey != "" { + key = su.multiWalletSupportKey } req, err := zboxutil.NewCommitRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, body, 0, key) if err != nil { @@ -362,8 +362,8 @@ func (sb *ChunkedUploadBlobber) processWriteMarker( var lR ReferencePathResult // choose signing key for reference request: prefer per-operation pubkey if set refKey := su.allocationObj.Owner - if su.pubkey != "" { - refKey = su.pubkey + if su.multiWalletSupportKey != "" { + refKey = su.multiWalletSupportKey } req, err := zboxutil.NewReferencePathRequest(sb.blobber.Baseurl, su.allocationObj.ID, su.allocationObj.Tx, su.allocationObj.sig, paths, refKey) if err != nil || len(paths) == 0 { diff --git a/zboxcore/sdk/chunked_upload_model.go b/zboxcore/sdk/chunked_upload_model.go index 68a66d4bd..ce2649ce2 100644 --- a/zboxcore/sdk/chunked_upload_model.go +++ b/zboxcore/sdk/chunked_upload_model.go @@ -96,8 +96,8 @@ type ChunkedUpload struct { //used in wasm check chunked_upload_process_js.go processMap map[int]zboxutil.Uint128 //nolint:unused //used in wasm check chunked_upload_process_js.go - processMapLock sync.Mutex //nolint:unused - pubkey string + processMapLock sync.Mutex //nolint:unused + multiWalletSupportKey string } // FileMeta metadata of stream input/local diff --git a/zboxcore/sdk/chunked_upload_option.go b/zboxcore/sdk/chunked_upload_option.go index 1ce015c45..8c61e4680 100644 --- a/zboxcore/sdk/chunked_upload_option.go +++ b/zboxcore/sdk/chunked_upload_option.go @@ -39,7 +39,7 @@ func WithThumbnail(buf []byte) ChunkedUploadOption { func WithWallet(w string) ChunkedUploadOption { return func(su *ChunkedUpload) { - su.pubkey = w + su.multiWalletSupportKey = w } } diff --git a/zboxcore/sdk/chunked_upload_process.go b/zboxcore/sdk/chunked_upload_process.go index 94dcb2515..7de989a23 100644 --- a/zboxcore/sdk/chunked_upload_process.go +++ b/zboxcore/sdk/chunked_upload_process.go @@ -107,11 +107,11 @@ func (su *ChunkedUpload) processUpload(chunkStartIndex, chunkEndIndex int, defer wg.Done() var uploadData blobberData var err error - if su.pubkey != "" { + if su.multiWalletSupportKey != "" { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, su.chunkSize, chunkStartIndex, chunkEndIndex, isFinal, su.encryptedKey, su.progress.EncryptedKeyPoint, - fileShards[pos], thumbnailChunkData, su.shardSize, su.pubkey) + fileShards[pos], thumbnailChunkData, su.shardSize, su.multiWalletSupportKey) } else { uploadData, err = su.formBuilder.Build( &su.fileMeta, blobber.progress.Hasher, su.progress.ConnectionID, blobber.blobber.ID, diff --git a/zboxcore/sdk/upload_worker.go b/zboxcore/sdk/upload_worker.go index 147b73fd7..82440289b 100644 --- a/zboxcore/sdk/upload_worker.go +++ b/zboxcore/sdk/upload_worker.go @@ -36,7 +36,7 @@ func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([ err := allocObj.DownloadFileToFileHandler(f, uo.chunkedUpload.fileMeta.RemotePath, false, nil, true, WithFileCallback(func() { f.Close() //nolint:errcheck }), func(dr *DownloadRequest) { - dr.MultiWalletSupportKey = uo.chunkedUpload.pubkey + dr.MultiWalletSupportKey = uo.chunkedUpload.multiWalletSupportKey }) if err != nil { l.Logger.Error("DownloadFileToFileHandler Failed", zap.String("path", uo.chunkedUpload.fileMeta.RemotePath), zap.Error(err)) From 941f12557f64035b0a65ca425798aa54219f89e8 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 14 Nov 2025 12:27:03 +0530 Subject: [PATCH 33/47] add logs --- zboxcore/sdk/chunked_upload_form_builder.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zboxcore/sdk/chunked_upload_form_builder.go b/zboxcore/sdk/chunked_upload_form_builder.go index d21ad8f80..3702bed10 100644 --- a/zboxcore/sdk/chunked_upload_form_builder.go +++ b/zboxcore/sdk/chunked_upload_form_builder.go @@ -13,6 +13,7 @@ import ( "github.com/0chain/gosdk/core/client" "github.com/0chain/gosdk/core/encryption" + l "github.com/0chain/gosdk/zboxcore/logger" "golang.org/x/crypto/sha3" ) @@ -267,6 +268,13 @@ func (b *chunkedUploadFormBuilder) Build( return res, err } + // Log upload metadata for debugging signature/validation issues + var keyUsed string + if len(keys) > 0 { + keyUsed = keys[0] + } + l.Logger.Info("uploadMeta prepared", "blobber", blobberID, "connection_id", connectionID, "key", keyUsed, "uploadMeta", string(uploadMeta)) + err = formWriter.WriteField("uploadMeta", string(uploadMeta)) if err != nil { return res, err From 37dc8d8f39bc40add579c68b2414fd8f6df9d3a4 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 14 Nov 2025 13:41:46 +0530 Subject: [PATCH 34/47] upload fix --- core/client/set.go | 2 +- zboxcore/sdk/allocation.go | 52 +++++++++++++++++++++++----------- zboxcore/sdk/chunked_upload.go | 1 + 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 09da56a59..2956b4867 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -486,7 +486,7 @@ func PublicKey(keys ...string) string { client.mu.RLock() if client.wallets != nil { if w, ok := client.wallets[keys[0]]; ok && w != nil { - k := w.Keys[0].PublicKey + k := w.ClientKey client.mu.RUnlock() return k } diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 540dd94e8..06f130f73 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -475,18 +475,35 @@ func (a *Allocation) InitAllocation(keys ...string) { InitCommitWorker(a.Blobbers) InitBlockDownloader(a.Blobbers, downloadWorkerCount) if a.StorageVersion == StorageV2 && a.OwnerPublicKey == client.PublicKey(a.Owner) { - a.CheckAllocStatus() //nolint:errcheck + a.CheckAllocStatus(keys...) //nolint:errcheck } a.initialized = true } func (a *Allocation) generateAndSetOwnerSigningPublicKey(keys ...string) { + l.Logger.Info("a.OwnerPublicKey:", a.OwnerPublicKey, " client.PublicKey(keys...):", client.PublicKey(keys...)) + //create ecdsa public key from signature + if a.OwnerPublicKey != client.PublicKey(keys...) { + return + } + + wallet := client.Wallet() + if len(keys) > 0 && keys[0] != "" { + wallet = client.GetWalletByKey(keys[0]) + if wallet == nil { + l.Logger.Error("multi-wallet-settings err ", keys[0]) + return + } + } + + privateSigningKey, err := GenerateOwnerSigningKey(a.OwnerPublicKey, a.Owner, keys...) if err != nil { l.Logger.Error("Failed to generate owner signing key", zap.Error(err)) return } - if a.OwnerSigningPublicKey == "" && !a.Finalized && !a.Canceled && client.Wallet().IsSplit { + l.Logger.Info("privateSigningKey: ", privateSigningKey) + if a.OwnerSigningPublicKey == "" && !a.Finalized && !a.Canceled && wallet.IsSplit { pubKey := privateSigningKey.Public().(ed25519.PublicKey) a.OwnerSigningPublicKey = hex.EncodeToString(pubKey) hash, _, err := UpdateAllocation(0, 0, false, a.ID, 0, "", "", "", "", a.OwnerSigningPublicKey, false, nil, "", keys...) @@ -503,6 +520,7 @@ func (a *Allocation) generateAndSetOwnerSigningPublicKey(keys ...string) { return } a.privateSigningKey = privateSigningKey + l.Logger.Info("a.privateSigningKey ", a.privateSigningKey) } func (a *Allocation) isInitialized() bool { @@ -963,10 +981,10 @@ func (a *Allocation) GetCurrentVersion() (bool, error) { markerChan <- nil } else { markerChan <- &RollbackBlobber{ - ClientId: a.Owner, - blobber: blobber, - lpm: wr, - commitResult: &CommitResult{}, + ClientId: a.Owner, + blobber: blobber, + lpm: wr, + commitResult: &CommitResult{}, MultiWalletSupportKey: a.MultiWalletSupportKey, } } @@ -2330,7 +2348,7 @@ func (a *Allocation) createDir(remotePath string, threshConsensus, fullConsensus consensusThresh: threshConsensus, fullconsensus: fullConsensus, }, - alreadyExists: make(map[uint64]bool), + alreadyExists: make(map[uint64]bool), multiWalletSupportKey: a.MultiWalletSupportKey, } req.ctx, req.ctxCncl = context.WithCancel(a.ctx) @@ -2463,16 +2481,16 @@ func (a *Allocation) GetAuthTicket(path, filename string, } shareReq := &ShareRequest{ - ClientId: a.Owner, - expirationSeconds: expiration, - allocationID: a.ID, - allocationTx: a.Tx, - sig: a.sig, - blobbers: a.Blobbers, - ctx: a.ctx, - remotefilepath: path, - remotefilename: filename, - signingPrivateKey: a.privateSigningKey, + ClientId: a.Owner, + expirationSeconds: expiration, + allocationID: a.ID, + allocationTx: a.Tx, + sig: a.sig, + blobbers: a.Blobbers, + ctx: a.ctx, + remotefilepath: path, + remotefilename: filename, + signingPrivateKey: a.privateSigningKey, MultiWalletSupportKey: a.MultiWalletSupportKey, } diff --git a/zboxcore/sdk/chunked_upload.go b/zboxcore/sdk/chunked_upload.go index d9fe5fbad..c08db0836 100644 --- a/zboxcore/sdk/chunked_upload.go +++ b/zboxcore/sdk/chunked_upload.go @@ -293,6 +293,7 @@ func CreateChunkedUpload( su.chunkReader = cReader + logger.Logger.Info("CreateChunkedUploadFormBuilder storageVersion", su.allocationObj.StorageVersion, " and encryptedVersion ", su.encryptionVersion, "and privateSigningKey ", su.allocationObj.privateSigningKey) su.formBuilder = CreateChunkedUploadFormBuilder(su.allocationObj.StorageVersion, su.encryptionVersion, su.allocationObj.privateSigningKey) su.isRepair = isRepair From c2b500e28b145fef93690064457c50b36b31008d Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sun, 16 Nov 2025 21:33:37 +0530 Subject: [PATCH 35/47] provide blobber multi-wallet operations wasm --- wasmsdk/allocation_mw.go | 5 + wasmsdk/blobber_mw.go | 648 ++++++++++++++++++++++++++ wasmsdk/proxy.go | 35 ++ wasmsdk/sdk.go | 13 + zboxcore/sdk/allocation.go | 4 +- zboxcore/sdk/chunked_upload_option.go | 10 + zboxcore/sdk/downloader.go | 9 +- zboxcore/sdk/downloader_option.go | 8 + zboxcore/sdk/reader.go | 1 + zboxcore/sdk/sdk.go | 4 +- zcncore/execute_transactions.go | 12 +- 11 files changed, 737 insertions(+), 12 deletions(-) create mode 100644 wasmsdk/allocation_mw.go diff --git a/wasmsdk/allocation_mw.go b/wasmsdk/allocation_mw.go new file mode 100644 index 000000000..ec098b2db --- /dev/null +++ b/wasmsdk/allocation_mw.go @@ -0,0 +1,5 @@ +//go:build js && wasm +// +build js,wasm + +package main + diff --git a/wasmsdk/blobber_mw.go b/wasmsdk/blobber_mw.go index 1da4a4799..eb2c2cff1 100644 --- a/wasmsdk/blobber_mw.go +++ b/wasmsdk/blobber_mw.go @@ -4,11 +4,26 @@ package main import ( + "bytes" + "context" "encoding/json" "errors" + "fmt" + "path" + "strings" + "sync" + "syscall/js" + "time" "github.com/0chain/gosdk/constants" + "github.com/0chain/gosdk/core/encryption" + "github.com/0chain/gosdk/core/pathutil" + "github.com/0chain/gosdk/core/sys" + "github.com/0chain/gosdk/core/transaction" + "github.com/0chain/gosdk/wasmsdk/jsbridge" + "github.com/0chain/gosdk/zboxcore/fileref" "github.com/0chain/gosdk/zboxcore/sdk" + "github.com/0chain/gosdk/zboxcore/zboxutil" ) // NOTE: This file provides *MW suffixed* wrappers for several wasm blobber functions @@ -199,6 +214,639 @@ func MultiOperationMW(allocationID string, jsonMultiUploadOptions string, key st return allocationObj.DoMultiOperation(operations, func(mo *sdk.MultiOperation) { mo.MultiWalletSupportKey = key }) } +// multiDownloadMW - start multi-download operation with per-op key support. +func multiDownloadMW(allocationID, jsonMultiDownloadOptions, authTicket, callbackFuncName, key string) (string, error) { + defer func() { + if r := recover(); r != nil { + PrintError("Recovered in multiDownload Error", r) + } + }() + wg := &sync.WaitGroup{} + useCallback := false + if callbackFuncName != "" { + useCallback = true + } + var options []*MultiDownloadOption + err := json.Unmarshal([]byte(jsonMultiDownloadOptions), &options) + if err != nil { + return "", err + } + var alloc *sdk.Allocation + if authTicket == "" { + alloc, err = getAllocation(allocationID, key) + } else { + alloc, err = sdk.GetAllocationFromAuthTicket(authTicket, key) + } + if err != nil { + return "", err + } + allStatusBar := make([]*StatusBar, len(options)) + wg.Add(len(options)) + for ind, option := range options { + fileName := strings.Replace(path.Base(option.RemotePath), "/", "-", -1) + localPath := allocationID + "_" + fileName + option.LocalPath = localPath + statusBar := &StatusBar{wg: wg, totalBytesMap: make(map[string]int)} + allStatusBar[ind] = statusBar + if useCallback { + callback := js.Global().Get(callbackFuncName) + statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { + callback.Invoke(totalBytes, completedBytes, filename, objURL, err) + } + } + var mf sys.File + if option.DownloadToDisk { + if option.SuggestedName != "" { + fileName = option.SuggestedName + } + mf, err = jsbridge.NewFileWriter(fileName) + if err != nil { + PrintError(err.Error()) + return "", err + } + } else { + statusBar.localPath = localPath + fs, _ := sys.Files.Open(localPath) + mf, _ = fs.(*sys.MemFile) + } + + var downloader sdk.Downloader + if option.DownloadOp == 1 { + downloader, err = sdk.CreateDownloader(allocationID, localPath, option.RemotePath, + sdk.WithAllocation(alloc), + sdk.WithAuthticket(authTicket, option.RemoteLookupHash), + sdk.WithOnlyThumbnail(false), + sdk.WithBlocks(0, 0, option.NumBlocks), + sdk.WithFileHandler(mf), + sdk.WithDownloadPubKey(key), + ) + } else { + downloader, err = sdk.CreateDownloader(allocationID, localPath, option.RemotePath, + sdk.WithAllocation(alloc), + sdk.WithAuthticket(authTicket, option.RemoteLookupHash), + sdk.WithOnlyThumbnail(true), + sdk.WithBlocks(0, 0, option.NumBlocks), + sdk.WithFileHandler(mf), + sdk.WithDownloadPubKey(key), + ) + } + if err != nil { + PrintError(err.Error()) + return "", err + } + defer sys.Files.Remove(option.LocalPath) //nolint + downloader.Start(statusBar, ind == len(options)-1) + } + wg.Wait() + resp := make([]DownloadCommandResponse, len(options)) + for ind, statusBar := range allStatusBar { + statusResponse := DownloadCommandResponse{} + if !statusBar.success { + statusResponse.CommandSuccess = false + statusResponse.Error = "Download failed: " + statusBar.err.Error() + } else { + statusResponse.CommandSuccess = true + statusResponse.FileName = options[ind].RemoteFileName + statusResponse.Url = statusBar.objURL + } + resp[ind] = statusResponse + } + respBytes, err := json.Marshal(resp) + if err != nil { + return "", err + } + return string(respBytes), nil +} + +// uploadMW uploads a single file using the provided per-op key when fetching the allocation. +func uploadMW(allocationID, remotePath string, fileBytes, thumbnailBytes []byte, webStreaming, encrypt, isUpdate, isRepair bool, numBlocks int, key string) (*FileCommandResponse, error) { + if len(allocationID) == 0 { + return nil, RequiredArg("allocationID") + } + if len(remotePath) == 0 { + return nil, RequiredArg("remotePath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + PrintError("Error fetching the allocation", err) + return nil, err + } + wg := &sync.WaitGroup{} + statusBar := &StatusBar{wg: wg, totalBytesMap: make(map[string]int)} + wg.Add(1) + fileReader := bytes.NewReader(fileBytes) + localPath := remotePath + remotePath = zboxutil.RemoteClean(remotePath) + isabs := zboxutil.IsRemoteAbs(remotePath) + if !isabs { + err = errors.New("invalid_path: Path should be valid and absolute") + return nil, err + } + remotePath = zboxutil.GetFullRemotePath(localPath, remotePath) + _, fileName := pathutil.Split(remotePath) + mimeType, err := zboxutil.GetFileContentType(path.Ext(fileName), fileReader) + if err != nil { + return nil, err + } + fileMeta := sdk.FileMeta{ + Path: localPath, + ActualSize: int64(len(fileBytes)), + MimeType: mimeType, + RemoteName: fileName, + RemotePath: remotePath, + } + if numBlocks < 1 { + numBlocks = 100 + } + if allocationObj.DataShards > 7 { + numBlocks = 50 + } + ChunkedUpload, err := sdk.CreateChunkedUpload(context.TODO(), "/", allocationObj, fileMeta, fileReader, isUpdate, isRepair, webStreaming, + zboxutil.NewConnectionId(), + sdk.WithThumbnail(thumbnailBytes), + sdk.WithEncrypt(encrypt), + sdk.WithStatusCallback(statusBar), + sdk.WithChunkNumber(numBlocks), + sdk.WithUploadPubKey(key), + ) + if err != nil { + return nil, err + } + err = ChunkedUpload.Start() + if err != nil { + PrintError("Upload failed.", err) + return nil, err + } + wg.Wait() + if !statusBar.success { + return nil, errors.New("upload failed: unknown") + } + resp := &FileCommandResponse{CommandSuccess: true} + return resp, nil +} + + +// multiUploadMW uploads multiple files in parallel using per-op key when selecting the allocation. +func multiUploadMW(jsonBulkUploadOptions string, key string) ([]BulkUploadResult, error) { + var options []BulkUploadOption + err := json.Unmarshal([]byte(jsonBulkUploadOptions), &options) + if err != nil { + return nil, err + } + n := len(options) + if n == 0 { + return nil, errors.New("No files to upload") + } + allocationID := options[0].AllocationID + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + err = addWebWorkers(allocationObj) + if err != nil { + return nil, err + } + wait := make(chan BulkUploadResult, 1) + for _, option := range options { + go func(o BulkUploadOption) { + result := BulkUploadResult{RemotePath: o.RemotePath} + defer func() { wait <- result }() + + ok, err := uploadWithJsFuncsWithKey(o.AllocationID, o.RemotePath, o.ReadChunkFuncName, o.FileSize, o.ThumbnailBytes.Buffer, o.IsWebstreaming, o.Encrypt, o.IsUpdate, o.IsRepair, o.NumBlocks, o.CallbackFuncName, key) + + result.Success = ok + if err != nil { + result.Error = err.Error() + result.Success = false + } + }(option) + } + results := make([]BulkUploadResult, 0, n) + for i := 0; i < n; i++ { + result := <-wait + results = append(results, result) + } + return results, nil +} + +// uploadWithJsFuncsWithKey mirrors uploadWithJsFuncs but allows passing per-op key when fetching allocation. +func uploadWithJsFuncsWithKey(allocationID, remotePath string, readChunkFuncName string, fileSize int64, thumbnailBytes []byte, webStreaming, encrypt, isUpdate, isRepair bool, numBlocks int, callbackFuncName string, key string) (bool, error) { + if len(allocationID) == 0 { + return false, RequiredArg("allocationID") + } + if len(remotePath) == 0 { + return false, RequiredArg("remotePath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + PrintError("Error fetching the allocation", err) + return false, err + } + wg := &sync.WaitGroup{} + statusBar := &StatusBar{wg: wg, totalBytesMap: make(map[string]int)} + if callbackFuncName != "" { + callback := js.Global().Get(callbackFuncName) + statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { + callback.Invoke(totalBytes, completedBytes, filename, objURL, err) + } + } + wg.Add(1) + + fileReader, err := jsbridge.NewFileReader(readChunkFuncName, fileSize, allocationObj.GetChunkReadSize(encrypt)) + if err != nil { + return false, err + } + + localPath := remotePath + remotePath = zboxutil.RemoteClean(remotePath) + isabs := zboxutil.IsRemoteAbs(remotePath) + if !isabs { + err = errors.New("invalid_path: Path should be valid and absolute") + return false, err + } + remotePath = zboxutil.GetFullRemotePath(localPath, remotePath) + + _, fileName := pathutil.Split(remotePath) + + mimeType, err := zboxutil.GetFileContentType(path.Ext(fileName), fileReader) + if err != nil { + return false, err + } + + fileMeta := sdk.FileMeta{ + Path: localPath, + ActualSize: fileSize, + MimeType: mimeType, + RemoteName: fileName, + RemotePath: remotePath, + } + + if numBlocks < 1 { + numBlocks = 100 + } + if allocationObj.DataShards > 7 { + numBlocks = 50 + } + + ChunkedUpload, err := sdk.CreateChunkedUpload(context.TODO(), "/", allocationObj, fileMeta, fileReader, isUpdate, isRepair, webStreaming, zboxutil.NewConnectionId(), + sdk.WithThumbnail(thumbnailBytes), + sdk.WithEncrypt(encrypt), + sdk.WithStatusCallback(statusBar), + sdk.WithChunkNumber(numBlocks), + sdk.WithUploadPubKey(key), + ) + if err != nil { + return false, err + } + + err = ChunkedUpload.Start() + if err != nil { + PrintError("Upload failed.", err) + return false, err + } + + wg.Wait() + if !statusBar.success { + return false, errors.New("upload failed: unknown") + } + + return true, nil +} + +// cancelUploadMW cancels an upload using the provided key when fetching the allocation. +func cancelUploadMW(allocationID, remotePath, key string) error { + if allocationID == "" { + return errors.New("allocationID required") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return err + } + return allocationObj.CancelUpload(remotePath) +} + +// pauseUploadMW pauses an upload using the provided key when fetching the allocation. +func pauseUploadMW(allocationID, remotePath, key string) error { + if allocationID == "" { + return errors.New("allocationID required") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return err + } + return allocationObj.PauseUpload(remotePath) +} + +// getFileStatsMW returns file stats and allows selecting the wallet via key. +func getFileStatsMW(allocationID, remotePath, key string) ([]*sdk.FileStats, error) { + if allocationID == "" { + return nil, RequiredArg("allocationID") + } + if remotePath == "" { + return nil, RequiredArg("remotePath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + m, err := allocationObj.GetFileStats(remotePath) + if err != nil { + return nil, err + } + var stats []*sdk.FileStats + for _, v := range m { + stats = append(stats, v) + } + return stats, nil +} + +// updateBlobberSettingsMW updates blobber settings. The underlying SDK call does not accept a per-op key +// so the key parameter is ignored here (kept for API symmetry). +func updateBlobberSettingsMW(blobberSettingsJson string, key string) (*transaction.Transaction, error) { + // Forward to existing implementation (no per-op key supported in SDK wrapper) + return updateBlobberSettings(blobberSettingsJson) +} + +// ShareMW generates an auth ticket and uses the provided key when acquiring the allocation. +func ShareMW(allocationID, remotePath, clientID, encryptionPublicKey string, expiration int, revoke bool, availableAfter string, key string) (string, error) { + if allocationID == "" { + return "", RequiredArg("allocationID") + } + if remotePath == "" { + return "", RequiredArg("remotePath") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return "", err + } + if revoke { + if err := allocationObj.RevokeShare(remotePath, clientID); err != nil { + return "", err + } + return "", nil + } + availableAt := time.Now() + ref, err := allocationObj.GetAuthTicket(remotePath, path.Base(remotePath), fileref.DIRECTORY, clientID, encryptionPublicKey, int64(expiration), &availableAt) + if err != nil { + return "", err + } + return ref, nil +} + +// getFileMetaByNameMW wraps getFileMetaByName and supports selecting the allocation via key. +func getFileMetaByNameMW(allocationID, fileNameQuery, key string) ([]*sdk.ConsolidatedFileMetaByName, error) { + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + return allocationObj.GetFileMetaByName(fileNameQuery) +} + +// getFileMetaByAuthTicketMW wraps getFileMetaByAuthTicket and supports selecting the allocation via key. +func getFileMetaByAuthTicketMW(allocationID, authTicket, lookupHash, key string) (*sdk.ConsolidatedFileMeta, error) { + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + return allocationObj.GetFileMetaFromAuthTicket(authTicket, lookupHash) +} + +// downloadBlocksMW downloads blocks and supports selecting allocation via key. +func downloadBlocksMW(allocId, remotePath, authTicket, lookupHash, writeChunkFuncName string, startBlock, endBlock int64, key string) ([]byte, error) { + return downloadBlocksWithKey(allocId, remotePath, authTicket, lookupHash, writeChunkFuncName, startBlock, endBlock, key) +} + +// repairAllocationMW repairs allocation using provided key for allocation selection. +func repairAllocationMW(allocationID, callbackFuncName, key string) error { + return repairAllocationWithKey(allocationID, callbackFuncName, key) +} + +// checkAllocStatusMW checks allocation status and supports key for allocation selection. +func checkAllocStatusMW(allocationID, key string) (string, error) { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return "", err + } + status, _, err := alloc.CheckAllocStatus(key) + var statusStr string + switch status { + case sdk.Repair: + statusStr = "repair" + case sdk.Broken: + statusStr = "broken" + default: + statusStr = "ok" + } + return statusStr, err +} + +// skipStatusCheckMW sets the check status flag on the allocation, using the provided key. +func skipStatusCheckMW(allocationID string, checkStatus bool, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + alloc.SetCheckStatus(checkStatus) + return nil +} + +// terminateWorkersMW cancels workers for an allocation using provided key. +func terminateWorkersMW(allocationID, key string) { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return + } + terminateWorkersWithAllocation(alloc) +} + +// createWorkersMW creates workers for allocation using provided key. +func createWorkersMW(allocationID, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + return addWebWorkers(alloc) +} + +// downloadDirectoryMW downloads a directory; uses provided key to select allocation. +func downloadDirectoryMW(allocationID, remotePath, authticket, callbackFuncName, key string) error { + return downloadDirectoryWithKey(allocationID, remotePath, authticket, callbackFuncName, key) +} + +// cancelDownloadDirectoryMW cancels a directory download; key ignored. +func cancelDownloadDirectoryMW(remotePath, key string) { + cancelDownloadDirectory(remotePath) +} + +// cancelDownloadBlocksMW cancels download blocks for allocation using provided key. +func cancelDownloadBlocksMW(allocationID, remotePath string, start, end int64, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + return alloc.CancelDownloadBlocks(remotePath, start, end) +} + +// setConsensusThresholdMW sets consensus threshold using provided key to find allocation. +func setConsensusThresholdMW(allocationID string, threshold int, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + alloc.SetConsensusThreshold(threshold) + return nil +} + +// downloadBlocks downloads file blocks using an optional per-op key when fetching the allocation. +func downloadBlocksWithKey(allocId, remotePath, authTicket, lookupHash, writeChunkFuncName string, startBlock, endBlock int64, key string) ([]byte, error) { + + if len(remotePath) == 0 && len(authTicket) == 0 { + return nil, RequiredArg("remotePath/authTicket") + } + + alloc, err := getAllocation(allocId, key) + if err != nil { + PrintError("Error fetching the allocation", err) + return nil, err + } + + var ( + wg = &sync.WaitGroup{} + statusBar = &StatusBar{wg: wg, totalBytesMap: make(map[string]int)} + ) + + if lookupHash == "" { + lookupHash = getLookupHash(allocId, remotePath) + } + + var fh sys.File + if writeChunkFuncName == "" { + pathHash := encryption.FastHash(fmt.Sprintf("%s:%d:%d", lookupHash, startBlock, endBlock)) + fs, err := sys.Files.Open(pathHash) + if err != nil { + return nil, fmt.Errorf("could not open local file: %v", err) + } + + mf, _ := fs.(*sys.MemFile) + if mf == nil { + return nil, fmt.Errorf("invalid memfile") + } + fh = mf + defer sys.Files.Remove(pathHash) //nolint + } else { + fh = jsbridge.NewFileCallbackWriter(writeChunkFuncName, lookupHash) + if fh == nil { + return nil, fmt.Errorf("could not create file writer, callback function not found") + } + } + + wg.Add(1) + if authTicket != "" { + err = alloc.DownloadByBlocksToFileHandlerFromAuthTicket(fh, authTicket, lookupHash, startBlock, endBlock, 100, remotePath, false, statusBar, true, sdk.WithFileCallback( + func() { + fh.Close() //nolint:errcheck + }, + )) + } else { + err = alloc.DownloadByBlocksToFileHandler( + fh, + remotePath, + startBlock, + endBlock, + 100, + false, + statusBar, true, sdk.WithFileCallback( + func() { + fh.Close() //nolint:errcheck + }, + )) + } + if err != nil { + return nil, err + } + wg.Wait() + var buf []byte + if mf, ok := fh.(*sys.MemFile); ok { + buf = mf.Buffer + } + return buf, nil +} + +// repairAllocation repairs the allocation using an optional per-op key for allocation lookup. +func repairAllocationWithKey(allocationID, callbackFuncName, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + err = addWebWorkers(alloc) + if err != nil { + return err + } + wg := &sync.WaitGroup{} + statusBar := &StatusBar{wg: wg, isRepair: true, totalBytesMap: make(map[string]int)} + wg.Add(1) + if callbackFuncName != "" { + callback := js.Global().Get(callbackFuncName) + statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { + callback.Invoke(totalBytes, completedBytes, filename, objURL, err) + } + } + err = alloc.RepairAlloc(statusBar) + if err != nil { + return err + } + wg.Wait() + if statusBar.err != nil { + fmt.Println("Error in repair allocation: ", statusBar.err) + return statusBar.err + } + status, _, err := alloc.CheckAllocStatus() + if err != nil { + return err + } + if status == sdk.Repair || status == sdk.Broken { + fmt.Println("allocation repair failed") + return errors.New("allocation repair failed") + } + return nil +} + +// downloadDirectory downloads directory to local file system using fs api, will only work in browsers where fs api is available +// It uses the provided per-op key when selecting the allocation. +func downloadDirectoryWithKey(allocationID, remotePath, authticket, callbackFuncName, key string) error { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return err + } + wg := &sync.WaitGroup{} + wg.Add(1) + statusBar := &StatusBar{wg: wg, totalBytesMap: make(map[string]int)} + if callbackFuncName != "" { + callback := js.Global().Get(callbackFuncName) + statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { + callback.Invoke(totalBytes, completedBytes, filename, objURL, err) + } + } + ctx, cancel := context.WithCancelCause(context.Background()) + defer cancel(nil) + errChan := make(chan error, 1) + go func() { + errChan <- alloc.DownloadDirectory(ctx, remotePath, "", authticket, statusBar) + }() + downloadDirLock.Lock() + downloadDirContextMap[remotePath] = cancel + downloadDirLock.Unlock() + select { + case err = <-errChan: + if err != nil { + PrintError("Error in download directory: ", err) + } + return err + case <-ctx.Done(): + return context.Cause(ctx) + } +} + // For other functions in blobber.go that are primarily read-only or don't expose a // way to set a per-operation signing key in the SDK (for example: GetFileStats, // GetBlobbers, downloadBlocks, upload wrappers that don't accept a wallet option), diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index ec56f3ec0..70ccbe17c 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -261,6 +261,41 @@ func main() { "cancelDownloadBlocks": cancelDownloadBlocks, "setConsensusThreshold": setConsensusThreshold, + //blobber mw (multi-wallet support) + "deleteMW": DeleteMW, + "shareMW": ShareMW, + "multiDownloadMW": multiDownloadMW, + "uploadMW": uploadMW, + // "setUploadModeMW": setUploadModeMW, + "multiUploadMW": multiUploadMW, + "multiOperationMW": MultiOperationMW, + "listObjectsMW": listObjectsMW, + "listObjectsFromAuthTicketMW": listObjectsFromAuthTicketMW, + "createDirMW": createDirMW, + "downloadBlocksMW": downloadBlocksMW, + "getFileStatsMW": getFileStatsMW, + "updateBlobberSettingsMW": updateBlobberSettingsMW, + // "getRemoteFileMapMW": getRemoteFileMapMW, + // "getBlobbersMW": getBlobbersMW, + // "getcontainersMW": GetContainersMW, + // "updatecontainerMW": UpdateContainerMW, + // "searchcontainerMW": SearchContainerMW, + // "updateForbidAllocationMW": UpdateForbidAllocationMW, + "sendMW": sendMW, + "cancelUploadMW": cancelUploadMW, + "pauseUploadMW": pauseUploadMW, + "repairAllocationMW": repairAllocationMW, + "checkAllocStatusMW": checkAllocStatusMW, + "skipStatusCheckMW": skipStatusCheckMW, + "terminateWorkersMW": terminateWorkersMW, + "createWorkersMW": createWorkersMW, + "getFileMetaByNameMW": getFileMetaByNameMW, + "getFileMetaByAuthTicketMW": getFileMetaByAuthTicketMW, + "downloadDirectoryMW": downloadDirectoryMW, + "cancelDownloadDirectoryMW": cancelDownloadDirectoryMW, + "cancelDownloadBlocksMW": cancelDownloadBlocksMW, + "setConsensusThresholdMW": setConsensusThresholdMW, + // player "play": play, "stop": stop, diff --git a/wasmsdk/sdk.go b/wasmsdk/sdk.go index 07f9974ad..485ef2f4e 100644 --- a/wasmsdk/sdk.go +++ b/wasmsdk/sdk.go @@ -178,3 +178,16 @@ func send(toClientID string, tokens uint64, fee uint64, desc string) (string, er } return txn.TransactionOutput, nil } + +// send Send tokens to a client +// - toClientID is the client id to send tokens to +// - tokens is the number of tokens to send +// - fee is the transaction fee +// - desc is the description of the transaction +func sendMW(toClientID string, tokens uint64, fee uint64, desc string, key string) (string, error) { + _, _, _, txn, err := zcncore.Send(toClientID, tokens, desc, key) + if err != nil { + return "", err + } + return txn.TransactionOutput, nil +} diff --git a/zboxcore/sdk/allocation.go b/zboxcore/sdk/allocation.go index 06f130f73..89244cd9b 100644 --- a/zboxcore/sdk/allocation.go +++ b/zboxcore/sdk/allocation.go @@ -3391,7 +3391,7 @@ func (a *Allocation) UpdateWithStatus( } l.Logger.Info("Updating allocation") - hash, _, err := UpdateAllocation(size, authRoundExpiry, extend, a.ID, lock, addBlobberId, addBlobberAuthTicket, removeBlobberId, "", ownerSigninPublicKey, setThirdPartyExtendable, fileOptionsParams, updateAllocTicket) + hash, _, err := UpdateAllocation(size, authRoundExpiry, extend, a.ID, lock, addBlobberId, addBlobberAuthTicket, removeBlobberId, "", ownerSigninPublicKey, setThirdPartyExtendable, fileOptionsParams, updateAllocTicket, a.MultiWalletSupportKey) if err != nil { return alloc, "", isRepairRequired, err } @@ -3402,7 +3402,7 @@ func (a *Allocation) UpdateWithStatus( deadline := time.Now().Add(1 * time.Minute) for time.Now().Before(deadline) { - alloc, err = GetAllocation(a.ID) + alloc, err = GetAllocation(a.ID, a.MultiWalletSupportKey) if err != nil { l.Logger.Error("failed to get allocation") return alloc, hash, isRepairRequired, err diff --git a/zboxcore/sdk/chunked_upload_option.go b/zboxcore/sdk/chunked_upload_option.go index 8c61e4680..046af6e65 100644 --- a/zboxcore/sdk/chunked_upload_option.go +++ b/zboxcore/sdk/chunked_upload_option.go @@ -43,6 +43,16 @@ func WithWallet(w string) ChunkedUploadOption { } } +// WithUploadPubKey sets the per-operation public key used for owner-signing +// and request-level signing during chunked uploads. It's an alias for +// WithWallet but provides a clearer name for callers that want to set the +// upload-specific public key. +func WithUploadPubKey(pubKey string) ChunkedUploadOption { + return func(su *ChunkedUpload) { + su.multiWalletSupportKey = pubKey + } +} + // WithThumbnailFile add thumbnail from file. stream mode is unnecessary for thumbnail. // - fileName: file name of the thumbnail, which will be read and uploaded func WithThumbnailFile(fileName string) ChunkedUploadOption { diff --git a/zboxcore/sdk/downloader.go b/zboxcore/sdk/downloader.go index b2aa4062f..cef47bb7f 100644 --- a/zboxcore/sdk/downloader.go +++ b/zboxcore/sdk/downloader.go @@ -23,6 +23,7 @@ type DownloadOptions struct { localPath string remotePath string + MultiWalletSupportKey string isViewer bool authTicket string @@ -63,12 +64,16 @@ func CreateDownloader(allocationID, localPath, remotePath string, opts ...Downlo var err error if do.allocationObj == nil { if do.isViewer { - do.allocationObj, err = GetAllocationFromAuthTicket(do.authTicket) + do.allocationObj, err = GetAllocationFromAuthTicket(do.authTicket, do.MultiWalletSupportKey) if err != nil { return nil, err } } else { - do.allocationObj, err = GetAllocation(allocationID) + if do.MultiWalletSupportKey != "" { + do.allocationObj, err = GetAllocation(allocationID, do.MultiWalletSupportKey) + } else { + do.allocationObj, err = GetAllocation(allocationID) + } if err != nil { return nil, err } diff --git a/zboxcore/sdk/downloader_option.go b/zboxcore/sdk/downloader_option.go index 0dca50557..8faf23d5a 100644 --- a/zboxcore/sdk/downloader_option.go +++ b/zboxcore/sdk/downloader_option.go @@ -74,3 +74,11 @@ func WithFileHandler(fileHandler sys.File) DownloadOption { do.isFileHandlerDownload = true } } + +// WithDownloadPubKey sets the per-operation public key that should be used +// for owner-signing and request-level signing during downloads. +func WithDownloadPubKey(pubKey string) DownloadOption { + return func(do *DownloadOptions) { + do.MultiWalletSupportKey = pubKey + } +} diff --git a/zboxcore/sdk/reader.go b/zboxcore/sdk/reader.go index ae005b369..f6a8efa1b 100644 --- a/zboxcore/sdk/reader.go +++ b/zboxcore/sdk/reader.go @@ -190,6 +190,7 @@ func GetDStorageFileReader(alloc *Allocation, ref *ORef, sdo *StreamDownloadOpti chunkSize: BlockSize, maskMu: &sync.Mutex{}, connectionID: zboxutil.NewConnectionId(), + MultiWalletSupportKey: alloc.MultiWalletSupportKey, }, open: true, } diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index 64f789754..cb439bb4d 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -610,7 +610,7 @@ func GetClientEncryptedPublicKey() (string, error) { // - authTicket: the auth ticket hash // // returns the allocation instance and error if any -func GetAllocationFromAuthTicket(authTicket string) (*Allocation, error) { +func GetAllocationFromAuthTicket(authTicket string, keys ...string) (*Allocation, error) { if !client.IsSDKInitialized() { return nil, sdkNotInitialized } @@ -623,7 +623,7 @@ func GetAllocationFromAuthTicket(authTicket string) (*Allocation, error) { if err != nil { return nil, errors.New("auth_ticket_decode_error", "Error unmarshaling the auth ticket."+err.Error()) } - return GetAllocation(at.AllocationID) + return GetAllocation(at.AllocationID, keys...) } // GetAllocation - get allocation from given allocation id diff --git a/zcncore/execute_transactions.go b/zcncore/execute_transactions.go index 5a75ddde8..0b31e23e1 100644 --- a/zcncore/execute_transactions.go +++ b/zcncore/execute_transactions.go @@ -202,17 +202,17 @@ type SendTxnData struct { Note string `json:"note"` } -func Send(toClientID string, tokens uint64, desc string, client ...string) (hash, out string, nonce int64, txn *transaction.Transaction, err error) { - if len(client) == 0 { - client = append(client, "") - client = append(client, toClientID) +func Send(toClientID string, tokens uint64, desc string, keys ...string) (hash, out string, nonce int64, txn *transaction.Transaction, err error) { + if len(keys) == 0 { + keys = append(keys, "") + keys = append(keys, toClientID) } else { - client = append(client, toClientID) + keys = append(keys, toClientID) } return transaction.SmartContractTxnValue(MinerSmartContractAddress, transaction.SmartContractTxnData{ Name: "transfer", InputArgs: SendTxnData{Note: desc}, - }, tokens, true, client...) + }, tokens, true, keys...) } func Faucet(tokens uint64, input string, client ...string) (hash, out string, nonce int64, txn *transaction.Transaction, err error) { From 2b190c27f27d38886533960df2740d6b8d18ed3e Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 17 Nov 2025 16:20:23 +0530 Subject: [PATCH 36/47] allocation wasm functions --- wasmsdk/allocation_mw.go | 382 +++++++++++++++++++++++++++++ wasmsdk/blobber_mw.go | 12 - wasmsdk/proxy.go | 22 +- zboxcore/sdk/blobber_operations.go | 11 +- zboxcore/sdk/sdk.go | 34 ++- 5 files changed, 434 insertions(+), 27 deletions(-) diff --git a/wasmsdk/allocation_mw.go b/wasmsdk/allocation_mw.go index ec098b2db..027a6bbf8 100644 --- a/wasmsdk/allocation_mw.go +++ b/wasmsdk/allocation_mw.go @@ -3,3 +3,385 @@ package main +import ( + "errors" + "strings" + "sync" + "syscall/js" + "time" + + "github.com/0chain/gosdk/core/transaction" + "github.com/0chain/gosdk/wasmsdk/jsbridge" + "github.com/0chain/gosdk/zboxcore/sdk" +) + +// MW (multi-wallet) variants of allocation helpers. Each function accepts an +// additional `key string` argument (the multi-wallet support key). When the +// underlying SDK supports explicit key-based signing (via variadic keys) the +// key is forwarded. When selecting an allocation object the cached helper +// `getAllocation(allocationID, key)` is used to select the allocation for that +// key. + +// createfreeallocationMW creates a free allocation +func createfreeallocationMW(freeStorageMarker string, key string) (string, error) { + allocationID, _, err := sdk.CreateFreeAllocation(freeStorageMarker, 0, key) + if err != nil { + sdkLogger.Error("Error creating free allocation: ", err) + return "", err + } + return allocationID, err +} + +// getAllocationBlobbersMW retrieves allocation blobbers (key is ignored) +func getAllocationBlobbersMW(preferredBlobberURLs []string, + dataShards, parityShards int, size int64, + minReadPrice, maxReadPrice, minWritePrice, maxWritePrice int64, isRestricted int, force bool, key string) ([]string, error) { + + if len(preferredBlobberURLs) > 0 { + return sdk.GetBlobberIds(preferredBlobberURLs) + } + + return sdk.GetAllocationBlobbers(sdk.StorageV2, dataShards, parityShards, size, isRestricted, sdk.PriceRange{ + Min: uint64(minReadPrice), + Max: uint64(maxReadPrice), + }, sdk.PriceRange{ + Min: uint64(minWritePrice), + Max: uint64(maxWritePrice), + }, force) +} + +// getBlobberIdsMW retrieves blobber ids from the given blobber urls (key ignored) +func getBlobberIdsMW(blobberUrls []string, key string) ([]string, error) { + return sdk.GetBlobberIds(blobberUrls) +} + +// reloadAllocationMW reload allocation from blockchain and update cache (supports key) +func reloadAllocationMW(allocationID, key string) (*sdk.Allocation, error) { + a, err := sdk.GetAllocation(allocationID, key) + if err != nil { + return nil, err + } + + it := &cachedAllocation{ + Allocation: a, + Expiration: time.Now().Add(5 * time.Minute), + } + + cachedAllocations.Add(allocationID, it) + + return it.Allocation, nil +} + +// createAllocationMW creates an allocation given allocation creation parameters +func createAllocationMW(datashards, parityshards int, size, authRoundExpiry int64, + minReadPrice, maxReadPrice, minWritePrice, maxWritePrice int64, lock int64, blobberIds, blobberAuthTickets []string, setThirdPartyExtendable, IsEnterprise, force bool, key string) ( + *transaction.Transaction, error) { + + options := sdk.CreateAllocationOptions{ + DataShards: datashards, + ParityShards: parityshards, + Size: size, + ReadPrice: sdk.PriceRange{ + Min: uint64(minReadPrice), + Max: uint64(maxReadPrice), + }, + WritePrice: sdk.PriceRange{ + Min: uint64(minWritePrice), + Max: uint64(maxWritePrice), + }, + Lock: uint64(lock), + BlobberIds: blobberIds, + ThirdPartyExtendable: setThirdPartyExtendable, + IsEnterprise: IsEnterprise, + StorageVersion: sdk.StorageV2, + BlobberAuthTickets: blobberAuthTickets, + Force: force, + AuthRoundExpiry: authRoundExpiry, + } + + sdkLogger.Info(options) + _, _, txn, err := sdk.CreateAllocationWith(options, key) + return txn, err +} + +// listAllocationsMW retrieves the list of allocations owned by the client +func listAllocationsMW(key string) ([]*sdk.Allocation, error) { + return sdk.GetAllocations(key) +} + +// transferAllocationMW transfers the ownership of an allocation to a new owner +func transferAllocationMW(allocationID, newOwnerId, newOwnerPublicKey, key string) error { + if allocationID == "" { + return RequiredArg("allocationID") + } + if newOwnerId == "" { + return RequiredArg("newOwnerId") + } + if newOwnerPublicKey == "" { + return RequiredArg("newOwnerPublicKey") + } + + _, _, err := sdk.TransferAllocation(allocationID, newOwnerId, newOwnerPublicKey, key) + if err == nil { + clearAllocation(allocationID) + } + return err +} + +// UpdateForbidAllocationMW updates allocation file options with optional key +func UpdateForbidAllocationMW(allocationID string, forbidupload, forbiddelete, forbidupdate, forbidmove, forbidcopy, forbidrename bool, key string) (string, error) { + fop := &sdk.FileOptionsParameters{ + ForbidUpload: sdk.FileOptionParam{Changed: forbidupload, Value: forbidupload}, + ForbidDelete: sdk.FileOptionParam{Changed: forbiddelete, Value: forbiddelete}, + ForbidUpdate: sdk.FileOptionParam{Changed: forbidupdate, Value: forbidupdate}, + ForbidMove: sdk.FileOptionParam{Changed: forbidmove, Value: forbidmove}, + ForbidCopy: sdk.FileOptionParam{Changed: forbidcopy, Value: forbidcopy}, + ForbidRename: sdk.FileOptionParam{Changed: forbidrename, Value: forbidrename}, + } + + hash, _, err := sdk.UpdateAllocation(0, 0, false, allocationID, 0, "", "", "", "", "", false, fop, "", key) + return hash, err +} + +// freezeAllocationMW freezes one of the client's allocations +func freezeAllocationMW(allocationID, key string) (string, error) { + hash, _, err := sdk.UpdateAllocation(0, 0, false, allocationID, 0, "", "", "", "", "", false, &sdk.FileOptionsParameters{ + ForbidUpload: sdk.FileOptionParam{Changed: true, Value: true}, + ForbidDelete: sdk.FileOptionParam{Changed: true, Value: true}, + ForbidUpdate: sdk.FileOptionParam{Changed: true, Value: true}, + ForbidMove: sdk.FileOptionParam{Changed: true, Value: true}, + ForbidCopy: sdk.FileOptionParam{Changed: true, Value: true}, + ForbidRename: sdk.FileOptionParam{Changed: true, Value: true}, + }, "", key) + if err == nil { + clearAllocation(allocationID) + } + return hash, err +} + +// cancelAllocationMW cancels one of the client's allocations +func cancelAllocationMW(allocationID, key string) (string, error) { + hash, _, err := sdk.CancelAllocation(allocationID, key) + if err == nil { + clearAllocation(allocationID) + } + return hash, err +} + +// updateAllocationWithRepairMW updates the allocation settings and repairs if necessary +func updateAllocationWithRepairMW(allocationID string, + size, authRoundExpiry int64, + extend bool, + lock int64, + addBlobberId, addBlobberAuthTicket, removeBlobberId, ownerSigninPublicKey, updateAllocTicket, callbackFuncName, key string) (string, error) { + + sdk.SetWasm() + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return "", err + } + + wg := &sync.WaitGroup{} + statusBar := &StatusBar{wg: wg, isRepair: true, totalBytesMap: make(map[string]int)} + wg.Add(1) + if callbackFuncName != "" { + callback := js.Global().Get(callbackFuncName) + statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { + callback.Invoke(totalBytes, completedBytes, filename, objURL, err) + } + } + + alloc, hash, isRepairRequired, err := allocationObj.UpdateWithStatus(size, authRoundExpiry, extend, uint64(lock), addBlobberId, addBlobberAuthTicket, removeBlobberId, ownerSigninPublicKey, false, &sdk.FileOptionsParameters{}, updateAllocTicket) + if err != nil { + return hash, err + } + clearAllocation(allocationID) + + if isRepairRequired { + addWebWorkers(alloc) + if removeBlobberId != "" { + jsbridge.RemoveWorker(removeBlobberId) + } + err := alloc.RepairAlloc(statusBar) + if err != nil { + return "", err + } + wg.Wait() + if statusBar.err != nil { + return "", statusBar.err + } + } + + return hash, err +} + +// updateAllocationMW updates the allocation settings +func updateAllocationMW(allocationID string, + size, authRoundExpiry int64, extend bool, + lock int64, + addBlobberId, addBlobberAuthTicket, removeBlobberId, ownerSigninPublicKey string, setThirdPartyExtendable bool, key string) (string, error) { + + hash, _, err := sdk.UpdateAllocation(size, authRoundExpiry, extend, allocationID, uint64(lock), addBlobberId, addBlobberAuthTicket, removeBlobberId, "", ownerSigninPublicKey, setThirdPartyExtendable, &sdk.FileOptionsParameters{}, "", key) + if err == nil { + clearAllocation(allocationID) + } + return hash, err +} + +// getUpdateAllocTicketMW forwards key to SDK's GetUpdateAllocTicket +func getUpdateAllocTicketMW(allocationID, userID, operationType string, roundExpiry int64, key string) (string, error) { + return sdk.GetUpdateAllocTicket(allocationID, userID, operationType, roundExpiry, key) +} + +// getAllocationMW returns allocation for given id using the provided key (if any) +func getAllocationMW(allocationID, key string) (*sdk.Allocation, error) { + return getAllocation(allocationID, key) +} + +// getAllocationMinLockMW retrieves the minimum lock value for allocation creation. +// The `key` parameter is accepted for API symmetry but not forwarded because the +// underlying SDK call does not require a signing key for this computation. +func getAllocationMinLockMW(datashards, parityshards int, + size int64, + maxwritePrice uint64, + key string, +) (int64, error) { + writePrice := sdk.PriceRange{Min: 0, Max: maxwritePrice} + + value, err := sdk.GetAllocationMinLock(datashards, parityshards, size, writePrice) + if err != nil { + sdkLogger.Error(err) + return 0, err + } + sdkLogger.Info("allocation Minlock value", value) + return value, nil +} + +// getUpdateAllocationMinLockMW retrieves the minimum lock value required for an allocation update. +// The `key` parameter is accepted for API symmetry but is not used because the SDK +// function does not require a signing key. +func getUpdateAllocationMinLockMW( + allocationID string, + size int64, + extend bool, + addBlobberId, removeBlobberId, key string) (int64, error) { + return sdk.GetUpdateAllocationMinLock(allocationID, size, extend, addBlobberId, removeBlobberId) +} + +// getRemoteFileMapMW list all files in an allocation from the blobbers. +func getRemoteFileMapMW(allocationID string, key string) ([]*fileResp, error) { + if len(allocationID) == 0 { + return nil, RequiredArg("allocationID") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return nil, err + } + + ref, err := allocationObj.GetRemoteFileMap(nil, "/") + if err != nil { + sdkLogger.Error(err) + return nil, err + } + + fileResps := make([]*fileResp, 0) + for path, data := range ref { + paths := strings.SplitAfter(path, "/") + var resp = fileResp{ + Name: paths[len(paths)-1], + Path: path, + FileInfo: data, + } + fileResps = append(fileResps, &resp) + } + + return fileResps, nil +} + +// lockWritePoolMW locks given number of tokens for duration in write pool +func lockWritePoolMW(allocID string, tokens, fee uint64, key string) (string, error) { + hash, _, err := sdk.WritePoolLock(allocID, tokens, fee, key) + return hash, err +} + +// lockStakePoolMW stake number of tokens for a given provider +func lockStakePoolMW(providerType, tokens, fee uint64, providerID string, key string) (string, error) { + hash, _, err := sdk.StakePoolLock(sdk.ProviderType(providerType), providerID, tokens, fee, key) + return hash, err +} + +// unlockStakePoolMW unlocks stake pool +func unlockStakePoolMW(providerType, fee uint64, providerID, clientID, key string) (int64, error) { + unstake, _, err := sdk.StakePoolUnlock(sdk.ProviderType(providerType), providerID, clientID, fee, key) + return unstake, err +} + +// collectRewardsMW collects rewards +func collectRewardsMW(providerType int, providerID, key string) (string, error) { + hash, _, err := sdk.CollectRewards(providerID, sdk.ProviderType(providerType), key) + return hash, err +} + +// getSkatePoolInfoMW gets stake pool info +func getSkatePoolInfoMW(providerType int, providerID, key string) (*sdk.StakePoolInfo, error) { + info, err := sdk.GetStakePoolInfo(sdk.ProviderType(providerType), providerID, key) + if err != nil { + return nil, err + } + return info, err +} + +// getAllocationWithMW retrieves allocation with auth ticket and optional key +func getAllocationWithMW(authTicket, key string) (*sdk.Allocation, error) { + sdk.SetWasm() + sdkAllocation, err := sdk.GetAllocationFromAuthTicket(authTicket, key) + if err != nil { + return nil, err + } + return sdkAllocation, err +} + +// convertTokenToSASMW converts tokens in ZCN to SAS. +func convertTokenToSASMW(token float64, key string) uint64 { + return uint64(token * float64(TOKEN_UNIT)) +} + +// allocationRepairMW issue repair process for an allocation +func allocationRepairMW(allocationID, remotePath, key string) error { + if len(allocationID) == 0 { + return RequiredArg("allocationID") + } + allocationObj, err := getAllocation(allocationID, key) + if err != nil { + return err + } + sdk.SetWasm() + wg := &sync.WaitGroup{} + statusBar := &StatusBar{wg: wg, isRepair: true, totalBytesMap: make(map[string]int)} + wg.Add(1) + + err = allocationObj.StartRepair("/tmp", remotePath, statusBar) + if err != nil { + PrintError("Upload failed.", err) + return err + } + wg.Wait() + if !statusBar.success { + return errors.New("upload failed: unknown") + } + return nil +} + +// repairSizeMW retrieves the repair size for a specific path in an allocation +func repairSizeMW(allocationID, remotePath, key string) (sdk.RepairSize, error) { + alloc, err := getAllocation(allocationID, key) + if err != nil { + return sdk.RepairSize{}, err + } + return alloc.RepairSize(remotePath) +} + +// generateOwnerSigningKeyMW generates owner signing key (key is ignored) +func generateOwnerSigningKeyMW(ownerPublicKey, ownerID, key string) (string, error) { + return sdk.GenerateOwnerSigningPublicKey(key) +} diff --git a/wasmsdk/blobber_mw.go b/wasmsdk/blobber_mw.go index eb2c2cff1..057d78cac 100644 --- a/wasmsdk/blobber_mw.go +++ b/wasmsdk/blobber_mw.go @@ -847,15 +847,3 @@ func downloadDirectoryWithKey(allocationID, remotePath, authticket, callbackFunc } } -// For other functions in blobber.go that are primarily read-only or don't expose a -// way to set a per-operation signing key in the SDK (for example: GetFileStats, -// GetBlobbers, downloadBlocks, upload wrappers that don't accept a wallet option), -// the SDK currently does not provide a simple way to use the MultiWalletSupportKey. -// Such functions are not implemented here with key-aware behavior and will -// effectively ignore the `key` parameter if a MW wrapper were added that calls -// the existing API. - -// TODO: If you want, I can extend this file with additional MW wrappers (for -// example uploadMW that will use sdk.CreateChunkedUpload with sdk.WithWallet(key)), -// or implement key-aware variants for more of the blobber API. If so, tell me -// which specific functions you'd like prioritized. diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index 70ccbe17c..c912b4b44 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -275,12 +275,12 @@ func main() { "downloadBlocksMW": downloadBlocksMW, "getFileStatsMW": getFileStatsMW, "updateBlobberSettingsMW": updateBlobberSettingsMW, - // "getRemoteFileMapMW": getRemoteFileMapMW, + "getRemoteFileMapMW": getRemoteFileMapMW, // "getBlobbersMW": getBlobbersMW, // "getcontainersMW": GetContainersMW, // "updatecontainerMW": UpdateContainerMW, // "searchcontainerMW": SearchContainerMW, - // "updateForbidAllocationMW": UpdateForbidAllocationMW, + "updateForbidAllocationMW": UpdateForbidAllocationMW, "sendMW": sendMW, "cancelUploadMW": cancelUploadMW, "pauseUploadMW": pauseUploadMW, @@ -319,6 +319,24 @@ func main() { "createfreeallocation": createfreeallocation, "getUpdateAllocTicket": getUpdateAllocTicket, + //allocation mw (multi-wallet support) + "createAllocationMW": createAllocationMW, + "getAllocationBlobbersMW": getAllocationBlobbersMW, + "getBlobberIdsMW": getBlobberIdsMW, + "listAllocationsMW": listAllocationsMW, + "getAllocationMW": getAllocationMW, + "reloadAllocationMW": reloadAllocationMW, + "transferAllocationMW": transferAllocationMW, + "freezeAllocationMW": freezeAllocationMW, + "cancelAllocationMW": cancelAllocationMW, + "updateAllocationMW": updateAllocationMW, + "updateAllocationWithRepairMW": updateAllocationWithRepairMW, + "getAllocationMinLockMW": getAllocationMinLockMW, + "getUpdateAllocationMinLockMW": getUpdateAllocationMinLockMW, + "getAllocationWithMW": getAllocationWithMW, + "createfreeallocationMW": createfreeallocationMW, + "getUpdateAllocTicketMW": getUpdateAllocTicketMW, + // claim rewards "collectRewards": collectRewards, diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index ebf82747e..1d4198f3f 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -401,7 +401,16 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string, signingPubKey ...st return privateSigningKey, nil } -func GenerateOwnerSigningPublicKey() (string, error) { +func GenerateOwnerSigningPublicKey(keys ...string) (string, error) { + if len(keys) > 0 && keys[0] != "" { + privateSigningKey, err := GenerateOwnerSigningKey(client.PublicKey(keys...), client.Id(keys...), keys...) + if err != nil { + return "", err + } + + pubKey := privateSigningKey.Public().(ed25519.PublicKey) + return hex.EncodeToString(pubKey), nil + } privateSigningKey, err := GenerateOwnerSigningKey(client.PublicKey(), client.Id()) if err != nil { return "", err diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index cb439bb4d..d9a9c5b56 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -172,7 +172,7 @@ type StakePoolInfo struct { // GetStakePoolInfo retrieve stake pool info for the current client configured to the sdk, given provider type and provider ID. // - providerType: provider type // - providerID: provider ID -func GetStakePoolInfo(providerType ProviderType, providerID string) (info *StakePoolInfo, err error) { +func GetStakePoolInfo(providerType ProviderType, providerID string, keys ...string) (info *StakePoolInfo, err error) { if !client.IsSDKInitialized() { return nil, sdkNotInitialized } @@ -724,7 +724,10 @@ func SetNumBlockDownloads(num int) { // GetAllocations - get all allocations for the current client // // returns the list of allocations and error if any -func GetAllocations() ([]*Allocation, error) { +func GetAllocations(keys ...string) ([]*Allocation, error) { + if len(keys) > 0 && keys[0] != "" { + return GetAllocationsForClient(client.Id(keys...)) + } return GetAllocationsForClient(client.Id()) } @@ -820,9 +823,16 @@ type CreateAllocationOptions struct { // - options is the options struct instance for creating the allocation. // // returns the hash of the new_allocation_request transaction, the nonce of the transaction, the transaction object and an error if any. -func CreateAllocationWith(options CreateAllocationOptions) ( +func CreateAllocationWith(options CreateAllocationOptions, keys ...string) ( string, int64, *transaction.Transaction, error) { + if len(keys) > 0 && keys[0] != "" { + return CreateAllocationForOwner( + client.Id(keys...), client.PublicKey(keys...), "", options.DataShards, options.ParityShards, + options.Size, options.ReadPrice, options.WritePrice, options.Lock, + options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams, options.AuthRoundExpiry) + } + return CreateAllocationForOwner(client.Id(), client.PublicKey(), "", options.DataShards, options.ParityShards, options.Size, options.ReadPrice, options.WritePrice, options.Lock, @@ -1042,7 +1052,7 @@ func FinalizeAllocation(allocID string) (hash string, nonce int64, err error) { // - allocID is the id of the allocation. // // returns the hash of the transaction, the nonce of the transaction and an error if any. -func CancelAllocation(allocID string) (hash string, nonce int64, err error) { +func CancelAllocation(allocID string, keys ...string) (hash string, nonce int64, err error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } @@ -1050,7 +1060,7 @@ func CancelAllocation(allocID string) (hash string, nonce int64, err error) { Name: transaction.STORAGESC_CANCEL_ALLOCATION, InputArgs: map[string]interface{}{"allocation_id": allocID}, } - hash, _, nonce, _, err = storageSmartContractTxn(sn) + hash, _, nonce, _, err = storageSmartContractTxn(sn, keys...) return } @@ -1121,7 +1131,7 @@ func ShutdownProvider(providerType ProviderType, providerID string) (string, int // CollectRewards collects the rewards for a provider (txn: `storagesc.collect_reward`) // - providerId is the id of the provider. // - providerType is the type of the provider. -func CollectRewards(providerId string, providerType ProviderType) (string, int64, error) { +func CollectRewards(providerId string, providerType ProviderType, keys ...string) (string, int64, error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } @@ -1150,7 +1160,7 @@ func CollectRewards(providerId string, providerType ProviderType) (string, int64 return "", 0, fmt.Errorf("collect rewards provider type %v not implimented", providerType) } - hash, _, n, _, err := transaction.SmartContractTxn(scAddress, sn, true) + hash, _, n, _, err := transaction.SmartContractTxn(scAddress, sn, true, keys...) return hash, n, err } @@ -1161,12 +1171,12 @@ func CollectRewards(providerId string, providerType ProviderType) (string, int64 // - newOwnerPublicKey is the public key of the new owner. // // returns the hash of the transaction, the nonce of the transaction and an error if any. -func TransferAllocation(allocationId, newOwner, newOwnerPublicKey string) (string, int64, error) { +func TransferAllocation(allocationId, newOwner, newOwnerPublicKey string, keys ...string) (string, int64, error) { if !client.IsSDKInitialized() { return "", 0, sdkNotInitialized } - alloc, err := GetAllocation(allocationId) + alloc, err := GetAllocation(allocationId, keys...) if err != nil { return "", 0, allocationNotFound } @@ -1188,7 +1198,7 @@ func TransferAllocation(allocationId, newOwner, newOwnerPublicKey string) (strin Name: transaction.STORAGESC_UPDATE_ALLOCATION, InputArgs: allocationRequest, } - hash, _, n, _, err := storageSmartContractTxn(sn) + hash, _, n, _, err := storageSmartContractTxn(sn, keys...) return hash, n, err } @@ -1285,10 +1295,10 @@ func StorageSmartContractTxn(sn transaction.SmartContractTxnData) ( return storageSmartContractTxnValue(sn, 0) } -func storageSmartContractTxn(sn transaction.SmartContractTxnData) ( +func storageSmartContractTxn(sn transaction.SmartContractTxnData, keys ...string) ( hash, out string, nonce int64, txn *transaction.Transaction, err error) { - return storageSmartContractTxnValue(sn, 0) + return storageSmartContractTxnValue(sn, 0, keys...) } func storageSmartContractTxnValue(sn transaction.SmartContractTxnData, value uint64, keys ...string) ( From 22ac1398c12f262e69538941c8c533d28e22547f Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 17 Nov 2025 19:06:24 +0530 Subject: [PATCH 37/47] player and add wallets wasm --- wasmsdk/player_file.go | 15 +++++++--- wasmsdk/player_mw.go | 61 ++++++++++++++++++++++++++++++++++++++++ wasmsdk/player_stream.go | 7 +++-- wasmsdk/proxy.go | 7 +++++ wasmsdk/sdk.go | 22 +++++++++++++++ 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 wasmsdk/player_mw.go diff --git a/wasmsdk/player_file.go b/wasmsdk/player_file.go index 82de0d4c8..bbe0aae04 100644 --- a/wasmsdk/player_file.go +++ b/wasmsdk/player_file.go @@ -23,6 +23,9 @@ type FilePlayer struct { authTicketObj *marker.AuthTicket playlistFile *sdk.PlaylistFile + // mwKey is the multi-wallet key used for per-op signing/selection. + mwKey string + downloadedChunks chan []byte downloadedLen int ctx context.Context @@ -66,7 +69,7 @@ func (p *FilePlayer) download(startBlock int64) { } fmt.Println("start:", startBlock, "end:", endBlock, "numBlocks:", p.numBlocks, "total:", p.playlistFile.NumBlocks) - data, err := downloadBlocks(p.allocationObj.ID, p.remotePath, p.authTicket, p.lookupHash, "", startBlock, endBlock) + data, err := downloadBlocksWithKey(p.allocationObj.ID, p.remotePath, p.authTicket, p.lookupHash, "", startBlock, endBlock, p.mwKey) // data, err := downloadBlocks2(int(startBlock), int(endBlock), p.allocationObj, p.remotePath) if err != nil { PrintError(err.Error()) @@ -159,7 +162,8 @@ func (p *FilePlayer) GetNext() []byte { } // createFilePalyer create player for remotePath -func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string) (*FilePlayer, error) { +// accepts optional keys varargs to support multi-wallet selection when fetching allocations +func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string, keys ...string) (*FilePlayer, error) { player := &FilePlayer{} player.prefetchQty = 3 player.remotePath = remotePath @@ -167,6 +171,9 @@ func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string) ( player.lookupHash = lookupHash player.numBlocks = 10 player.allocationID = allocationID + if len(keys) > 0 { + player.mwKey = keys[0] + } //player is viewer if len(authTicket) > 0 { @@ -178,7 +185,7 @@ func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string) ( return nil, err } - allocationObj, err := sdk.GetAllocationFromAuthTicket(authTicket) + allocationObj, err := sdk.GetAllocationFromAuthTicket(authTicket, keys...) if err != nil { PrintError("Error fetching the allocation", err) return nil, err @@ -197,7 +204,7 @@ func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string) ( return nil, RequiredArg("allocationID") } - allocationObj, err := sdk.GetAllocation(allocationID) + allocationObj, err := getAllocation(allocationID, keys...) if err != nil { PrintError("Error fetching the allocation", err) return nil, err diff --git a/wasmsdk/player_mw.go b/wasmsdk/player_mw.go new file mode 100644 index 000000000..e25321fb8 --- /dev/null +++ b/wasmsdk/player_mw.go @@ -0,0 +1,61 @@ +//go:build js && wasm +// +build js,wasm + +package main + +import "errors" + +var currentPlayerMW Player + +// play starts playing a playable file or stream +// - allocationID is the allocation id +// - remotePath is the remote path of the file or stream +// - authTicket is the auth ticket, in case of accessing as a shared file +// - lookupHash is the lookup hash for the file +// - isLive is the flag to indicate if the file is live or not +// +// playMW starts playing a playable file or stream and accepts a key for multi-wallet signing. +func playMW(allocationID, remotePath, authTicket, lookupHash string, isLive bool, key string) error { + var err error + + if currentPlayerMW != nil { + currentPlayerMW.Stop() + currentPlayerMW = nil + } + + if isLive { + currentPlayerMW, err = createStreamPalyer(allocationID, remotePath, authTicket, lookupHash, key) + if err != nil { + return err + } + + } else { + currentPlayerMW, err = createFilePalyer(allocationID, remotePath, authTicket, lookupHash, key) + if err != nil { + return err + } + } + + return currentPlayerMW.Start() + +} + +// stop stops the current player +func stopMW() error { + if currentPlayerMW != nil { + currentPlayerMW.Stop() + } + + currentPlayerMW = nil + + return nil +} + +// getNextSegment gets the next segment of the current player +func getNextSegmentMW() ([]byte, error) { + if currentPlayerMW == nil { + return nil, errors.New("No player is available") + } + + return currentPlayerMW.GetNext(), nil +} diff --git a/wasmsdk/player_stream.go b/wasmsdk/player_stream.go index 51c844e20..2dc80c1ec 100644 --- a/wasmsdk/player_stream.go +++ b/wasmsdk/player_stream.go @@ -209,7 +209,8 @@ func (p *StreamPlayer) GetNext() []byte { } // createStreamPalyer create player for remotePath -func createStreamPalyer(allocationID, remotePath, authTicket, lookupHash string) (*StreamPlayer, error) { +// accepts optional keys varargs to support multi-wallet selection when fetching allocations +func createStreamPalyer(allocationID, remotePath, authTicket, lookupHash string, keys ...string) (*StreamPlayer, error) { player := &StreamPlayer{} player.prefetchQty = 3 @@ -227,7 +228,7 @@ func createStreamPalyer(allocationID, remotePath, authTicket, lookupHash string) return nil, err } - allocationObj, err := sdk.GetAllocationFromAuthTicket(authTicket) + allocationObj, err := sdk.GetAllocationFromAuthTicket(authTicket, keys...) if err != nil { PrintError("Error fetching the allocation", err) return nil, err @@ -246,7 +247,7 @@ func createStreamPalyer(allocationID, remotePath, authTicket, lookupHash string) return nil, RequiredArg("allocationID") } - allocationObj, err := sdk.GetAllocation(allocationID) + allocationObj, err := getAllocation(allocationID, keys...) if err != nil { PrintError("Error fetching the allocation", err) return nil, err diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index c912b4b44..0e23a13b8 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -225,6 +225,8 @@ func main() { "createThumbnail": createThumbnail, "makeSCRestAPICall": makeSCRestAPICall, "wasmType": getWasmType, + "addWallet": addWallet, + "removeWallet": removeWallet, //blobber "delete": Delete, @@ -301,6 +303,11 @@ func main() { "stop": stop, "getNextSegment": getNextSegment, + // player mw + "playMW": playMW, + "stopMW": stopMW, + "getNextSegmentMW": getNextSegmentMW, + //allocation "createAllocation": createAllocation, "getAllocationBlobbers": getAllocationBlobbers, diff --git a/wasmsdk/sdk.go b/wasmsdk/sdk.go index 485ef2f4e..e3e71c3bc 100644 --- a/wasmsdk/sdk.go +++ b/wasmsdk/sdk.go @@ -15,6 +15,7 @@ import ( "github.com/0chain/gosdk/core/screstapi" "github.com/0chain/gosdk/zboxcore/sdk" "github.com/0chain/gosdk/zcncore" + "github.com/0chain/gosdk/core/zcncrypto" "io" "os" @@ -191,3 +192,24 @@ func sendMW(toClientID string, tokens uint64, fee uint64, desc string, key strin } return txn.TransactionOutput, nil } + +// addWallet adds a new wallet to the SDK (used by wasm bindings). +func addWallet(clientID, clientKey, peerPublicKey, publicKey, privateKey, mnemonic string, isSplit bool) error { + keys := []zcncrypto.KeyPair{{PrivateKey: privateKey, PublicKey: publicKey}} + w := zcncrypto.Wallet{ + ClientID: clientID, + ClientKey: clientKey, + PeerPublicKey: peerPublicKey, + Mnemonic: mnemonic, + Keys: keys, + IsSplit: isSplit, + } + client.AddWallet(w) + return nil +} + +// removeWallet removes a wallet from the SDK by public key (used by wasm bindings). +func removeWallet(pubKey string) error { + client.RemoveWallet(pubKey) + return nil +} From 73399faca2ebb1d190ee2e770f52ef32085b0914 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 18 Nov 2025 12:38:23 +0530 Subject: [PATCH 38/47] bridge mw wasm --- wasmsdk/bridge_mw.go | 199 +++++++++++++++++++++++++++++++++ wasmsdk/proxy.go | 27 ++++- zcnbridge/authorizers_query.go | 12 +- zcnbridge/bridge.go | 12 +- 4 files changed, 235 insertions(+), 15 deletions(-) create mode 100644 wasmsdk/bridge_mw.go diff --git a/wasmsdk/bridge_mw.go b/wasmsdk/bridge_mw.go new file mode 100644 index 000000000..6ab6bcd6e --- /dev/null +++ b/wasmsdk/bridge_mw.go @@ -0,0 +1,199 @@ +package main + +import ( + "context" + "encoding/base64" + "encoding/json" + "github.com/0chain/gosdk/zcnbridge/errors" + "github.com/0chain/gosdk/zcnbridge/log" + "github.com/0chain/gosdk/zcncore" + "strconv" +) + + +// burnZCN Burns ZCN tokens and returns a hash of the burn transaction +// - amount: amount of ZCN tokens to burn +// - txnfee: transaction fee +func burnZCNMW(amount uint64, key string) string { //nolint + if bridge == nil { + return errors.New("burnZCN", "bridge is not initialized").Error() + } + + hash, _, err := bridge.BurnZCN(amount, key) + if err != nil { + return errors.Wrap("burnZCN", "failed to burn ZCN tokens", err).Error() + } + + return hash +} + +// mintZCN Mints ZCN tokens and returns a hash of the mint transaction +// - burnTrxHash: hash of the burn transaction +// - timeout: timeout in seconds +func mintZCNMW(burnTrxHash string, timeout int, key string) string { //nolint + mintPayload, + + err := bridge.QueryZChainMintPayload(burnTrxHash, key) + if err != nil { + return errors.Wrap("mintZCN", "failed to QueryZChainMintPayload", err).Error() + } + + hash, err := bridge.MintZCN(mintPayload, key) + if err != nil { + return errors.Wrap("mintZCN", "failed to MintZCN for txn "+hash, err).Error() + } + + return hash +} + +// getMintWZCNPayload returns the mint payload for the given burn transaction hash +// - burnTrxHash: hash of the burn transaction +func getMintWZCNPayloadMW(burnTrxHash string, key string) string { //nolint:unused + mintPayload, err := bridge.QueryEthereumMintPayload(burnTrxHash) + if err != nil { + return errors.Wrap("getMintWZCNPayload", "failed to query ethereum mint payload", err).Error() + } + var result []byte + result, err = json.Marshal(mintPayload) + if err != nil { + return errors.Wrap("getMintWZCNPayload", "failed to query ethereum mint payload", err).Error() + } + + return string(result) +} + +// getNotProcessedWZCNBurnEvents returns all not processed WZCN burn events from the Ethereum network +func getNotProcessedWZCNBurnEventsMW(key string) string { //nolint:unused + var ( + mintNonce int64 + res []byte + err error + ) + if res, err = zcncore.GetMintNonce(); err != nil { + return errors.Wrap("getNotProcessedWZCNBurnEvents", "failed to retreive last ZCN processed mint nonce", err).Error() + } + + if err = json.Unmarshal(res, &mintNonce); err != nil { + return errors.Wrap("getNotProcessedWZCNBurnEvents", "failed to unmarshal last ZCN processed mint nonce", err).Error() + } + + log.Logger.Debug("MintNonce = " + strconv.Itoa(int(mintNonce))) + burnEvents, err := bridge.QueryEthereumBurnEvents(strconv.Itoa(int(mintNonce)), key) + if err != nil { + return errors.Wrap("getNotProcessedWZCNBurnEvents", "failed to retrieve WZCN burn events", err).Error() + } + + var result []byte + result, err = json.Marshal(burnEvents) + if err != nil { + return errors.Wrap("getNotProcessedWZCNBurnEvents", "failed to marshal WZCN burn events", err).Error() + } + + return string(result) +} + +// getNotProcessedZCNBurnTickets Returns all not processed ZCN burn tickets burned for a certain ethereum address +func getNotProcessedZCNBurnTicketsMW(key string) string { //nolint:unused + userNonce, err := bridge.GetUserNonceMinted(context.Background(), bridge.EthereumAddress) + if err != nil { + return errors.Wrap("getNotProcessedZCNBurnTickets", "failed to retreive user nonce", err).Error() + } + + var ( + res []byte + burnTickets []zcncore.BurnTicket + ) + + res, err = zcncore.GetNotProcessedZCNBurnTickets(bridge.EthereumAddress, userNonce.String()) + if err != nil { + return errors.Wrap("getNotProcessedZCNBurnTickets", "failed to retreive ZCN burn tickets", err).Error() + } + + if err = json.Unmarshal(res, &burnTickets); err != nil { + return errors.Wrap("getNotProcessedZCNBurnTickets", "failed to unmarshal ZCN burn tickets", err).Error() + } + + var result []byte + result, err = json.Marshal(burnTickets) + if err != nil { + return errors.Wrap("getNotProcessedZCNBurnTickets", "failed to marshal ZCN burn tickets", err).Error() + } + + return string(result) +} + +// estimateBurnWZCNGasAmount performs gas amount estimation for the given burn wzcn transaction. +// - from: address of the sender +// - to: address of the receiver +// - amountTokens: amount of tokens to burn (as a string) +func estimateBurnWZCNGasAmountMW(from, to, amountTokens, key string) string { // nolint:golint,unused + estimateBurnWZCNGasAmountResponse, err := bridge.EstimateBurnWZCNGasAmount( + context.Background(), from, to, amountTokens, key) + if err != nil { + return errors.Wrap("estimateBurnWZCNGasAmount", "failed to estimate gas amount", err).Error() + } + + var result []byte + result, err = json.Marshal(estimateBurnWZCNGasAmountResponse) + if err != nil { + return errors.Wrap("estimateBurnWZCNGasAmount", "failed to marshal gas amount estimation result", err).Error() + } + + return string(result) +} + +// estimateMintWZCNGasAmount performs gas amount estimation for the given mint wzcn transaction. +// - from: address of the sender +// - to: address of the receiver +// - zcnTransaction: hash of the ZCN transaction +// - amountToken: amount of tokens to mint (as a string) +// - nonce: nonce of the transaction +// - signaturesRaw: encoded format (base-64) of the burn signatures received from the authorizers. +func estimateMintWZCNGasAmountMW(from, to, zcnTransaction, amountToken string, nonce int64, signaturesRaw []string, key string) string { // nolint:golint,unused + var signaturesBytes [][]byte + + var ( + signatureBytes []byte + err error + ) + + for _, signature := range signaturesRaw { + signatureBytes, err = base64.StdEncoding.DecodeString(signature) + if err != nil { + return errors.Wrap("estimateMintWZCNGasAmount", "failed to convert raw signature into bytes", err).Error() + } + + signaturesBytes = append(signaturesBytes, signatureBytes) + } + + estimateMintWZCNGasAmountResponse, err := bridge.EstimateMintWZCNGasAmount( + context.Background(), from, to, zcnTransaction, amountToken, nonce, signaturesBytes) + if err != nil { + return errors.Wrap("estimateMintWZCNGasAmount", "failed to estimate gas amount", err).Error() + } + + var result []byte + result, err = json.Marshal(estimateMintWZCNGasAmountResponse) + if err != nil { + return errors.Wrap("estimateMintWZCNGasAmount", "failed to marshal gas amount estimation result", err).Error() + } + + return string(result) +} + +// estimateGasPrice performs gas estimation for the given transaction using Alchemy enhanced API returning +// approximate final gas fee. +func estimateGasPriceMW(key string) string { // nolint:golint,unused + estimateGasPriceResponse, err := bridge.EstimateGasPrice(context.Background()) + if err != nil { + return errors.Wrap("estimateGasPrice", "failed to estimate gas price", err).Error() + } + + var result []byte + result, err = json.Marshal(estimateGasPriceResponse) + if err != nil { + return errors.Wrap("estimateGasPrice", "failed to marshal gas price estimation result", err).Error() + } + + return string(result) +} diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index 0e23a13b8..765ca2257 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -262,7 +262,6 @@ func main() { "cancelDownloadDirectory": cancelDownloadDirectory, "cancelDownloadBlocks": cancelDownloadBlocks, "setConsensusThreshold": setConsensusThreshold, - //blobber mw (multi-wallet support) "deleteMW": DeleteMW, "shareMW": ShareMW, @@ -302,7 +301,6 @@ func main() { "play": play, "stop": stop, "getNextSegment": getNextSegment, - // player mw "playMW": playMW, "stopMW": stopMW, @@ -325,7 +323,6 @@ func main() { "getAllocationWith": getAllocationWith, "createfreeallocation": createfreeallocation, "getUpdateAllocTicket": getUpdateAllocTicket, - //allocation mw (multi-wallet support) "createAllocationMW": createAllocationMW, "getAllocationBlobbersMW": getAllocationBlobbersMW, @@ -346,20 +343,35 @@ func main() { // claim rewards "collectRewards": collectRewards, + //claim rewards mw + "collectRewardsMW": collectRewardsMW, // stakepool "getSkatePoolInfo": getSkatePoolInfo, "lockStakePool": lockStakePool, "unlockStakePool": unlockStakePool, + // stakepool mw + "getSkatePoolInfoMW": getSkatePoolInfoMW, + "lockStakePoolMW": lockStakePoolMW, + "unlockStakePoolMW": unlockStakePoolMW, // writepool "lockWritePool": lockWritePool, + // writepool mw + "lockWritePoolMW": lockWritePoolMW, + + "decodeAuthTicket": decodeAuthTicket, "allocationRepair": allocationRepair, "repairSize": repairSize, + // "decodeAuthTicketMW": decodeAuthTicketMW, + "allocationRepairMW": allocationRepairMW, + "repairSizeMW": repairSizeMW, "generateOwnerSigningKey": generateOwnerSigningKey, + "generateOwnerSigningKeyMW": generateOwnerSigningKeyMW, + // bridge "initBridge": initBridge, @@ -371,6 +383,15 @@ func main() { "estimateBurnWZCNGasAmount": estimateBurnWZCNGasAmount, "estimateMintWZCNGasAmount": estimateMintWZCNGasAmount, "estimateGasPrice": estimateGasPrice, + // bridge mw + "burnZCNMW": burnZCNMW, + "mintZCNMW": mintZCNMW, + "getMintWZCNPayloadMW": getMintWZCNPayloadMW, + "getNotProcessedWZCNBurnEventsMW": getNotProcessedWZCNBurnEventsMW, + "getNotProcessedZCNBurnTicketsMW": getNotProcessedZCNBurnTicketsMW, + "estimateBurnWZCNGasAmountMW": estimateBurnWZCNGasAmountMW, + "estimateMintWZCNGasAmountMW": estimateMintWZCNGasAmountMW, + "estimateGasPriceMW": estimateGasPriceMW, //zcn "getWalletBalance": getWalletBalance, diff --git a/zcnbridge/authorizers_query.go b/zcnbridge/authorizers_query.go index 067e146fd..7cb2d0b4f 100644 --- a/zcnbridge/authorizers_query.go +++ b/zcnbridge/authorizers_query.go @@ -119,7 +119,7 @@ func (b *BridgeClient) QueryEthereumMintPayload(zchainBurnHash string) (*ethereu } // QueryEthereumBurnEvents gets ethereum burn events -func (b *BridgeClient) QueryEthereumBurnEvents(startNonce string) ([]*ethereum.BurnEvent, error) { +func (b *BridgeClient) QueryEthereumBurnEvents(startNonce string, keys ...string) ([]*ethereum.BurnEvent, error) { client = h.CleanClient() authorizers, err := getAuthorizers(true) @@ -130,7 +130,7 @@ func (b *BridgeClient) QueryEthereumBurnEvents(startNonce string) ([]*ethereum.B var ( totalWorkers = len(authorizers) values = map[string]string{ - "clientid": coreClient.Id(), + "clientid": coreClient.Id(keys...), "ethereumaddress": b.EthereumAddress, "startnonce": startNonce, } @@ -176,7 +176,7 @@ func (b *BridgeClient) QueryEthereumBurnEvents(startNonce string) ([]*ethereum.B // QueryZChainMintPayload gets burn ticket and creates mint payload to be minted in the ZChain // ethBurnHash - Ethereum burn transaction hash -func (b *BridgeClient) QueryZChainMintPayload(ethBurnHash string) (*zcnsc.MintPayload, error) { +func (b *BridgeClient) QueryZChainMintPayload(ethBurnHash string, keys ...string) (*zcnsc.MintPayload, error) { const maxRetries = 3 var lastErr error @@ -191,7 +191,7 @@ func (b *BridgeClient) QueryZChainMintPayload(ethBurnHash string) (*zcnsc.MintPa time.Sleep(delay) } - payload, err := b.queryZChainMintPayloadOnce(ethBurnHash) + payload, err := b.queryZChainMintPayloadOnce(ethBurnHash, keys...) if err == nil { return payload, nil } @@ -203,7 +203,7 @@ func (b *BridgeClient) QueryZChainMintPayload(ethBurnHash string) (*zcnsc.MintPa } // queryZChainMintPayloadOnce performs a single attempt to query mint payload -func (b *BridgeClient) queryZChainMintPayloadOnce(ethBurnHash string) (*zcnsc.MintPayload, error) { +func (b *BridgeClient) queryZChainMintPayloadOnce(ethBurnHash string, keys ...string) (*zcnsc.MintPayload, error) { client = h.CleanClient() authorizers, err := getAuthorizers(true) log.Logger.Info("Got authorizers", zap.Int("amount", len(authorizers))) @@ -216,7 +216,7 @@ func (b *BridgeClient) queryZChainMintPayloadOnce(ethBurnHash string) (*zcnsc.Mi totalWorkers = len(authorizers) values = map[string]string{ "hash": ethBurnHash, - "clientid": coreClient.Id(), + "clientid": coreClient.Id(keys...), } ) diff --git a/zcnbridge/bridge.go b/zcnbridge/bridge.go index f222a4fbd..164452a63 100644 --- a/zcnbridge/bridge.go +++ b/zcnbridge/bridge.go @@ -622,7 +622,7 @@ func (b *BridgeClient) BurnWZCN(ctx context.Context, amountTokens uint64) (*type // MintZCN mints ZCN tokens after receiving proof-of-burn of WZCN tokens // - ctx go context instance to run the transaction // - payload received from authorizers -func (b *BridgeClient) MintZCN(payload *zcnsc.MintPayload) (string, error) { +func (b *BridgeClient) MintZCN(payload *zcnsc.MintPayload, keys ...string) (string, error) { Logger.Info( "Starting MINT smart contract", zap.String("sc address", wallet.ZCNSCSmartContractAddress), @@ -632,7 +632,7 @@ func (b *BridgeClient) MintZCN(payload *zcnsc.MintPayload) (string, error) { hash, _, _, _, err := coreTransaction.SmartContractTxn(wallet.ZCNSCSmartContractAddress, coreTransaction.SmartContractTxnData{ Name: wallet.MintFunc, InputArgs: payload, - }, true) + }, true, keys...) if err != nil { return "", errors.Wrap(err, fmt.Sprintf("failed to execute smart contract, hash = %s", hash)) @@ -650,7 +650,7 @@ func (b *BridgeClient) MintZCN(payload *zcnsc.MintPayload) (string, error) { // - ctx go context instance to run the transaction // - amount amount of tokens to burn // - txnfee transaction fee -func (b *BridgeClient) BurnZCN(amount uint64) (string, string, error) { +func (b *BridgeClient) BurnZCN(amount uint64, keys ...string) (string, string, error) { payload := zcnsc.BurnPayload{ EthereumAddress: b.EthereumAddress, } @@ -664,7 +664,7 @@ func (b *BridgeClient) BurnZCN(amount uint64) (string, string, error) { hash, out, _, _, err := coreTransaction.SmartContractTxnValue(wallet.ZCNSCSmartContractAddress, coreTransaction.SmartContractTxnData{ Name: wallet.BurnFunc, InputArgs: payload, - }, amount, true) + }, amount, true, keys...) if err != nil { Logger.Error("Burn ZCN transaction FAILED", zap.Error(err)) return hash, out, errors.Wrap(err, fmt.Sprintf("failed to execute smart contract, hash = %s", hash)) @@ -1057,7 +1057,7 @@ func (b *BridgeClient) estimateAlchemyGasAmount(ctx context.Context, to, data st // - from source address // - to target address // - amountTokens amount of tokens to burn -func (b *BridgeClient) EstimateBurnWZCNGasAmount(ctx context.Context, from, to, amountTokens string) (float64, error) { +func (b *BridgeClient) EstimateBurnWZCNGasAmount(ctx context.Context, from, to, amountTokens string, keys ...string) (float64, error) { switch b.getProviderType() { case AlchemyProvider: abi, err := bridge.BridgeMetaData.GetAbi() @@ -1065,7 +1065,7 @@ func (b *BridgeClient) EstimateBurnWZCNGasAmount(ctx context.Context, from, to, return 0, errors.Wrap(err, "failed to get ABI") } - clientID := DefaultClientIDEncoder(coreClient.Id()) + clientID := DefaultClientIDEncoder(coreClient.Id(keys...)) amount := new(big.Int) amount.SetString(amountTokens, 10) From c38fe9d68dd36860e51d2e21201d6fabba422510 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Tue, 18 Nov 2025 12:59:38 +0530 Subject: [PATCH 39/47] all wasm functions supported --- core/client/zauth.go | 16 ++++++++-------- wasmsdk/auth_txn.go | 19 +++++++++++++++++++ wasmsdk/proxy.go | 1 + 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/core/client/zauth.go b/core/client/zauth.go index 25a4b5a4e..29979b6ba 100644 --- a/core/client/zauth.go +++ b/core/client/zauth.go @@ -535,7 +535,7 @@ func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) { // ZauthSignTxn returns a function that sends a txn signing request to the zauth server func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { - return func(msg string, pubkeys ...string) (string, error) { + return func(msg string, keys ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -543,10 +543,10 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { req.Header.Set("Content-Type", "application/json") c := GetClient() pubkey := c.Keys[0].PublicKey - if len(pubkeys) > 0 { - c = GetWalletByKey(pubkeys[0]) + if len(keys) > 0 { + c = GetWalletByKey(keys[0]) if c == nil { - return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) + return "", errors.Errorf("wallet not found for pubkey: %s", keys[0]) } pubkey = c.Keys[0].PublicKey } @@ -580,7 +580,7 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { } func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { - return func(msg string, pubkeys ...string) (string, error) { + return func(msg string, keys ...string) (string, error) { req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg))) if err != nil { return "", errors.Wrap(err, "failed to create HTTP request") @@ -588,10 +588,10 @@ func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { c := GetClient() pubkey := c.Keys[0].PublicKey - if len(pubkeys) > 0 { - c = GetWalletByKey(pubkeys[0]) + if len(keys) > 0 { + c = GetWalletByKey(keys[0]) if c == nil { - return "", errors.Errorf("wallet not found for pubkey: %s", pubkeys[0]) + return "", errors.Errorf("wallet not found for pubkey: %s", keys[0]) } pubkey = c.Keys[0].PublicKey } diff --git a/wasmsdk/auth_txn.go b/wasmsdk/auth_txn.go index aa8354446..269ff88c8 100644 --- a/wasmsdk/auth_txn.go +++ b/wasmsdk/auth_txn.go @@ -129,6 +129,25 @@ func callAuth(this js.Value, args []js.Value) interface{} { return nil } +// callAuth Call the authorization callback function and provide the message to pass to it. +// The message is passed as the first argument to the js calling. +func callAuthMW(this js.Value, args []js.Value) interface{} { + fmt.Println("callAuth is called") + if len(args) == 0 { + return nil + } + + if authCallback != nil { + msg := args[0].String() + key := args[1].String() + result, _ := sys.Authorize(msg, key) + fmt.Println("auth is called, result:", result) + return js.ValueOf(result) + } + + return nil +} + // Parse the JavaScript callback function into Go AuthorizerCallback type func parseAuthorizerCallback(jsCallback js.Value) AuthCallbackFunc { return func(msg string) string { diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index 765ca2257..d46e1ecc5 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -409,6 +409,7 @@ func main() { "registerAuthorizer": js.FuncOf(registerAuthorizer), "registerAuthCommon": js.FuncOf(registerAuthCommon), "callAuth": js.FuncOf(callAuth), + "callAuthMW": js.FuncOf(callAuthMW), "authResponse": authResponse, // zauth From 565352f6aab21773bbced143c0bc1a8ca13b545d Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Thu, 20 Nov 2025 19:04:56 +0530 Subject: [PATCH 40/47] fix --- core/client/set.go | 4 +++- zboxcore/sdk/blobber_operations.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 2956b4867..7e12e6376 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -72,7 +72,9 @@ func init() { defer client.mu.RUnlock() wallet := client.wallet if len(keys) > 0 && keys[0] != "" { - if client.wallets != nil { + if wallet.Keys[0].PublicKey == keys[0] { + // use default wallet + } else if client.wallets != nil { if w, ok := client.wallets[keys[0]]; ok && w != nil { wallet = w } diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index 1d4198f3f..9319b10f3 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -56,7 +56,7 @@ func CreateAllocationForOwner( return "", 0, nil, sdkNotInitialized } - if client.PublicKey() == ownerPublicKey { + if client.PublicKey(keys...) == ownerPublicKey { privateSigningKey, err := GenerateOwnerSigningKey(ownerPublicKey, owner) if err != nil { return "", 0, nil, errors.New("failed_generate_owner_signing_key", "failed to generate owner signing key: "+err.Error()) From 8f39d846036d64e79c6d12aafde2977aa3bd2142 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 21 Nov 2025 12:57:05 +0530 Subject: [PATCH 41/47] provide signing-key method --- core/client/set.go | 21 +++++++++++++++++++++ core/client/zauth.go | 2 +- zboxcore/sdk/blobber_operations.go | 11 +++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 7e12e6376..72496593d 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -499,6 +499,27 @@ func PublicKey(keys ...string) string { return client.wallet.ClientKey } +// PublicKey lookup uses read lock +func SigningKey(keys ...string) (string, error) { + if len(keys) > 0 && keys[0] != "" { + client.mu.RLock() + if client.wallets != nil { + if w, ok := client.wallets[keys[0]]; ok && w != nil { + k := w.Keys[0].PublicKey + client.mu.RUnlock() + return k, nil + } else { + client.mu.RUnlock() + return "", errors.New("multi-wallet-settings err: " + keys[0]) + } + } + client.mu.RUnlock() + } + + return client.wallet.Keys[0].PublicKey, nil +} + + func Mnemonic() string { return client.wallet.Mnemonic } diff --git a/core/client/zauth.go b/core/client/zauth.go index 29979b6ba..feac4e167 100644 --- a/core/client/zauth.go +++ b/core/client/zauth.go @@ -591,7 +591,7 @@ func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { if len(keys) > 0 { c = GetWalletByKey(keys[0]) if c == nil { - return "", errors.Errorf("wallet not found for pubkey: %s", keys[0]) + return "", errors.Errorf("multi-wallet-settings err: %v", keys[0]) } pubkey = c.Keys[0].PublicKey } diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index 9319b10f3..3edcd39b4 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -57,7 +57,7 @@ func CreateAllocationForOwner( } if client.PublicKey(keys...) == ownerPublicKey { - privateSigningKey, err := GenerateOwnerSigningKey(ownerPublicKey, owner) + privateSigningKey, err := GenerateOwnerSigningKey(ownerPublicKey, owner, keys...) if err != nil { return "", 0, nil, errors.New("failed_generate_owner_signing_key", "failed to generate owner signing key: "+err.Error()) } @@ -385,12 +385,11 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string, signingPubKey ...st } hashData := fmt.Sprintf("%s:%s", ownerPublicKey, "owner_signing_public_key") // prefer explicit signing pubkey when provided (for split-wallet scenarios) - pubkeyToUse := client.PublicKey() - if len(signingPubKey) > 0 && signingPubKey[0] != "" { - pubkeyToUse = signingPubKey[0] + signingKey, err := client.SigningKey(signingPubKey...) + if err != nil { + return nil, err } - - sig, err := client.Sign(encryption.Hash(hashData), pubkeyToUse) + sig, err := client.Sign(encryption.Hash(hashData), signingKey) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) return nil, err From a9a97301edc9f3da576e335624aca99809017c39 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Fri, 21 Nov 2025 13:03:26 +0530 Subject: [PATCH 42/47] fix signing-key function --- core/client/set.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/client/set.go b/core/client/set.go index 72496593d..398535ba6 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -516,7 +516,7 @@ func SigningKey(keys ...string) (string, error) { client.mu.RUnlock() } - return client.wallet.Keys[0].PublicKey, nil + return client.wallet.ClientID, nil } From 5269fe50de87f07dd26ef604d68471a923b35955 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Mon, 24 Nov 2025 20:57:22 +0530 Subject: [PATCH 43/47] fix --- core/client/set.go | 25 ++++++++++++----- core/transaction/entity.go | 43 +++++++++++++----------------- zboxcore/sdk/blobber_operations.go | 1 + zboxcore/sdk/sdk.go | 4 +-- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index 398535ba6..a779c18d0 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -110,10 +110,21 @@ func GetClient() *zcncrypto.Wallet { return client.wallet } -var SignFn = func(hash string) (string, error) { +var SignFn = func(hash string, keys ...string) (string, error) { ss := zcncrypto.NewSignatureScheme(client.signatureScheme) - err := ss.SetPrivateKey(client.wallet.Keys[0].PrivateKey) + var err error + if len(keys) > 0 && keys[0] != "" { + wallet := GetWalletByKey(keys[0]) + if wallet == nil { + return "", errors.New("multi-wallet-settings err: " + keys[0]) + } + err = ss.SetPrivateKey(wallet.Keys[0].PrivateKey) + + } else { + err = ss.SetPrivateKey(client.wallet.Keys[0].PrivateKey) + } + if err != nil { return "", err } @@ -570,21 +581,23 @@ func Id(keys ...string) string { // IsWalletSplit returns whether the wallet identified by keys[0] (pubkey or id) // is a split-key wallet. If no key is provided the default SDK wallet's split // flag is returned. -func IsWalletSplit(keys ...string) bool { +func IsWalletSplit(keys ...string) (bool, error) { client.mu.RLock() defer client.mu.RUnlock() if len(keys) > 0 && keys[0] != "" && client.wallets != nil { if w, ok := client.wallets[keys[0]]; ok && w != nil { - return w.IsSplit + return w.IsSplit, nil + } else { + return false, errors.New("multi-wallet-settings err: " + keys[0]) } } if client.wallet != nil { - return client.wallet.IsSplit + return client.wallet.IsSplit, nil } - return false + return false, nil } // VerifySignature ... diff --git a/core/transaction/entity.go b/core/transaction/entity.go index 944e59b7c..5a594e229 100644 --- a/core/transaction/entity.go +++ b/core/transaction/entity.go @@ -166,7 +166,7 @@ const ( FEES_TABLE = `/v1/fees_table` ) -type SignFunc = func(msg string) (string, error) +type SignFunc = func(msg string, keys ...string) (string, error) type VerifyFunc = func(publicKey, signature, msgHash string) (bool, error) type SignWithWallet = func(msg string, wallet interface{}) (string, error) @@ -230,7 +230,7 @@ func (t *Transaction) getAuthorize() (string, error) { func (t *Transaction) ComputeHashAndSign(signHandler SignFunc) error { t.ComputeHashData() var err error - t.Signature, err = signHandler(t.Hash) + t.Signature, err = signHandler(t.Hash, t.MultiWalletSupportKey) if err != nil { return err } @@ -552,11 +552,7 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, // Determine client identifier/public key to use for signing. If an explicit key is // provided in keys varargs, prefer it; otherwise default to SDK client id. - clientId := client.Id() - if len(keys) > 0 && keys[0] != "" { - // keys[0] may be a client public key or client id. Let client.Id resolve it. - clientId = client.Id(keys[0]) - } + clientId := client.Id(keys...) var requestBytes []byte if requestBytes, err = json.Marshal(sn); err != nil { @@ -573,8 +569,8 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, return } - txn := NewTransactionEntity(client.Id(clientId), - cfg.ChainID, client.PublicKey(clientId), nonce) + txn := NewTransactionEntity(clientId, + cfg.ChainID, client.PublicKey(keys...), nonce) txn.TransactionData = string(requestBytes) txn.ToClientID = scAddress @@ -604,25 +600,24 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData, txn.TransactionNonce = client.Cache.GetNextNonce(txn.ClientID) } - if client.IsWalletSplit(keys...) { - if len(keys) > 0 && keys[0] != "" { - txn.MultiWalletSupportKey = keys[0] - } - txn.ComputeHashData() + if len(keys) > 0 && keys[0] != "" { + txn.MultiWalletSupportKey = keys[0] + } + + err = txn.ComputeHashAndSign(client.SignFn) + if err != nil { + return + } + + isSplit, err := client.IsWalletSplit(keys...) + if err != nil { + return + } + if isSplit { txn.Signature, err = txn.getAuthorize() if err != nil { return } - } else { - // Use a sign wrapper that forwards the provided keys to client.Sign so the - // signing happens under the intended wallet/public key when keys are provided. - err = txn.ComputeHashAndSign(func(hash string) (string, error) { - // forward original keys varargs so client.Sign can pick the correct wallet - return client.Sign(hash, keys...) - }) - if err != nil { - return - } } ok, err := txn.VerifySigWith(txn.PublicKey, sys.VerifyWith) diff --git a/zboxcore/sdk/blobber_operations.go b/zboxcore/sdk/blobber_operations.go index 3edcd39b4..8b98e506d 100644 --- a/zboxcore/sdk/blobber_operations.go +++ b/zboxcore/sdk/blobber_operations.go @@ -389,6 +389,7 @@ func GenerateOwnerSigningKey(ownerPublicKey, ownerID string, signingPubKey ...st if err != nil { return nil, err } + fmt.Printf("signingKey: %s\n", signingKey) sig, err := client.Sign(encryption.Hash(hashData), signingKey) if err != nil { logger.Logger.Error("error during sign", zap.Error(err)) diff --git a/zboxcore/sdk/sdk.go b/zboxcore/sdk/sdk.go index d9a9c5b56..111031431 100644 --- a/zboxcore/sdk/sdk.go +++ b/zboxcore/sdk/sdk.go @@ -830,13 +830,13 @@ func CreateAllocationWith(options CreateAllocationOptions, keys ...string) ( return CreateAllocationForOwner( client.Id(keys...), client.PublicKey(keys...), "", options.DataShards, options.ParityShards, options.Size, options.ReadPrice, options.WritePrice, options.Lock, - options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams, options.AuthRoundExpiry) + options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams, options.AuthRoundExpiry, keys...) } return CreateAllocationForOwner(client.Id(), client.PublicKey(), "", options.DataShards, options.ParityShards, options.Size, options.ReadPrice, options.WritePrice, options.Lock, - options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams, options.AuthRoundExpiry) + options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams, options.AuthRoundExpiry, keys...) } // GetAllocationBlobbers returns a list of blobber ids that can be used for a new allocation. From 40a2e22f91cb1293afc1a026d08384dd969acdc1 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Sat, 6 Dec 2025 11:59:46 +0530 Subject: [PATCH 44/47] fix wasm build --- core/zcncrypto/bls0chain_wasm.go | 2 +- wasmsdk/proxy.go | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/zcncrypto/bls0chain_wasm.go b/core/zcncrypto/bls0chain_wasm.go index a7592ed08..de9009d96 100644 --- a/core/zcncrypto/bls0chain_wasm.go +++ b/core/zcncrypto/bls0chain_wasm.go @@ -10,7 +10,7 @@ import ( ) var ( - Sign func(hash string) (string, error) + Sign func(hash string, keys ...string) (string, error) ) // WasmScheme - a signature scheme for BLS0Chain Signature diff --git a/wasmsdk/proxy.go b/wasmsdk/proxy.go index d46e1ecc5..51c988c12 100644 --- a/wasmsdk/proxy.go +++ b/wasmsdk/proxy.go @@ -54,13 +54,21 @@ func main() { jsSign := jsProxy.Get("sign") if !(jsSign.IsNull() || jsSign.IsUndefined()) { - signFunc := func(hash string) (string, error) { + signFunc := func(hash string, keys ...string) (string, error) { c := client.GetClient() if c == nil || len(c.Keys) == 0 { return "", errors.New("no keys found") } pk := c.Keys[0].PrivateKey + if len(keys) > 0 && keys[0] != "" { + wallet := client.GetWalletByKey(keys[0]) + if wallet == nil { + return "", errors.New("wallet not found") + } + pk = wallet.Keys[0].PrivateKey + } + result, err := jsbridge.Await(jsSign.Invoke(hash, pk)) if len(err) > 0 && !err[0].IsNull() { @@ -446,13 +454,20 @@ func main() { if !(jsProxy.IsNull() || jsProxy.IsUndefined()) { jsSign := jsProxy.Get("sign") if !(jsSign.IsNull() || jsSign.IsUndefined()) { - signFunc := func(hash string) (string, error) { + signFunc := func(hash string, keys ...string) (string, error) { c := client.GetClient() if c == nil || len(c.Keys) == 0 { return "", errors.New("no keys found") } pk := c.Keys[0].PrivateKey + if len(keys) > 0 && keys[0] != "" { + wallet := client.GetWalletByKey(keys[0]) + if wallet == nil { + return "", errors.New("wallet not found") + } + pk = wallet.Keys[0].PrivateKey + } result, err := jsbridge.Await(jsSign.Invoke(hash, pk)) if len(err) > 0 && !err[0].IsNull() { From 7f59e3f622931c396f8d3f47689489107c8f14d1 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Wed, 17 Dec 2025 12:10:20 +0530 Subject: [PATCH 45/47] build fix --- mobilesdk/sdk/sdk.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mobilesdk/sdk/sdk.go b/mobilesdk/sdk/sdk.go index d9b78bcfd..25dcae1bd 100644 --- a/mobilesdk/sdk/sdk.go +++ b/mobilesdk/sdk/sdk.go @@ -33,7 +33,7 @@ var nonce = int64(0) var allocationIDRequired = errors.Errorf("Allocation ID is required") type Autorizer interface { - Auth(msg string, clientIDs ...string) (string, error) + Auth(msg string, clientIDs []string) (string, error) } // ChainConfig - blockchain config @@ -508,5 +508,7 @@ func decodeTicket(ticket string) (string, string, uint64, error) { // } // } func RegisterAuthorizer(auth Autorizer) { - sys.Authorize = auth.Auth + sys.Authorize = func(msg string, clientIDs ...string) (string, error) { + return auth.Auth(msg, clientIDs) + } } From 0b0396506394c9cc4f63f78a09d10bd946b17f47 Mon Sep 17 00:00:00 2001 From: Arun Ramanathan Date: Wed, 17 Dec 2025 19:07:08 +0530 Subject: [PATCH 46/47] fix mobile build --- mobilesdk/sdk/sdk.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mobilesdk/sdk/sdk.go b/mobilesdk/sdk/sdk.go index 25dcae1bd..6fb295493 100644 --- a/mobilesdk/sdk/sdk.go +++ b/mobilesdk/sdk/sdk.go @@ -33,7 +33,7 @@ var nonce = int64(0) var allocationIDRequired = errors.Errorf("Allocation ID is required") type Autorizer interface { - Auth(msg string, clientIDs []string) (string, error) + Auth(msg string) (string, error) } // ChainConfig - blockchain config @@ -509,6 +509,7 @@ func decodeTicket(ticket string) (string, string, uint64, error) { // } func RegisterAuthorizer(auth Autorizer) { sys.Authorize = func(msg string, clientIDs ...string) (string, error) { - return auth.Auth(msg, clientIDs) + // clientIDs are ignored as the interface only accepts msg + return auth.Auth(msg) } } From 08c95fe35366d22532365428c4821f4d1c9285a4 Mon Sep 17 00:00:00 2001 From: Nahom Amare Date: Fri, 9 Jan 2026 23:38:30 +0300 Subject: [PATCH 47/47] feat: dual-index wallets by ClientID and PublicKey to fix multi-wallet lookup --- core/client/set.go | 119 ++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 34 deletions(-) diff --git a/core/client/set.go b/core/client/set.go index a779c18d0..cb490f541 100644 --- a/core/client/set.go +++ b/core/client/set.go @@ -66,29 +66,45 @@ func init() { // prime the sign channel sigC <- struct{}{} + // default Sign implementation (uses client.wallet or wallets map) // default Sign implementation (uses client.wallet or wallets map) Sign = func(hash string, keys ...string) (string, error) { client.mu.RLock() - defer client.mu.RUnlock() wallet := client.wallet if len(keys) > 0 && keys[0] != "" { - if wallet.Keys[0].PublicKey == keys[0] { + if wallet != nil && len(wallet.Keys) > 0 && wallet.Keys[0].PublicKey == keys[0] { // use default wallet } else if client.wallets != nil { if w, ok := client.wallets[keys[0]]; ok && w != nil { wallet = w + } else { + // Wallet not found by the provided key + client.mu.RUnlock() + return "", errors.New("no wallets available for signing by key: " + keys[0]) } } else { + client.mu.RUnlock() return "", errors.New("no wallets available for signing by key: " + keys[0]) } } - fmt.Print("wallet found: client_id: ", wallet.ClientID, "is_split: ", wallet.IsSplit, "pubkey: ", wallet.Keys[0].PublicKey) - - if !wallet.IsSplit { - return sys.Sign(hash, client.signatureScheme, GetClientSysKeys(keys...)) + if wallet == nil { + client.mu.RUnlock() + return "", errors.New("wallet not initialized") } + // fmt.Print("wallet found: client_id: ", wallet.ClientID, "is_split: ", wallet.IsSplit, "pubkey: ", wallet.Keys[0].PublicKey) + + isSplit := wallet.IsSplit + sigScheme := client.signatureScheme + + // Release lock before calling external functions that might re-acquire it + client.mu.RUnlock() + + if !isSplit { + return sys.Sign(hash, sigScheme, GetClientSysKeys(keys...)) + } + fmt.Println("Signature: ", "It actually get's to this point right after signing") // split-key signing via auth <-sigC fmt.Println("Sign: with sys.SignWithAuth:", sys.SignWithAuth, "sysKeys:", GetClientSysKeys(keys...)) @@ -348,7 +364,7 @@ func SetWallet(w zcncrypto.Wallet) { // GetWalletByKey gets a wallet by client pubkey. func GetWalletByKey(key string) *zcncrypto.Wallet { - client.mu.RLock() + client.mu.RLock() defer client.mu.RUnlock() if client.wallets == nil { return nil @@ -361,8 +377,15 @@ func GetWallet() *zcncrypto.Wallet { } // AddWallet adds a new wallet to the sdk. +// The wallet is indexed by BOTH ClientID and PublicKey to support +// lookups from different parts of the codebase (workers use ClientID, +// Sign function uses PublicKey). func AddWallet(wallet zcncrypto.Wallet) { + if len(wallet.Keys) == 0 { + return + } pubkey := wallet.Keys[0].PublicKey + clientID := wallet.ClientID client.mu.Lock() defer client.mu.Unlock() @@ -377,49 +400,57 @@ func AddWallet(wallet zcncrypto.Wallet) { client.walletCount = make(map[string]int) } - // if wallet already present, just increment counter - if _, exists := client.wallets[pubkey]; exists { - client.walletCount[pubkey]++ + // Check if wallet already exists (by ClientID to avoid double-counting) + if _, exists := client.wallets[clientID]; exists { + client.walletCount[clientID]++ // ensure wg exists - if client.wg[pubkey] == nil { - client.wg[pubkey] = &sync.WaitGroup{} + if client.wg[clientID] == nil { + client.wg[clientID] = &sync.WaitGroup{} } - client.wg[pubkey].Add(1) + client.wg[clientID].Add(1) return } - // add new wallet + // Add new wallet - index by BOTH ClientID and PublicKey + client.wallets[clientID] = &wallet client.wallets[pubkey] = &wallet - if client.wg[pubkey] == nil { - client.wg[pubkey] = &sync.WaitGroup{} + + // Use ClientID for reference counting and wait groups + if client.wg[clientID] == nil { + client.wg[clientID] = &sync.WaitGroup{} } - client.wg[pubkey].Add(1) - client.walletCount[pubkey]++ + client.wg[clientID].Add(1) + client.walletCount[clientID]++ } -// RemoveWallet removes a wallet from the sdk. -func RemoveWallet(pubkey string) { +// RemoveWallet removes a wallet from the sdk by ClientID. +// This also removes the PublicKey index to maintain dual-index consistency. +func RemoveWallet(clientID string) { client.mu.Lock() defer client.mu.Unlock() - if pubkey == "" || client.walletCount == nil { + if clientID == "" || client.walletCount == nil { return } // only decrement if count > 0 - if client.walletCount[pubkey] > 0 { - client.walletCount[pubkey]-- + if client.walletCount[clientID] > 0 { + client.walletCount[clientID]-- // call Done on wg only if it exists - if wg, ok := client.wg[pubkey]; ok && wg != nil { + if wg, ok := client.wg[clientID]; ok && wg != nil { wg.Done() } } - // if count reaches zero, clean up maps - if client.walletCount[pubkey] == 0 { - delete(client.wallets, pubkey) - delete(client.wg, pubkey) - delete(client.walletCount, pubkey) + // if count reaches zero, clean up both indexes + if client.walletCount[clientID] == 0 { + // Remove both ClientID and PublicKey indexes + if w := client.wallets[clientID]; w != nil && len(w.Keys) > 0 { + delete(client.wallets, w.Keys[0].PublicKey) // Remove PublicKey index + } + delete(client.wallets, clientID) // Remove ClientID index + delete(client.wg, clientID) + delete(client.walletCount, clientID) } } @@ -490,7 +521,12 @@ func TxnFee() uint64 { } func IsWalletSet() bool { - return client.wallet.ClientID != "" + client.mu.RLock() + defer client.mu.RUnlock() + if client.wallet != nil && client.wallet.ClientID != "" { + return true + } + return len(client.wallets) > 0 } // PublicKey lookup uses read lock @@ -507,7 +543,10 @@ func PublicKey(keys ...string) string { client.mu.RUnlock() } - return client.wallet.ClientKey + if client.wallet != nil { + return client.wallet.ClientKey + } + return "" } // PublicKey lookup uses read lock @@ -527,12 +566,18 @@ func SigningKey(keys ...string) (string, error) { client.mu.RUnlock() } - return client.wallet.ClientID, nil + if client.wallet != nil { + return client.wallet.ClientID, nil + } + return "", errors.New("wallet not initialized") } func Mnemonic() string { - return client.wallet.Mnemonic + if client.wallet != nil { + return client.wallet.Mnemonic + } + return "" } // GetWalletMnemonic returns the mnemonic for a wallet identified by pubkey. @@ -557,6 +602,9 @@ func GetWalletMnemonic(pubkey string) string { } func PrivateKey() string { + if client.wallet == nil { + return "" + } for _, kv := range client.wallet.Keys { return kv.PrivateKey } @@ -575,7 +623,10 @@ func Id(keys ...string) string { } client.mu.RUnlock() } - return client.wallet.ClientID + if client.wallet != nil { + return client.wallet.ClientID + } + return "" } // IsWalletSplit returns whether the wallet identified by keys[0] (pubkey or id)