ceremonyclient/node/execution/intrinsics/token/application/token_handle_mint.go
Cassandra Heart 058885951a
final -b4
2024-10-22 18:46:05 -05:00

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")
}