mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
159 lines
4.4 KiB
Go
159 lines
4.4 KiB
Go
package fees
|
|
|
|
import (
|
|
"bytes"
|
|
"math/big"
|
|
|
|
"github.com/pkg/errors"
|
|
"source.quilibrium.com/quilibrium/monorepo/protobufs"
|
|
)
|
|
|
|
// Policy controls which ops PRODUCE fees and which ops CONSUME a single fee.
|
|
type Policy struct {
|
|
// Domain whose tx/mint/pending PRODUCE fee outputs (flattened FIFO queue).
|
|
// Typically token.QUIL_TOKEN_ADDRESS. Alt fee markets configure this
|
|
// differently.
|
|
ProducerDomain []byte
|
|
|
|
// Consumers (each consumes exactly one fee, FIFO).
|
|
ConsumeDeploy bool
|
|
ConsumeUpdate bool
|
|
ConsumeTx bool
|
|
ConsumePendingTx bool
|
|
ConsumeMintTx bool // MintTransaction (usually false; mints are free)
|
|
|
|
// Compute ops (consumption)
|
|
ConsumeComputeDeploy bool
|
|
ConsumeComputeUpdate bool
|
|
ConsumeCodeDeploy bool
|
|
ConsumeCodeExecute bool
|
|
ConsumeCodeFinalize bool
|
|
|
|
// Hypergraph ops (consumption)
|
|
ConsumeHypergraphDeploy bool
|
|
ConsumeHypergraphUpdate bool
|
|
ConsumeVertexAdd bool
|
|
ConsumeVertexRemove bool
|
|
ConsumeHyperedgeAdd bool
|
|
ConsumeHyperedgeRemove bool
|
|
}
|
|
|
|
// CollectBundleFees flattens fee outputs produced by ops in ProducerDomain.
|
|
// Operations that do not consume fees may still produce fee outputs for others.
|
|
func CollectBundleFees(
|
|
bundle *protobufs.MessageBundle,
|
|
pol *Policy,
|
|
) []*big.Int {
|
|
feeQueue := []*big.Int{}
|
|
|
|
push := func(raw [][]byte) {
|
|
for _, b := range raw {
|
|
if len(b) == 0 {
|
|
continue
|
|
}
|
|
feeQueue = append(feeQueue, new(big.Int).SetBytes(b))
|
|
}
|
|
}
|
|
|
|
for _, op := range bundle.Requests {
|
|
switch t := op.Request.(type) {
|
|
case *protobufs.MessageRequest_PendingTransaction:
|
|
if t.PendingTransaction != nil &&
|
|
bytes.Equal(t.PendingTransaction.Domain, pol.ProducerDomain) &&
|
|
len(t.PendingTransaction.Fees) > 0 {
|
|
push(t.PendingTransaction.Fees)
|
|
}
|
|
case *protobufs.MessageRequest_Transaction:
|
|
if t.Transaction != nil &&
|
|
bytes.Equal(t.Transaction.Domain, pol.ProducerDomain) &&
|
|
len(t.Transaction.Fees) > 0 {
|
|
push(t.Transaction.Fees)
|
|
}
|
|
case *protobufs.MessageRequest_MintTransaction:
|
|
if t.MintTransaction != nil &&
|
|
bytes.Equal(t.MintTransaction.Domain, pol.ProducerDomain) &&
|
|
len(t.MintTransaction.Fees) > 0 {
|
|
push(t.MintTransaction.Fees)
|
|
}
|
|
}
|
|
}
|
|
|
|
return feeQueue
|
|
}
|
|
|
|
// CountFeeConsumers counts how many ops in the bundle must consume a single fee
|
|
func CountFeeConsumers(bundle *protobufs.MessageBundle, pol *Policy) int {
|
|
n := 0
|
|
for _, op := range bundle.Requests {
|
|
if NeedsOneFee(op, pol) {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// SanityCheck ensures there are enough fee outputs to satisfy all consumers.
|
|
func SanityCheck(feeQueue []*big.Int, consumers int) error {
|
|
if len(feeQueue) < consumers {
|
|
return errors.Wrap(
|
|
errors.Wrapf(
|
|
errors.New("insufficient fees"),
|
|
"have %d fee outputs, need %d",
|
|
len(feeQueue), consumers,
|
|
),
|
|
"sanity check",
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NeedsOneFee says whether the given request consumes a fee under the policy.
|
|
func NeedsOneFee(req *protobufs.MessageRequest, pol *Policy) bool {
|
|
switch req.Request.(type) {
|
|
case *protobufs.MessageRequest_TokenDeploy:
|
|
return pol.ConsumeDeploy
|
|
case *protobufs.MessageRequest_TokenUpdate:
|
|
return pol.ConsumeUpdate
|
|
case *protobufs.MessageRequest_Transaction:
|
|
return pol.ConsumeTx
|
|
case *protobufs.MessageRequest_PendingTransaction:
|
|
return pol.ConsumePendingTx
|
|
case *protobufs.MessageRequest_MintTransaction:
|
|
return pol.ConsumeMintTx
|
|
case *protobufs.MessageRequest_ComputeDeploy:
|
|
return pol.ConsumeComputeDeploy
|
|
case *protobufs.MessageRequest_ComputeUpdate:
|
|
return pol.ConsumeComputeUpdate
|
|
case *protobufs.MessageRequest_CodeDeploy:
|
|
return pol.ConsumeCodeDeploy
|
|
case *protobufs.MessageRequest_CodeExecute:
|
|
return pol.ConsumeCodeExecute
|
|
case *protobufs.MessageRequest_CodeFinalize:
|
|
return pol.ConsumeCodeFinalize
|
|
case *protobufs.MessageRequest_HypergraphDeploy:
|
|
return pol.ConsumeHypergraphDeploy
|
|
case *protobufs.MessageRequest_HypergraphUpdate:
|
|
return pol.ConsumeHypergraphUpdate
|
|
case *protobufs.MessageRequest_VertexAdd:
|
|
return pol.ConsumeVertexAdd
|
|
case *protobufs.MessageRequest_VertexRemove:
|
|
return pol.ConsumeVertexRemove
|
|
case *protobufs.MessageRequest_HyperedgeAdd:
|
|
return pol.ConsumeHyperedgeAdd
|
|
case *protobufs.MessageRequest_HyperedgeRemove:
|
|
return pol.ConsumeHyperedgeRemove
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// PopFee pops the next fee from the queue (caller should ensure availability).
|
|
func PopFee(queue *[]*big.Int) *big.Int {
|
|
if len(*queue) == 0 {
|
|
return big.NewInt(0)
|
|
}
|
|
f := (*queue)[0]
|
|
*queue = (*queue)[1:]
|
|
return f
|
|
}
|