Skip to content

Commit cf1641c

Browse files
authored
check prev nonce for rollback wm (#1369)
* check prev nonce for rollback wm * fix txn
1 parent b1b133f commit cf1641c

File tree

4 files changed

+97
-4
lines changed

4 files changed

+97
-4
lines changed

code/go/0chain.net/blobbercore/writemarker/entity.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type WriteMarkerEntity struct {
5050
StatusMessage string `gorm:"column:status_message"`
5151
ReedeemRetries int64 `gorm:"column:redeem_retries;not null;default:0"`
5252
CloseTxnID string `gorm:"column:close_txn_id;size:64"`
53+
CloseTxnNonce int64 `gorm:"column:close_txn_nonce"`
5354
ConnectionID string `gorm:"column:connection_id;size:64"`
5455
ClientPublicKey string `gorm:"column:client_key;size:256"`
5556
Latest bool `gorm:"column:latest;not null;default:true"`
@@ -84,6 +85,7 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke
8485
StatusMessage: string(statusBytes),
8586
CloseTxnID: redeemTxn,
8687
ReedeemRetries: wm.ReedeemRetries,
88+
CloseTxnNonce: wm.CloseTxnNonce,
8789
}).Error
8890
return err
8991
}
@@ -92,6 +94,7 @@ func (wm *WriteMarkerEntity) UpdateStatus(ctx context.Context, status WriteMarke
9294
Status: status,
9395
StatusMessage: string(statusBytes),
9496
CloseTxnID: redeemTxn,
97+
CloseTxnNonce: wm.CloseTxnNonce,
9598
}).Error
9699
if err != nil {
97100
return err
@@ -136,6 +139,20 @@ func GetWriteMarkerEntity(ctx context.Context, allocation_root string) (*WriteMa
136139
return wm, nil
137140
}
138141

142+
// GetPreviousWM get previous WriteMarkerEntity from postgres for rollback WM
143+
func GetPreviousWM(ctx context.Context, allocation_root string, timestamp common.Timestamp) (*WriteMarkerEntity, error) {
144+
db := datastore.GetStore().GetTransaction(ctx)
145+
wm := &WriteMarkerEntity{}
146+
err := db.Table((WriteMarkerEntity{}).TableName()).
147+
Where("allocation_root <> ? AND prev_allocation_root=? AND timestamp=?", allocation_root, allocation_root, timestamp).
148+
Order("timestamp desc").
149+
Take(wm).Error
150+
if err != nil {
151+
return nil, err
152+
}
153+
return wm, nil
154+
}
155+
139156
// AllocationRootMustUnique allocation_root must be unique in write_markers
140157
func AllocationRootMustUnique(ctx context.Context, allocation_root string, timestamp int64) error {
141158
db := datastore.GetStore().GetTransaction(ctx)

code/go/0chain.net/blobbercore/writemarker/protocol.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,21 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error {
135135
sn.PrevAllocationRoot = wme.WM.PreviousAllocationRoot
136136
sn.WriteMarker = &wme.WM
137137

138-
err = txn.ExecuteSmartContract(transaction.STORAGE_CONTRACT_ADDRESS, transaction.CLOSE_CONNECTION_SC_NAME, sn, 0)
138+
if sn.AllocationRoot == sn.PrevAllocationRoot {
139+
// get nonce of prev WM
140+
var prevWM *WriteMarkerEntity
141+
prevWM, err = GetPreviousWM(ctx, sn.AllocationRoot, wme.WM.Timestamp)
142+
if err != nil {
143+
wme.StatusMessage = "Error getting previous write marker. " + err.Error()
144+
if err := wme.UpdateStatus(ctx, Failed, "Error getting previous write marker. "+err.Error(), ""); err != nil {
145+
Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err))
146+
}
147+
return err
148+
}
149+
err = txn.ExecuteRollbackWM(transaction.STORAGE_CONTRACT_ADDRESS, transaction.CLOSE_CONNECTION_SC_NAME, sn, 0, prevWM.CloseTxnNonce)
150+
} else {
151+
err = txn.ExecuteSmartContract(transaction.STORAGE_CONTRACT_ADDRESS, transaction.CLOSE_CONNECTION_SC_NAME, sn, 0)
152+
}
139153
if err != nil {
140154
Logger.Error("Failed during sending close connection to the miner. ", zap.String("err:", err.Error()))
141155
wme.Status = Failed
@@ -148,11 +162,12 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error {
148162

149163
time.Sleep(transaction.SLEEP_FOR_TXN_CONFIRMATION * time.Second)
150164
t, err := transaction.VerifyTransactionWithNonce(txn.Hash, txn.GetTransaction().GetTransactionNonce())
165+
wme.CloseTxnID = txn.Hash
166+
wme.CloseTxnNonce = txn.GetTransaction().GetTransactionNonce()
151167
if err != nil {
152168
Logger.Error("Error verifying the close connection transaction", zap.String("err:", err.Error()), zap.String("txn", txn.Hash))
153169
wme.Status = Failed
154170
wme.StatusMessage = "Error verifying the close connection transaction." + err.Error()
155-
wme.CloseTxnID = txn.Hash
156171
// TODO Is this single try?
157172
if err := wme.UpdateStatus(ctx, Failed, "Error verifying the close connection transaction."+err.Error(), txn.Hash); err != nil {
158173
Logger.Error("WriteMarkerEntity_UpdateStatus", zap.Error(err))
@@ -161,7 +176,6 @@ func (wme *WriteMarkerEntity) redeemMarker(ctx context.Context) error {
161176
}
162177
wme.Status = Committed
163178
wme.StatusMessage = t.TransactionOutput
164-
wme.CloseTxnID = t.Hash
165179
_ = wme.UpdateStatus(ctx, Committed, t.TransactionOutput, t.Hash)
166180
return nil
167181
}

code/go/0chain.net/core/transaction/entity.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package transaction
22

33
import (
44
"encoding/json"
5-
"github.com/0chain/gosdk/core/transaction"
65
"sync"
76
"time"
87

8+
"github.com/0chain/gosdk/core/transaction"
9+
910
"github.com/0chain/blobber/code/go/0chain.net/core/logging"
1011
"go.uber.org/zap"
1112

@@ -186,6 +187,63 @@ func (t *Transaction) ExecuteSmartContract(address, methodName string, input int
186187
return nil
187188
}
188189

190+
func (t *Transaction) ExecuteRollbackWM(address, methodName string, input interface{}, val uint64, prevNonce int64) error {
191+
t.wg.Add(1)
192+
193+
sn := transaction.SmartContractTxnData{Name: methodName, InputArgs: input}
194+
snBytes, err := json.Marshal(sn)
195+
if err != nil {
196+
return err
197+
}
198+
199+
updateLast50Transactions(string(snBytes))
200+
201+
nonce := monitor.getNextUnusedNonce()
202+
if nonce < prevNonce {
203+
t.wg.Done()
204+
logging.Logger.Error("Failed to set nonce as prevNonce is greater",
205+
zap.Any("nonce", nonce),
206+
zap.Any("prevNonce", prevNonce),
207+
)
208+
monitor.recordFailedNonce(nonce)
209+
return common.NewError("transaction_send_error", "Failed to set nonce as prevNonce is greater")
210+
}
211+
if err := t.zcntxn.SetTransactionNonce(nonce); err != nil {
212+
logging.Logger.Error("Failed to set nonce.",
213+
zap.Any("hash", t.zcntxn.GetTransactionHash()),
214+
zap.Any("nonce", nonce),
215+
zap.Any("error", err))
216+
}
217+
218+
logging.Logger.Info("Transaction nonce set.",
219+
zap.Any("hash", t.zcntxn.GetTransactionHash()),
220+
zap.Any("nonce", nonce))
221+
222+
_, err = t.zcntxn.ExecuteSmartContract(address, methodName, input, uint64(val))
223+
if err != nil {
224+
t.wg.Done()
225+
logging.Logger.Error("Failed to execute SC.",
226+
zap.Any("hash", t.zcntxn.GetTransactionHash()),
227+
zap.Any("nonce", t.zcntxn.GetTransactionNonce()),
228+
zap.Any("error", err))
229+
monitor.recordFailedNonce(t.zcntxn.GetTransactionNonce())
230+
return err
231+
}
232+
233+
t.wg.Wait()
234+
235+
t.Hash = t.zcntxn.GetTransactionHash()
236+
if len(t.zcntxn.GetTransactionError()) > 0 {
237+
logging.Logger.Error("Failed to submit SC.",
238+
zap.Any("hash", t.zcntxn.GetTransactionHash()),
239+
zap.Any("nonce", t.zcntxn.GetTransactionNonce()),
240+
zap.Any("error", t.zcntxn.GetTransactionError()))
241+
monitor.recordFailedNonce(t.zcntxn.GetTransactionNonce())
242+
return common.NewError("transaction_send_error", t.zcntxn.GetTransactionError())
243+
}
244+
return nil
245+
}
246+
189247
func (t *Transaction) Verify() error {
190248
if err := t.zcntxn.SetTransactionHash(t.Hash); err != nil {
191249
monitor.recordFailedNonce(t.zcntxn.GetTransactionNonce())
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
ALTER TABLE write_markers ADD COLUMN close_txn_nonce BIGINT;
4+
-- +goose StatementEnd

0 commit comments

Comments
 (0)