mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-14 12:15:18 +00:00
278 lines
6.5 KiB
Go
278 lines
6.5 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"os"
|
|
"runtime"
|
|
"syscall"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/sha3"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/data"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
|
|
|
pcrypto "github.com/libp2p/go-libp2p/core/crypto"
|
|
"github.com/multiformats/go-multiaddr"
|
|
mn "github.com/multiformats/go-multiaddr/net"
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/reflection"
|
|
"google.golang.org/protobuf/proto"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
|
)
|
|
|
|
type DataWorkerIPCServer struct {
|
|
protobufs.UnimplementedDataIPCServiceServer
|
|
listenAddrGRPC string
|
|
logger *zap.Logger
|
|
coreId uint32
|
|
prover crypto.FrameProver
|
|
indices []int
|
|
parentProcessId int
|
|
}
|
|
|
|
// GetFrameInfo implements protobufs.NodeServiceServer.
|
|
func (r *DataWorkerIPCServer) CalculateChallengeProof(
|
|
ctx context.Context,
|
|
req *protobufs.ChallengeProofRequest,
|
|
) (*protobufs.ChallengeProofResponse, error) {
|
|
challenge := []byte{}
|
|
challenge = append(challenge, req.PeerId...)
|
|
challenge = binary.BigEndian.AppendUint64(
|
|
challenge,
|
|
req.ClockFrame.FrameNumber,
|
|
)
|
|
found := false
|
|
for _, proof := range req.ClockFrame.AggregateProofs {
|
|
for _, c := range proof.InclusionCommitments {
|
|
o := &protobufs.IntrinsicExecutionOutput{}
|
|
err := proto.Unmarshal(c.Data, o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
outputs := &protobufs.TokenOutputs{}
|
|
err = proto.Unmarshal(o.Output, outputs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
inRange:
|
|
for _, out := range outputs.Outputs {
|
|
switch e := out.Output.(type) {
|
|
case *protobufs.TokenOutput_Coin:
|
|
addr, err := token.GetAddressOfCoin(
|
|
e.Coin,
|
|
req.ClockFrame.FrameNumber,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, idx := range p2p.GetOnesIndices(
|
|
p2p.GetBloomFilter(
|
|
addr,
|
|
1024,
|
|
64,
|
|
),
|
|
) {
|
|
for _, i := range r.indices {
|
|
if i == idx {
|
|
challenge = append(challenge, req.ClockFrame.Filter...)
|
|
challenge = append(challenge, req.ClockFrame.Input...)
|
|
challenge = append(challenge, c.Data...)
|
|
found = true
|
|
break inRange
|
|
}
|
|
}
|
|
}
|
|
case *protobufs.TokenOutput_DeletedCoin:
|
|
for _, idx := range p2p.GetOnesIndices(
|
|
p2p.GetBloomFilter(
|
|
e.DeletedCoin.Address,
|
|
1024,
|
|
64,
|
|
),
|
|
) {
|
|
for _, i := range r.indices {
|
|
if i == idx {
|
|
challenge = append(challenge, req.ClockFrame.Filter...)
|
|
challenge = append(challenge, req.ClockFrame.Input...)
|
|
challenge = append(challenge, c.Data...)
|
|
found = true
|
|
break inRange
|
|
}
|
|
}
|
|
}
|
|
case *protobufs.TokenOutput_DeletedProof:
|
|
for _, idx := range p2p.GetOnesIndices(
|
|
p2p.GetBloomFilter(
|
|
e.DeletedProof.Owner.GetImplicitAccount().Address,
|
|
1024,
|
|
64,
|
|
),
|
|
) {
|
|
for _, i := range r.indices {
|
|
if i == idx {
|
|
challenge = append(challenge, req.ClockFrame.Filter...)
|
|
challenge = append(challenge, req.ClockFrame.Input...)
|
|
challenge = append(challenge, c.Data...)
|
|
found = true
|
|
break inRange
|
|
}
|
|
}
|
|
}
|
|
case *protobufs.TokenOutput_Proof:
|
|
for _, idx := range p2p.GetOnesIndices(
|
|
p2p.GetBloomFilter(
|
|
e.Proof.Owner.GetImplicitAccount().Address,
|
|
1024,
|
|
64,
|
|
),
|
|
) {
|
|
for _, i := range r.indices {
|
|
if i == idx {
|
|
challenge = append(challenge, req.ClockFrame.Filter...)
|
|
challenge = append(challenge, req.ClockFrame.Input...)
|
|
challenge = append(challenge, c.Data...)
|
|
found = true
|
|
break inRange
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
return nil, errors.Wrap(
|
|
data.ErrNoApplicableChallenge,
|
|
"calculate challenge proof",
|
|
)
|
|
}
|
|
proof, err := r.prover.CalculateChallengeProof(
|
|
challenge,
|
|
req.ClockFrame.Difficulty,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "calculate challenge proof")
|
|
}
|
|
|
|
return &protobufs.ChallengeProofResponse{
|
|
Output: proof,
|
|
}, nil
|
|
}
|
|
|
|
func NewDataWorkerIPCServer(
|
|
listenAddrGRPC string,
|
|
logger *zap.Logger,
|
|
coreId uint32,
|
|
prover crypto.FrameProver,
|
|
config *config.Config,
|
|
parentProcessId int,
|
|
) (*DataWorkerIPCServer, error) {
|
|
peerPrivKey, err := hex.DecodeString(config.P2P.PeerPrivKey)
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "error unmarshaling peerkey"))
|
|
}
|
|
|
|
privKey, err := pcrypto.UnmarshalEd448PrivateKey(peerPrivKey)
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "error unmarshaling peerkey"))
|
|
}
|
|
|
|
pub := privKey.GetPublic()
|
|
|
|
pubKey, err := pub.Raw()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
digest := make([]byte, 128)
|
|
s := sha3.NewShake256()
|
|
s.Write([]byte(pubKey))
|
|
_, err = s.Read(digest)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
indices := p2p.GetOnesIndices(p2p.GetBloomFilter(digest, 1024, 64))
|
|
|
|
return &DataWorkerIPCServer{
|
|
listenAddrGRPC: listenAddrGRPC,
|
|
logger: logger,
|
|
coreId: coreId,
|
|
prover: prover,
|
|
indices: []int{
|
|
indices[int(coreId)%len(indices)],
|
|
},
|
|
parentProcessId: parentProcessId,
|
|
}, nil
|
|
}
|
|
|
|
func (r *DataWorkerIPCServer) Start() error {
|
|
s := grpc.NewServer(
|
|
grpc.MaxRecvMsgSize(600*1024*1024),
|
|
grpc.MaxSendMsgSize(600*1024*1024),
|
|
)
|
|
protobufs.RegisterDataIPCServiceServer(s, r)
|
|
reflection.Register(s)
|
|
|
|
mg, err := multiaddr.NewMultiaddr(r.listenAddrGRPC)
|
|
if err != nil {
|
|
return errors.Wrap(err, "start")
|
|
}
|
|
|
|
lis, err := mn.Listen(mg)
|
|
if err != nil {
|
|
return errors.Wrap(err, "start")
|
|
}
|
|
|
|
go r.monitorParent()
|
|
|
|
r.logger.Info(
|
|
"data worker listening",
|
|
zap.String("address", r.listenAddrGRPC),
|
|
)
|
|
if err := s.Serve(mn.NetListener(lis)); err != nil {
|
|
r.logger.Error("terminating server", zap.Error(err))
|
|
panic(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *DataWorkerIPCServer) monitorParent() {
|
|
if r.parentProcessId == 0 {
|
|
r.logger.Info(
|
|
"no parent process id specified, running in detached worker mode",
|
|
zap.Uint32("core_id", r.coreId),
|
|
)
|
|
return
|
|
}
|
|
|
|
for {
|
|
time.Sleep(1 * time.Second)
|
|
proc, err := os.FindProcess(r.parentProcessId)
|
|
if err != nil {
|
|
r.logger.Error("parent process not found, terminating")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Windows returns an error if the process is dead, nobody else does
|
|
if runtime.GOOS != "windows" {
|
|
err := proc.Signal(syscall.Signal(0))
|
|
if err != nil {
|
|
r.logger.Error("parent process not found, terminating")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
}
|