github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/private/engine/qlightptm/caching_proxy.go (about) 1 package qlightptm 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "fmt" 7 8 "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/common/hexutil" 10 "github.com/ethereum/go-ethereum/log" 11 "github.com/ethereum/go-ethereum/private/cache" 12 "github.com/ethereum/go-ethereum/private/engine" 13 "github.com/ethereum/go-ethereum/rpc" 14 gocache "github.com/patrickmn/go-cache" 15 ) 16 17 type RPCClientCaller interface { 18 Call(result interface{}, method string, args ...interface{}) error 19 } 20 21 type CachingProxyTxManager struct { 22 features *engine.FeatureSet 23 cache *gocache.Cache 24 rpcClient RPCClientCaller 25 } 26 27 type CPItem struct { 28 cache.PrivateCacheItem 29 IsSender bool 30 IsEmpty bool 31 } 32 33 func Is(ptm interface{}) bool { 34 _, ok := ptm.(*CachingProxyTxManager) 35 return ok 36 } 37 38 func New() *CachingProxyTxManager { 39 return &CachingProxyTxManager{ 40 features: engine.NewFeatureSet(engine.PrivacyEnhancements), 41 cache: gocache.New(cache.DefaultExpiration, cache.CleanupInterval), 42 } 43 } 44 45 func (t *CachingProxyTxManager) SetRPCClient(client *rpc.Client) { 46 t.rpcClient = client 47 } 48 49 func (t *CachingProxyTxManager) SetRPCClientCaller(client RPCClientCaller) { 50 t.rpcClient = client 51 } 52 53 func (t *CachingProxyTxManager) Send(data []byte, from string, to []string, extra *engine.ExtraMetadata) (string, []string, common.EncryptedPayloadHash, error) { 54 panic("implement me") 55 } 56 57 func (t *CachingProxyTxManager) EncryptPayload(data []byte, from string, to []string, extra *engine.ExtraMetadata) ([]byte, error) { 58 panic("implement me") 59 } 60 61 func (t *CachingProxyTxManager) StoreRaw(data []byte, from string) (common.EncryptedPayloadHash, error) { 62 panic("implement me") 63 } 64 65 func (t *CachingProxyTxManager) SendSignedTx(data common.EncryptedPayloadHash, to []string, extra *engine.ExtraMetadata) (string, []string, []byte, error) { 66 panic("implement me") 67 } 68 69 func (t *CachingProxyTxManager) Receive(hash common.EncryptedPayloadHash) (string, []string, []byte, *engine.ExtraMetadata, error) { 70 return t.receive(hash, false) 71 } 72 73 // retrieve raw will not return information about medata. 74 // Related to SendSignedTx 75 func (t *CachingProxyTxManager) ReceiveRaw(hash common.EncryptedPayloadHash) ([]byte, string, *engine.ExtraMetadata, error) { 76 sender, _, data, extra, err := t.receive(hash, true) 77 return data, sender, extra, err 78 } 79 80 // retrieve raw will not return information about medata 81 func (t *CachingProxyTxManager) receive(hash common.EncryptedPayloadHash, isRaw bool) (string, []string, []byte, *engine.ExtraMetadata, error) { 82 if common.EmptyEncryptedPayloadHash(hash) { 83 return "", nil, nil, nil, nil 84 } 85 cacheKey := hash.Hex() 86 if isRaw { 87 // indicate the cache item is incomplete, this will be fulfilled in SendSignedTx 88 cacheKey = fmt.Sprintf("%s-incomplete", cacheKey) 89 } 90 log.Info("qlight: retrieving private data from ptm cache") 91 if item, found := t.cache.Get(cacheKey); found { 92 cacheItem, ok := item.(CPItem) 93 if !ok { 94 return "", nil, nil, nil, fmt.Errorf("unknown cache item. expected type PrivateCacheItem") 95 } 96 if cacheItem.IsEmpty { 97 return "", nil, nil, nil, nil 98 } 99 return cacheItem.Extra.Sender, cacheItem.Extra.ManagedParties, cacheItem.Payload, &cacheItem.Extra, nil 100 } 101 102 log.Info("qlight: no private data in ptm cache, retrieving from qlight server node") 103 var result engine.QuorumPayloadExtra 104 err := t.rpcClient.Call(&result, "eth_getQuorumPayloadExtra", hash.Hex()) 105 if err != nil { 106 return "", nil, nil, nil, err 107 } 108 if len(result.Payload) > 3 { 109 payloadBytes, err := hex.DecodeString(result.Payload[2:]) 110 if err != nil { 111 return "", nil, nil, nil, err 112 } 113 114 toCache := &CachablePrivateTransactionData{ 115 Hash: hash, 116 QuorumPrivateTxData: result, 117 } 118 if err := t.Cache(toCache); err != nil { 119 log.Warn("unable to cache ptm data", "err", err) 120 } 121 122 return result.ExtraMetaData.Sender, result.ExtraMetaData.ManagedParties, payloadBytes, result.ExtraMetaData, nil 123 } 124 return "", nil, nil, nil, nil 125 } 126 127 func (t *CachingProxyTxManager) CheckAndAddEmptyToCache(hash common.EncryptedPayloadHash) { 128 if common.EmptyEncryptedPayloadHash(hash) { 129 return 130 } 131 cacheKey := hash.Hex() 132 133 if _, found := t.cache.Get(cacheKey); found { 134 return 135 } 136 137 t.cache.Set(cacheKey, CPItem{ 138 IsEmpty: true, 139 }, gocache.DefaultExpiration) 140 } 141 142 type CachablePrivateTransactionData struct { 143 Hash common.EncryptedPayloadHash 144 QuorumPrivateTxData engine.QuorumPayloadExtra 145 } 146 147 func (t *CachingProxyTxManager) Cache(privateTxData *CachablePrivateTransactionData) error { 148 if common.EmptyEncryptedPayloadHash(privateTxData.Hash) { 149 return nil 150 } 151 cacheKey := privateTxData.Hash.Hex() 152 153 payload, err := hexutil.Decode(privateTxData.QuorumPrivateTxData.Payload) 154 if err != nil { 155 return err 156 } 157 158 t.cache.Set(cacheKey, CPItem{ 159 PrivateCacheItem: cache.PrivateCacheItem{ 160 Payload: payload, 161 Extra: *privateTxData.QuorumPrivateTxData.ExtraMetaData, 162 }, 163 IsSender: privateTxData.QuorumPrivateTxData.IsSender, 164 }, gocache.DefaultExpiration) 165 166 return nil 167 } 168 169 // retrieve raw will not return information about medata 170 func (t *CachingProxyTxManager) DecryptPayload(payload common.DecryptRequest) ([]byte, *engine.ExtraMetadata, error) { 171 payloadBytes, err := json.Marshal(payload) 172 if err != nil { 173 return nil, nil, err 174 } 175 payloadHex := fmt.Sprintf("0x%x", payloadBytes) 176 177 var result engine.QuorumPayloadExtra 178 err = t.rpcClient.Call(&result, "eth_decryptQuorumPayload", payloadHex) 179 if err != nil { 180 return nil, nil, err 181 } 182 183 responsePayloadHex := result.Payload 184 if len(responsePayloadHex) < 3 { 185 return nil, nil, fmt.Errorf("Invalid payload hex") 186 } 187 if responsePayloadHex[:2] == "0x" { 188 responsePayloadHex = responsePayloadHex[2:] 189 } 190 responsePayload, err := hex.DecodeString(responsePayloadHex) 191 if err != nil { 192 return nil, nil, err 193 } 194 return responsePayload, result.ExtraMetaData, nil 195 } 196 197 func (t *CachingProxyTxManager) IsSender(data common.EncryptedPayloadHash) (bool, error) { 198 _, _, _, _, err := t.receive(data, false) 199 if err != nil { 200 return false, err 201 } 202 cacheKey := data.Hex() 203 if item, found := t.cache.Get(cacheKey); found { 204 cacheItem, ok := item.(CPItem) 205 if !ok { 206 return false, fmt.Errorf("unknown cache item. expected type PrivateCacheItem") 207 } 208 return cacheItem.IsSender, nil 209 } 210 return false, nil 211 } 212 213 func (t *CachingProxyTxManager) GetParticipants(txHash common.EncryptedPayloadHash) ([]string, error) { 214 panic("implement me") 215 } 216 217 func (t *CachingProxyTxManager) GetMandatory(txHash common.EncryptedPayloadHash) ([]string, error) { 218 panic("implement me") 219 } 220 221 func (t *CachingProxyTxManager) Groups() ([]engine.PrivacyGroup, error) { 222 panic("implement me") 223 } 224 225 func (t *CachingProxyTxManager) Name() string { 226 return "CachingP2PProxy" 227 } 228 229 func (t *CachingProxyTxManager) HasFeature(f engine.PrivateTransactionManagerFeature) bool { 230 return t.features.HasFeature(f) 231 }