mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-23 19:37:27 +08:00
232 lines
6.5 KiB
Go
232 lines
6.5 KiB
Go
package application
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"math/big"
|
|
|
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
|
pcrypto "github.com/libp2p/go-libp2p/core/crypto"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/pkg/errors"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
|
)
|
|
|
|
func (a *TokenApplication) handleMint(
|
|
currentFrameNumber uint64,
|
|
lockMap map[string]struct{},
|
|
t *protobufs.MintCoinRequest,
|
|
) ([]*protobufs.TokenOutput, error) {
|
|
if t == nil || t.Proofs == nil || t.Signature == nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
payload := []byte("mint")
|
|
for _, p := range t.Proofs {
|
|
payload = append(payload, p...)
|
|
}
|
|
if err := t.Signature.Verify(payload); err != nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
pk, err := pcrypto.UnmarshalEd448PublicKey(
|
|
t.Signature.PublicKey.KeyValue,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
peerId, err := peer.IDFromPublicKey(pk)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
addr, err := poseidon.HashBytes(
|
|
t.Signature.PublicKey.KeyValue,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
altAddr, err := poseidon.HashBytes([]byte(peerId))
|
|
if err != nil {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
// todo: set termination frame for this:
|
|
if len(t.Proofs) == 1 && a.Tries[0].Contains(
|
|
addr.FillBytes(make([]byte, 32)),
|
|
) && bytes.Equal(t.Signature.PublicKey.KeyValue, a.Beacon) {
|
|
if len(t.Proofs[0]) != 64 {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
if _, touched := lockMap[string(t.Proofs[0][32:])]; touched {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
_, pr, err := a.CoinStore.GetPreCoinProofsForOwner(t.Proofs[0][32:])
|
|
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
for _, p := range pr {
|
|
if p.IndexProof == nil && bytes.Equal(p.Amount, t.Proofs[0][:32]) {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
}
|
|
|
|
lockMap[string(t.Proofs[0][32:])] = struct{}{}
|
|
|
|
outputs := []*protobufs.TokenOutput{
|
|
&protobufs.TokenOutput{
|
|
Output: &protobufs.TokenOutput_Proof{
|
|
Proof: &protobufs.PreCoinProof{
|
|
Amount: t.Proofs[0][:32],
|
|
Owner: &protobufs.AccountRef{
|
|
Account: &protobufs.AccountRef_ImplicitAccount{
|
|
ImplicitAccount: &protobufs.ImplicitAccount{
|
|
ImplicitType: 0,
|
|
Address: t.Proofs[0][32:],
|
|
},
|
|
},
|
|
},
|
|
Proof: t.Signature.Signature,
|
|
},
|
|
},
|
|
},
|
|
&protobufs.TokenOutput{
|
|
Output: &protobufs.TokenOutput_Coin{
|
|
Coin: &protobufs.Coin{
|
|
Amount: t.Proofs[0][:32],
|
|
Intersection: make([]byte, 1024),
|
|
Owner: &protobufs.AccountRef{
|
|
Account: &protobufs.AccountRef_ImplicitAccount{
|
|
ImplicitAccount: &protobufs.ImplicitAccount{
|
|
ImplicitType: 0,
|
|
Address: t.Proofs[0][32:],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
return outputs, nil
|
|
} else if len(t.Proofs) != 3 && currentFrameNumber > 60480 {
|
|
if _, touched := lockMap[string(t.Signature.PublicKey.KeyValue)]; touched {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
ring := -1
|
|
addrBytes := addr.FillBytes(make([]byte, 32))
|
|
for i, t := range a.Tries {
|
|
n := t.FindNearest(addrBytes)
|
|
if n != nil && bytes.Equal(n.External.Key, addrBytes) {
|
|
ring = i
|
|
}
|
|
}
|
|
if ring == -1 {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
outputs := []*protobufs.TokenOutput{}
|
|
for _, p := range t.Proofs {
|
|
if len(p) < 516+len(peerId)+8+32 {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
if !bytes.Equal(p[516:len(peerId)], []byte(peerId)) {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
wesoProver := crypto.NewWesolowskiFrameProver(a.Logger)
|
|
|
|
frameNumber := binary.BigEndian.Uint64(
|
|
p[516+len(peerId) : 516+len(peerId)+8],
|
|
)
|
|
if frameNumber > currentFrameNumber {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
frames, proofs, err := a.CoinStore.GetPreCoinProofsForOwner(
|
|
altAddr.FillBytes(make([]byte, 32)),
|
|
)
|
|
if err == nil {
|
|
none := true
|
|
for _, f := range frames {
|
|
if f == frameNumber {
|
|
none = false
|
|
break
|
|
}
|
|
}
|
|
|
|
if !none {
|
|
for _, pr := range proofs {
|
|
if bytes.Equal(pr.Proof, p) {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if !wesoProver.VerifyChallengeProof(p[516:], a.Difficulty, p[:516]) {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
scale := len(p2p.GetOnesIndices(p[516+len(peerId)+8 : 32]))
|
|
if scale == 0 {
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|
|
|
|
ringFactor := big.NewInt(2)
|
|
ringFactor.Exp(ringFactor, big.NewInt(int64(ring)), nil)
|
|
storage := big.NewInt(int64(1024 / (256 / scale)))
|
|
unitFactor := big.NewInt(8000000000)
|
|
storage.Mul(storage, unitFactor)
|
|
storage.Quo(storage, ringFactor)
|
|
|
|
outputs = append(
|
|
outputs,
|
|
&protobufs.TokenOutput{
|
|
Output: &protobufs.TokenOutput_Proof{
|
|
Proof: &protobufs.PreCoinProof{
|
|
Amount: storage.FillBytes(make([]byte, 32)),
|
|
Proof: p,
|
|
Difficulty: a.Difficulty,
|
|
Owner: &protobufs.AccountRef{
|
|
Account: &protobufs.AccountRef_ImplicitAccount{
|
|
ImplicitAccount: &protobufs.ImplicitAccount{
|
|
ImplicitType: 0,
|
|
Address: addr.FillBytes(make([]byte, 32)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&protobufs.TokenOutput{
|
|
Output: &protobufs.TokenOutput_Coin{
|
|
Coin: &protobufs.Coin{
|
|
Amount: storage.FillBytes(make([]byte, 32)),
|
|
Intersection: make([]byte, 1024),
|
|
Owner: &protobufs.AccountRef{
|
|
Account: &protobufs.AccountRef_ImplicitAccount{
|
|
ImplicitAccount: &protobufs.ImplicitAccount{
|
|
ImplicitType: 0,
|
|
Address: addr.FillBytes(make([]byte, 32)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
lockMap[string(t.Signature.PublicKey.KeyValue)] = struct{}{}
|
|
return outputs, nil
|
|
}
|
|
|
|
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
|
|
}
|