fox-one / mtg

FoxONE MTG
MIT License
2 stars 0 forks source link

多签流程问题 #1

Open umrx opened 3 years ago

umrx commented 3 years ago

有一些问题想请教一下:问题1:w.wallets.ListPendingTransfers查询了transfer表中handler字段=0的记录,如果某一个节点调用w.wallets.Spent(ctx, outputs, transfer)将transfer的handler字段改成1(这部分代码总是会执行),那么其他的节点不是就无法查询到这个transfer进行多签了吗?

问题2:如果outputs长度=32,会直接消费掉这些outputs,但是transfer.amount要大于sum,那么剩下的amount-sum会在什么时候消费

func (w *Cashier) run(ctx context.Context) error {
    log := logger.FromContext(ctx)
      // 问题1:w.wallets.ListPendingTransfers查询了transfer表中handler字段=0的记录
    transfers, err := w.wallets.ListPendingTransfers(ctx)
    if err != nil {
        log.WithError(err).Errorln("list transfers")
        return err
    }

    if len(transfers) == 0 {
        return errors.New("EOF")
    }

    for idx := range transfers {
        transfer := transfers[idx]
        _ = w.handleTransfer(ctx, transfer)
    }

    return nil
}

func (w *Cashier) handleTransfer(ctx context.Context, transfer *core.Transfer) error {
    log := logger.FromContext(ctx).WithField("transfer", transfer.TraceID)

    const limit = 32
    outputs, err := w.wallets.ListUnspent(ctx, transfer.AssetID, limit)
    if err != nil {
        log.WithError(err).Errorln("wallets.ListUnspent")
        return err
    }

    var (
        idx    int
        sum    decimal.Decimal
        traces []string
    )

    for _, output := range outputs {
        sum = sum.Add(output.Amount)
        traces = append(traces, output.TraceID)
        idx += 1

        if sum.GreaterThanOrEqual(transfer.Amount) {
            break
        }
    }

    outputs = outputs[:idx]

    if sum.LessThan(transfer.Amount) {
        // merge outputs
        if len(outputs) == limit {
            traceID := uuid.Modify(transfer.TraceID, mixin.HashMembers(traces))
            merge := &core.Transfer{
                TraceID:   traceID,
                AssetID:   transfer.AssetID,
                Amount:    sum,
                Opponents: w.system.MemberIDs(),
                Threshold: w.system.Threshold,
                Memo:      fmt.Sprintf("merge for %s", transfer.TraceID),
            }
                // 问题2:如果outputs长度=32,会直接消费掉这些outputs,但是transfer.amount要大于sum,那么剩下的amount-sum会在什么时候消费呢?
            return w.spend(ctx, outputs, merge)
        }

        err := errors.New("insufficient balance")
        log.WithError(err).Errorln("handle transfer", transfer.ID)
        return err
    }

    return w.spend(ctx, outputs, transfer)
}

func (w *Cashier) spend(ctx context.Context, outputs []*core.Output, transfer *core.Transfer) error {
    if tx, err := w.walletz.Spend(ctx, outputs, transfer); err != nil {
        logger.FromContext(ctx).WithError(err).Errorln("walletz.Spend")
        return err
    } else if tx != nil {
        // 签名收集完成,需要提交至主网
        // 此时将该上链 tx 存储至数据库,等待 tx sender worker 完成上链
        if err := w.wallets.CreateRawTransaction(ctx, tx); err != nil {
            logger.FromContext(ctx).WithError(err).Errorln("wallets.CreateRawTransaction")
            return err
        }
    }
        // 问题1:这里如果某一个节点调用w.wallets.Spent(ctx, outputs, transfer)将transfer的handler字段改成1(这部分代码总是会执行),那么其他的节点不是就无法查询到这个transfer进行多签了
    if err := w.wallets.Spent(ctx, outputs, transfer); err != nil {
        logger.FromContext(ctx).WithError(err).Errorln("wallets.Spend")
        return err
    }

    return nil
}
yiplee commented 3 years ago

问题一,每个节点都有自己的数据库,数据是独立的。 问题二,这个可以看 sdk 里面的实现,剩下的钱是转给自己了的,会同步回来继续使用。