Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First design for OpenTelemtry #82

Merged
merged 2 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions fhevm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
crypto "github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
fhevm_crypto "github.com/zama-ai/fhevm-go/crypto"
"go.opentelemetry.io/otel"
)

var zero = common.BytesToHash(uint256.NewInt(0).Bytes())
Expand Down Expand Up @@ -186,6 +187,10 @@ func verifyIfCiphertextHandle(handle common.Hash, env EVMEnvironment, contractAd

// This function is a modified copy from https://github.com/ethereum/go-ethereum
func OpSload(pc *uint64, env EVMEnvironment, scope ScopeContext) ([]byte, error) {
if otelCtx := env.OtelContext(); otelCtx != nil {
_, span := otel.Tracer("fhevm").Start(otelCtx, "OpSload")
defer span.End()
}
loc := scope.GetStack().Peek()
hash := common.Hash(loc.Bytes32())
val := env.GetState(scope.GetContract().Address(), hash)
Expand Down Expand Up @@ -267,6 +272,10 @@ func persistIfVerifiedCiphertext(flagHandleLocation common.Hash, handle common.H

func OpSstore(pc *uint64, env EVMEnvironment, scope ScopeContext) ([]byte, error) {
// This function is a modified copy from https://github.com/ethereum/go-ethereum
if otelCtx := env.OtelContext(); otelCtx != nil {
_, span := otel.Tracer("fhevm").Start(otelCtx, "OpSstore")
defer span.End()
}
if env.IsReadOnly() {
return nil, ErrWriteProtection
}
Expand Down Expand Up @@ -351,6 +360,10 @@ func RemoveVerifiedCipherextsAtCurrentDepth(env EVMEnvironment) {

func OpReturn(pc *uint64, env EVMEnvironment, scope ScopeContext) []byte {
// This function is a modified copy from https://github.com/ethereum/go-ethereum
if otelCtx := env.OtelContext(); otelCtx != nil {
_, span := otel.Tracer("fhevm").Start(otelCtx, "OpReturn")
defer span.End()
}
offset, size := scope.GetStack().Pop(), scope.GetStack().Pop()
ret := scope.GetMemory().GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
delegateCiphertextHandlesToCaller(env, ret)
Expand Down
6 changes: 6 additions & 0 deletions fhevm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fhevm

import (
"bytes"
"context"
"math/big"
"sync"
"testing"
Expand Down Expand Up @@ -160,6 +161,11 @@ type MockEVMEnvironment struct {
fhevmParams FhevmParams
}

func (*MockEVMEnvironment) OtelContext() context.Context {
// can also return nil and disable Otel
return context.TODO()
}

func (environment *MockEVMEnvironment) GetState(addr common.Address, hash common.Hash) common.Hash {
return environment.stateDb.GetState(addr, hash)
}
Expand Down
7 changes: 7 additions & 0 deletions fhevm/interface.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fhevm

import (
"context"
"math/big"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -33,6 +34,12 @@ type EVMEnvironment interface {

FhevmData() *FhevmData
FhevmParams() *FhevmParams

// This should return the context used for OpenTelemetry in the current EVM.
// It should be considered the root context for every op that runs in the EVM, and all spans created from this context
// would be child spans for what has been already created using the context.
// Implementations returning nil would disable OpenTelemetry on the fhEVM
OtelContext() context.Context
}

type FhevmData struct {
Expand Down
123 changes: 123 additions & 0 deletions fhevm/precompiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/holiman/uint256"
fhevm_crypto "github.com/zama-ai/fhevm-go/crypto"
kms "github.com/zama-ai/fhevm-go/kms"
"go.opentelemetry.io/otel"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/nacl/box"
"google.golang.org/grpc"
Expand Down Expand Up @@ -176,19 +177,37 @@ func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Ad
logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input))
return nil, err
}
otelCtx := environment.OtelContext()
tracer := otel.Tracer("fhevm")
// first 4 bytes are for the function signature
signature := binary.BigEndian.Uint32(input[0:4])
switch signature {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm the author of the initial switch statement (looked good idea at the time for me) and maybe in the future we can replace this with a map of small abstraction, like structs of all the fhevm functions which contain, say

type fhevmPrecompileMethod {
  name string
  implementation <function signature which implements current switch block>
}

And have a generated map of these for first 4 bytes of method signature

map[[]byte]fhevmPrecompileMethod

Then we could just do one lookup to the map, and do one trace using name of the method not to repeat ourselves.

Also, in future bwCompatBytes logic could be just moved inside implementation method, say fheAddRun.
This was needed before when we supported separate precompile smart contracts instead of one, we no longer need that now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this seems a nice refactor, I will do that just after we merge this (probably today)

case signatureFheAdd:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheAdd")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheAddRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureCast:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheCast")
defer span.End()
}
bwCompatBytes := input[4:minInt(37, len(input))]
return castRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureDecrypt:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheDecrypt")
defer span.End()
}
bwCompatBytes := input[4:minInt(36, len(input))]
return decryptRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFhePubKey:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fhePubKey")
defer span.End()
}
bwCompatBytes := input[4:minInt(5, len(input))]
precompileBytes, err := fhePubKeyRun(environment, caller, addr, bwCompatBytes, readOnly)
if err != nil {
Expand All @@ -200,75 +219,171 @@ func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Ad
outputBytes = append(outputBytes, precompileBytes...)
return padArrayTo32Multiple(outputBytes), nil
case signatureTrivialEncrypt:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheTrivialEncrypt")
defer span.End()
}
bwCompatBytes := input[4:minInt(37, len(input))]
return trivialEncryptRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheSub:
if otelCtx := environment.OtelContext(); otelCtx != nil {
_, span := otel.Tracer("fhevm").Start(otelCtx, "fheSub")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheSubRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheMul:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheMul")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheMulRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheLe:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheLe")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheLeRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheLt:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheLt")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheLtRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheEq:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheAdd")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheEqRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheGe:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheAdd")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheGeRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheGt:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheAdd")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheGtRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheShl:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheShl")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheShlRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheShr:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheShr")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheShrRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheNe:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheNe")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheNeRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheMin:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheMin")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheMinRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheMax:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheMax")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheMaxRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheNeg:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheNeg")
defer span.End()
}
bwCompatBytes := input[4:minInt(36, len(input))]
return fheNegRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheNot:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheNot")
defer span.End()
}
bwCompatBytes := input[4:minInt(36, len(input))]
return fheNotRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheDiv:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheDiv")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheDivRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheRem:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheRem")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheRemRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheBitAnd:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheBitAnd")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheBitAndRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheBitOr:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheBitOr")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheBitOrRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheBitXor:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheBitXor")
defer span.End()
}
bwCompatBytes := input[4:minInt(69, len(input))]
return fheBitXorRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheRand:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheRand")
defer span.End()
}
bwCompatBytes := input[4:minInt(5, len(input))]
return fheRandRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheRandBounded:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheRandBounded")
defer span.End()
}
bwCompatBytes := input[4:minInt(37, len(input))]
return fheRandBoundedRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureFheIfThenElse:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheIfThenElse")
defer span.End()
}
bwCompatBytes := input[4:minInt(100, len(input))]
return fheIfThenElseRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureVerifyCiphertext:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheVerifyCiphertext")
defer span.End()
}
// first 32 bytes of the payload is offset, then 32 bytes are size of byte array
if len(input) <= 68 {
err := errors.New("verifyCiphertext(bytes) must contain at least 68 bytes for selector, byte offset and size")
Expand All @@ -286,6 +401,10 @@ func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Ad
bwCompatBytes := input[bytesStart:minInt(bytesEnd, len(input))]
return verifyCiphertextRun(environment, caller, addr, bwCompatBytes, readOnly)
case signatureReencrypt:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheReencrypt")
defer span.End()
}
bwCompatBytes := input[4:minInt(68, len(input))]
precompileBytes, err := reencryptRun(environment, caller, addr, bwCompatBytes, readOnly)
if err != nil {
Expand All @@ -297,6 +416,10 @@ func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Ad
outputBytes = append(outputBytes, precompileBytes...)
return padArrayTo32Multiple(outputBytes), nil
case signatureOptimisticRequire:
if otelCtx != nil {
_, span := tracer.Start(otelCtx, "fheOptimisticRequire")
defer span.End()
}
bwCompatBytes := input[4:minInt(36, len(input))]
return optimisticRequireRun(environment, caller, addr, bwCompatBytes, readOnly)
default:
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ go 1.20
require (
github.com/ethereum/go-ethereum v1.12.0
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c
go.opentelemetry.io/otel v1.23.1
golang.org/x/crypto v0.16.0
)

require (
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
go.opentelemetry.io/otel/metric v1.23.1 // indirect
go.opentelemetry.io/otel/trace v1.23.1 // indirect
golang.org/x/net v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
)
Expand Down
15 changes: 13 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
Expand Down Expand Up @@ -121,7 +126,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -251,7 +256,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
Expand Down Expand Up @@ -279,6 +284,12 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY=
go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA=
go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo=
go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI=
go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8=
go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down
Loading