-
Notifications
You must be signed in to change notification settings - Fork 52
/
suave.go
142 lines (119 loc) · 4.57 KB
/
suave.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package vm
import (
"crypto/ecdsa"
"fmt"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/suave/artifacts"
suave "github.com/ethereum/go-ethereum/suave/core"
"github.com/flashbots/go-boost-utils/bls"
"golang.org/x/exp/slices"
)
// ConfidentialStore represents the API for the confidential store
// required by Suave runtime.
type ConfidentialStore interface {
InitializeBid(bid types.Bid) (types.Bid, error)
Store(bidId suave.BidId, caller common.Address, key string, value []byte) (suave.Bid, error)
Retrieve(bid types.BidId, caller common.Address, key string) ([]byte, error)
FetchBidById(suave.BidId) (suave.Bid, error)
FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid
}
type SuaveContext struct {
// TODO: MEVM access to Backend should be restricted to only the necessary functions!
Backend *SuaveExecutionBackend
ConfidentialComputeRequestTx *types.Transaction
ConfidentialInputs []byte
CallerStack []*common.Address
}
type SuaveExecutionBackend struct {
EthBundleSigningKey *ecdsa.PrivateKey
EthBlockSigningKey *bls.SecretKey
ConfidentialStore ConfidentialStore
ConfidentialEthBackend suave.ConfidentialEthBackend
}
func NewRuntimeSuaveContext(evm *EVM, caller common.Address) *SuaveContext {
if !evm.Config.IsConfidential {
return nil
}
return &SuaveContext{
Backend: evm.SuaveContext.Backend,
ConfidentialComputeRequestTx: evm.SuaveContext.ConfidentialComputeRequestTx,
ConfidentialInputs: evm.SuaveContext.ConfidentialInputs,
CallerStack: append(evm.SuaveContext.CallerStack, &caller),
}
}
// Implements PrecompiledContract for confidential smart contracts
type SuavePrecompiledContractWrapper struct {
addr common.Address
suaveContext *SuaveContext
}
func NewSuavePrecompiledContractWrapper(addr common.Address, suaveContext *SuaveContext) *SuavePrecompiledContractWrapper {
return &SuavePrecompiledContractWrapper{addr: addr, suaveContext: suaveContext}
}
func (p *SuavePrecompiledContractWrapper) RequiredGas(input []byte) uint64 {
// TODO: Figure out how to handle gas consumption of the precompiles
return 1000
}
func (p *SuavePrecompiledContractWrapper) Run(input []byte) ([]byte, error) {
stub := &SuaveRuntimeAdapter{
impl: &suaveRuntime{
suaveContext: p.suaveContext,
},
}
if metrics.EnabledExpensive {
precompileName := artifacts.PrecompileAddressToName(p.addr)
metrics.GetOrRegisterMeter("suave/runtime/"+precompileName, nil).Mark(1)
now := time.Now()
defer func() {
metrics.GetOrRegisterTimer("suave/runtime/"+precompileName+"/duration", nil).Update(time.Since(now))
}()
}
if p.addr == isConfidentialAddress {
// 'isConfidential' is a special precompile, redo as a function?
return []byte{0x1}, nil
}
ret, err := stub.run(p.addr, input)
if err != nil && ret == nil {
ret = []byte(err.Error())
}
return ret, err
}
func isPrecompileAddr(addr common.Address) bool {
if addr == isConfidentialAddress {
return true
}
return slices.Contains(addrList, addr)
}
// Returns the caller
func checkIsPrecompileCallAllowed(suaveContext *SuaveContext, precompile common.Address, bid suave.Bid) (common.Address, error) {
anyPeekerAllowed := slices.Contains(bid.AllowedPeekers, suave.AllowedPeekerAny)
if anyPeekerAllowed {
for i := len(suaveContext.CallerStack) - 1; i >= 0; i-- {
caller := suaveContext.CallerStack[i]
if caller != nil && *caller != precompile {
return *caller, nil
}
}
return precompile, nil
}
// In question!
// For now both the precompile *and* at least one caller must be allowed to allow access to bid data
// Alternative is to simply allow if any of the callers is allowed
isPrecompileAllowed := slices.Contains(bid.AllowedPeekers, precompile)
// Special case for confStore as those are implicitly allowed
if !isPrecompileAllowed && precompile != confidentialStoreAddr && precompile != confidentialRetrieveAddr {
return common.Address{}, fmt.Errorf("precompile %s (%x) not allowed on %x", artifacts.PrecompileAddressToName(precompile), precompile, bid.Id)
}
for i := len(suaveContext.CallerStack) - 1; i >= 0; i-- {
caller := suaveContext.CallerStack[i]
if caller == nil || *caller == precompile {
continue
}
if slices.Contains(bid.AllowedPeekers, *caller) {
return *caller, nil
}
}
return common.Address{}, fmt.Errorf("no caller of %s (%x) is allowed on %x", artifacts.PrecompileAddressToName(precompile), precompile, bid.Id)
}