Files
old-backend/services/blockchain/service.go
2023-09-21 11:59:08 +02:00

133 lines
3.7 KiB
Go

package blockchain
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"gitlab.com/pactual1/backend/config"
blockchain "gitlab.com/pactual1/backend/services/blockchain/lib"
)
type service struct {
networkEndpoint string
contractAddress string
walletAddress string
walletPrivateKey string
chainID big.Int
}
func NewService(blockchainConfig config.Blockchain) Service {
return &service{networkEndpoint: blockchainConfig.NetworkEndpoint, contractAddress: blockchainConfig.ContractAddress, walletAddress: blockchainConfig.WalletAddress, walletPrivateKey: blockchainConfig.WalletPrivateKey}
}
type Service interface {
CreateContract(ctx context.Context, contractID [32]byte) error
AddIOTData(ctx context.Context, contractID [32]byte, deviceID [32]byte, timestamp *big.Int, data []byte) error
RegisterNewDeviceIDs(ctx context.Context, contractID [32]byte, deviceIDs [][32]byte) error
}
func (s *service) signerFunc(address common.Address, txn *types.Transaction) (*types.Transaction, error) {
signer := types.NewLondonSigner(&s.chainID)
privateKey, err := crypto.HexToECDSA(s.walletPrivateKey)
if err != nil {
return nil, err
}
return types.SignTx(txn, signer, privateKey)
}
func (s *service) getTransactOpts() *bind.TransactOpts {
return &bind.TransactOpts{
From: common.HexToAddress(s.walletAddress),
Signer: s.signerFunc,
}
}
func (s *service) getClient(ctx context.Context) (*ethclient.Client, *blockchain.Blockchain, error) {
// connect to polygon network
conn, err := ethclient.Dial(s.networkEndpoint)
if err != nil {
return nil, nil, err
}
// create contract client
contract, err := blockchain.NewBlockchain(common.HexToAddress(s.contractAddress), conn)
if err != nil {
return nil, nil, err
}
chainID, err := conn.ChainID(ctx)
if err != nil {
return nil, nil, err
}
s.chainID = *chainID
return conn, contract, nil
}
// track transaction to handle failure in go routine
func (s *service) trackTransaction(txn *types.Transaction, conn *ethclient.Client) {
receipt, err := bind.WaitMined(context.Background(), conn, txn)
defer conn.Close()
if err != nil {
log.Error("blockchain transaction failed with error", "error", err.Error())
}
if receipt.Status != types.ReceiptStatusSuccessful {
log.Error("blockchain transaction not successful")
}
}
// create contract with blockchain contract ID
func (s *service) CreateContract(ctx context.Context, contractID [32]byte) error {
conn, contract, err := s.getClient(ctx)
if err != nil {
return err
}
txn, err := contract.CreateContract(s.getTransactOpts(), contractID)
if err != nil {
return err
}
go s.trackTransaction(txn, conn)
return nil
}
// map devices with blockchain contract
func (s *service) RegisterNewDeviceIDs(ctx context.Context, contractID [32]byte, deviceIDs [][32]byte) error {
conn, contract, err := s.getClient(ctx)
if err != nil {
return err
}
txn, err := contract.RegisterNewDeviceIds(s.getTransactOpts(), contractID, deviceIDs)
if err != nil {
return err
}
go s.trackTransaction(txn, conn)
return nil
}
// store device data with blockchain contract
func (s *service) AddIOTData(ctx context.Context, contractID [32]byte, deviceID [32]byte, timestamp *big.Int, data []byte) error {
conn, contract, err := s.getClient(ctx)
if err != nil {
return err
}
txn, err := contract.AddIOTData(s.getTransactOpts(), contractID, deviceID, timestamp, data)
if err != nil {
return err
}
go s.trackTransaction(txn, conn)
return nil
}