github.com/loomnetwork/gamechain@v0.0.0-20200406110549-36c47eb97a92/oracle/backend.go (about) 1 package oracle 2 3 import ( 4 "context" 5 "encoding/json" 6 "github.com/ethereum/go-ethereum" 7 "github.com/ethereum/go-ethereum/accounts/abi/bind" 8 "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/common/hexutil" 10 "github.com/ethereum/go-ethereum/core/types" 11 "github.com/loomnetwork/go-loom" 12 "github.com/loomnetwork/go-loom/auth" 13 "github.com/loomnetwork/go-loom/client" 14 loomcommon "github.com/loomnetwork/go-loom/common" 15 "github.com/loomnetwork/loomchain/rpc/eth" 16 "github.com/pkg/errors" 17 "math/big" 18 ) 19 20 var ErrNotImplemented = errors.New("not implememented") 21 22 type LoomchainBackend struct { 23 *client.DAppChainRPCClient 24 signer auth.Signer 25 } 26 27 var _ bind.ContractBackend = &LoomchainBackend{} 28 29 func NewLoomchainBackend(cli *client.DAppChainRPCClient, signer auth.Signer) bind.ContractBackend { 30 return &LoomchainBackend{ 31 DAppChainRPCClient: cli, 32 signer: signer, 33 } 34 } 35 36 func (l *LoomchainBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 37 return nil, ErrNotImplemented 38 } 39 40 func (l *LoomchainBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 41 42 contractAddress, err := commonAddressToLoomAddress(*call.To, l.GetChainID()) 43 if err != nil { 44 return nil, err 45 } 46 callerAddres := loom.Address{ 47 ChainID: l.GetChainID(), 48 Local: loom.LocalAddressFromPublicKey(l.signer.PublicKey()), 49 } 50 51 evmContract := client.NewEvmContract(l.DAppChainRPCClient, contractAddress.Local) 52 53 bytes, err := evmContract.StaticCall(call.Data, callerAddres) 54 if err != nil { 55 return nil, err 56 } 57 58 return bytes, nil 59 } 60 61 func (l *LoomchainBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 62 return nil, ErrNotImplemented 63 } 64 65 func (l *LoomchainBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { 66 return nil, ErrNotImplemented 67 } 68 69 func (l *LoomchainBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 70 return 0, ErrNotImplemented 71 } 72 73 func (l *LoomchainBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 74 return big.NewInt(0), ErrNotImplemented 75 } 76 77 func (l *LoomchainBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { 78 return 0, ErrNotImplemented 79 } 80 81 func (l *LoomchainBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { 82 return ErrNotImplemented 83 } 84 85 func (l *LoomchainBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { 86 var ethFilter eth.EthFilter 87 if query.FromBlock != nil { 88 ethFilter.FromBlock = eth.BlockHeight(query.FromBlock.String()) 89 } 90 if query.ToBlock != nil { 91 ethFilter.ToBlock = eth.BlockHeight(query.ToBlock.String()) 92 } 93 if len(query.Addresses) > 0 { 94 addrs, err := commonAddressesToLoomAddresses(query.Addresses...) 95 if err != nil { 96 return nil, err 97 } 98 ethFilter.Addresses = addrs 99 } 100 if len(query.Topics) > 0 { 101 ethFilter.Topics = hashToStrings(query.Topics) 102 } 103 104 // If eth.EthFilter is used, we get strange results with missing first topic 105 jsonFilter := eth.JsonFilter{} 106 jsonFilter.FromBlock = ethFilter.FromBlock 107 jsonFilter.ToBlock = ethFilter.ToBlock 108 jsonFilter.Address = query.Addresses[0] 109 jsonFilter.Topics = []interface{}{query.Topics[0][0].String()} 110 111 filter, err := json.Marshal(&jsonFilter) 112 if err != nil { 113 return nil, err 114 } 115 116 logs, err := l.GetEvmLogs(string(filter)) 117 if err != nil { 118 return nil, err 119 } 120 121 var tlogs []types.Log 122 for _, log := range logs.EthBlockLogs { 123 topicBytes := make([][]byte, len(log.Topics)) 124 for i, topicHexStringBytes := range log.Topics { 125 topicBytes[i], err = hexutil.Decode(string(topicHexStringBytes)) 126 if err != nil { 127 return nil, errors.Wrap(err, "failed to decode topics") 128 } 129 } 130 topicHashes := byteArrayToHashes(topicBytes...) 131 132 tlogs = append(tlogs, types.Log{ 133 Address: common.BytesToAddress(log.Address), 134 Topics: topicHashes, 135 Data: log.Data, 136 BlockNumber: uint64(log.BlockNumber), 137 TxHash: common.BytesToHash(log.TransactionHash), 138 TxIndex: uint(log.TransactionIndex), 139 BlockHash: common.BytesToHash(log.BlockHash), 140 Index: uint(log.LogIndex), 141 Removed: log.Removed, 142 }) 143 } 144 return tlogs, nil 145 } 146 147 func (l *LoomchainBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { 148 return nil, ErrNotImplemented 149 } 150 151 func (l *LoomchainBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 152 return nil, ErrNotImplemented 153 } 154 155 func byteArrayToHashes(bs ...[]byte) []common.Hash { 156 var hashes []common.Hash 157 for _, b := range bs { 158 hashes = append(hashes, common.BytesToHash(b)) 159 } 160 return hashes 161 } 162 163 func hashToStrings(hss [][]common.Hash) [][]string { 164 var strs [][]string 165 for _, hs := range hss { 166 var newhs []string 167 for _, h := range hs { 168 newhs = append(newhs, h.String()) 169 } 170 if len(newhs) > 0 { 171 strs = append(strs, newhs) 172 } 173 } 174 return strs 175 } 176 177 func commonAddressToLoomAddress(ca common.Address, chainId string) (*loom.Address, error) { 178 localAddress, err := loom.LocalAddressFromHexString(ca.Hex()) 179 if err != nil { 180 return nil, err 181 } 182 183 return &loom.Address{ 184 ChainID: chainId, 185 Local: localAddress, 186 }, nil 187 } 188 189 func commonAddressesToLoomAddresses(ca ...common.Address) ([]loomcommon.LocalAddress, error) { 190 var addrs []loomcommon.LocalAddress 191 for _, a := range ca { 192 addr, err := loom.LocalAddressFromHexString(a.Hex()) 193 if err != nil { 194 return nil, err 195 } 196 addrs = append(addrs, addr) 197 } 198 return addrs, nil 199 }