caching_proxy.go 6.7 KB

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