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  }