GethNode.cs
1 using BlockchainUtils; 2 using Core; 3 using KubernetesWorkflow.Types; 4 using Logging; 5 using Nethereum.ABI.FunctionEncoding.Attributes; 6 using Nethereum.BlockchainProcessing.BlockStorage.Entities.Mapping; 7 using Nethereum.Contracts; 8 using Nethereum.RPC.Eth.DTOs; 9 using NethereumWorkflow; 10 using Utils; 11 12 namespace GethPlugin 13 { 14 public interface IGethNode : IHasContainer 15 { 16 GethDeployment StartResult { get; } 17 EthAddress CurrentAddress { get; } 18 19 Ether GetEthBalance(); 20 Ether GetEthBalance(IHasEthAddress address); 21 Ether GetEthBalance(EthAddress address); 22 string SendEth(IHasEthAddress account, Ether eth); 23 string SendEth(EthAddress account, Ether eth); 24 TResult Call<TFunction, TResult>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); 25 TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new(); 26 void Call<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); 27 void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new(); 28 string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); 29 Transaction GetTransaction(string transactionHash); 30 decimal? GetSyncedBlockNumber(); 31 bool IsContractAvailable(string abi, string contractAddress); 32 GethBootstrapNode GetBootstrapRecord(); 33 List<EventLog<TEvent>> GetEvents<TEvent>(string address, BlockInterval blockRange) where TEvent : IEventDTO, new(); 34 List<EventLog<TEvent>> GetEvents<TEvent>(string address, TimeRange timeRange) where TEvent : IEventDTO, new(); 35 BlockInterval ConvertTimeRangeToBlockRange(TimeRange timeRange); 36 BlockTimeEntry GetBlockForNumber(ulong number); 37 void IterateTransactions(BlockInterval blockRange, Action<Transaction, ulong, DateTime> action); 38 void IterateFunctionCalls<TFunc>(BlockInterval blockInterval, Action<BlockTimeEntry, TFunc> onCall) where TFunc : FunctionMessage, new(); 39 IGethNode WithDifferentAccount(EthAccount account); 40 } 41 42 public class DeploymentGethNode : BaseGethNode, IGethNode 43 { 44 private readonly ILog log; 45 private readonly BlockCache blockCache; 46 47 public DeploymentGethNode(ILog log, BlockCache blockCache, GethDeployment startResult) 48 { 49 this.log = log; 50 this.blockCache = blockCache; 51 StartResult = startResult; 52 CurrentAddress = new EthAddress(startResult.Account.Account); 53 } 54 55 public GethDeployment StartResult { get; } 56 public RunningContainer Container => StartResult.Container; 57 public EthAddress CurrentAddress { get; } 58 59 public GethBootstrapNode GetBootstrapRecord() 60 { 61 var address = StartResult.Container.GetInternalAddress(GethContainerRecipe.ListenPortTag); 62 63 return new GethBootstrapNode( 64 publicKey: StartResult.PubKey, 65 ipAddress: address.Host.Replace("http://", ""), 66 port: address.Port 67 ); 68 } 69 70 protected override NethereumInteraction StartInteraction() 71 { 72 var address = StartResult.Container.GetAddress(GethContainerRecipe.HttpPortTag); 73 var account = StartResult.Account; 74 75 var creator = new NethereumInteractionCreator(log, blockCache, address.Host, address.Port, account.PrivateKey); 76 return creator.CreateWorkflow(); 77 } 78 79 public IGethNode WithDifferentAccount(EthAccount account) 80 { 81 return new DeploymentGethNode(log, blockCache, 82 new GethDeployment( 83 StartResult.Pod, 84 StartResult.DiscoveryPort, 85 StartResult.HttpPort, 86 StartResult.WsPort, 87 new GethAccount( 88 account.EthAddress.Address, 89 account.PrivateKey 90 ), 91 account.PrivateKey)); 92 } 93 } 94 95 public class CustomGethNode : BaseGethNode, IGethNode 96 { 97 private readonly ILog log; 98 private readonly BlockCache blockCache; 99 private readonly string gethHost; 100 private readonly int gethPort; 101 private readonly string privateKey; 102 103 public GethDeployment StartResult => throw new NotImplementedException(); 104 public RunningContainer Container => throw new NotImplementedException(); 105 public EthAddress CurrentAddress { get; } 106 107 public CustomGethNode(ILog log, BlockCache blockCache, string gethHost, int gethPort, string privateKey) 108 { 109 this.log = log; 110 this.blockCache = blockCache; 111 this.gethHost = gethHost; 112 this.gethPort = gethPort; 113 this.privateKey = privateKey; 114 115 var creator = new NethereumInteractionCreator(log, blockCache, gethHost, gethPort, privateKey); 116 CurrentAddress = creator.GetEthAddress(); 117 } 118 119 public GethBootstrapNode GetBootstrapRecord() 120 { 121 throw new NotImplementedException(); 122 } 123 124 public IGethNode WithDifferentAccount(EthAccount account) 125 { 126 return new CustomGethNode(log, blockCache, gethHost, gethPort, account.PrivateKey); 127 } 128 129 protected override NethereumInteraction StartInteraction() 130 { 131 var creator = new NethereumInteractionCreator(log, blockCache, gethHost, gethPort, privateKey); 132 return creator.CreateWorkflow(); 133 } 134 } 135 136 public abstract class BaseGethNode 137 { 138 public Ether GetEthBalance() 139 { 140 return StartInteraction().GetEthBalance().Eth(); 141 } 142 143 public Ether GetEthBalance(IHasEthAddress owner) 144 { 145 return GetEthBalance(owner.EthAddress); 146 } 147 148 public Ether GetEthBalance(EthAddress address) 149 { 150 return StartInteraction().GetEthBalance(address.Address).Wei(); 151 } 152 153 public string SendEth(IHasEthAddress owner, Ether eth) 154 { 155 return SendEth(owner.EthAddress, eth); 156 } 157 158 public string SendEth(EthAddress account, Ether eth) 159 { 160 return StartInteraction().SendEth(account.Address, eth); 161 } 162 163 public TResult Call<TFunction, TResult>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() 164 { 165 return StartInteraction().Call<TFunction, TResult>(contractAddress, function); 166 } 167 168 public TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new() 169 { 170 return StartInteraction().Call<TFunction, TResult>(contractAddress, function, blockNumber); 171 } 172 173 public void Call<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() 174 { 175 StartInteraction().Call(contractAddress, function); 176 } 177 178 public void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new() 179 { 180 StartInteraction().Call(contractAddress, function, blockNumber); 181 } 182 183 public string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() 184 { 185 return StartInteraction().SendTransaction(contractAddress, function); 186 } 187 188 public Transaction GetTransaction(string transactionHash) 189 { 190 return StartInteraction().GetTransaction(transactionHash); 191 } 192 193 public decimal? GetSyncedBlockNumber() 194 { 195 return StartInteraction().GetSyncedBlockNumber(); 196 } 197 198 public bool IsContractAvailable(string abi, string contractAddress) 199 { 200 return StartInteraction().IsContractAvailable(abi, contractAddress); 201 } 202 203 public List<EventLog<TEvent>> GetEvents<TEvent>(string address, BlockInterval blockRange) where TEvent : IEventDTO, new() 204 { 205 return StartInteraction().GetEvents<TEvent>(address, blockRange); 206 } 207 208 public List<EventLog<TEvent>> GetEvents<TEvent>(string address, TimeRange timeRange) where TEvent : IEventDTO, new() 209 { 210 return StartInteraction().GetEvents<TEvent>(address, ConvertTimeRangeToBlockRange(timeRange)); 211 } 212 213 public BlockInterval ConvertTimeRangeToBlockRange(TimeRange timeRange) 214 { 215 return StartInteraction().ConvertTimeRangeToBlockRange(timeRange); 216 } 217 218 public BlockTimeEntry GetBlockForNumber(ulong number) 219 { 220 return StartInteraction().GetBlockForNumber(number); 221 } 222 223 public BlockWithTransactions GetBlk(ulong number) 224 { 225 return StartInteraction().GetBlockWithTransactions(number); 226 } 227 228 public void IterateTransactions(BlockInterval blockRange, Action<Transaction, ulong, DateTime> action) 229 { 230 var i = StartInteraction(); 231 for (var blkI = blockRange.From; blkI <= blockRange.To; blkI++) 232 { 233 var blk = i.GetBlockWithTransactions(blkI); 234 var blkUtc = DateTimeOffset.FromUnixTimeSeconds(blk.Timestamp.ToLong()).UtcDateTime; 235 236 foreach (var t in blk.Transactions) 237 { 238 action(t, blkI, blkUtc); 239 } 240 } 241 } 242 243 public void IterateFunctionCalls<TFunc>(BlockInterval blockRange, Action<BlockTimeEntry, TFunc> onCall) where TFunc : FunctionMessage, new() 244 { 245 IterateTransactions(blockRange, (t, blkI, blkUtc) => 246 { 247 if (t.IsTransactionForFunctionMessage<TFunc>()) 248 { 249 var func = t.DecodeTransactionToFunctionMessage<TFunc>(); 250 if (func != null) 251 { 252 var b = GetBlockForNumber(blkI); 253 onCall(b, func); 254 } 255 } 256 }); 257 } 258 259 protected abstract NethereumInteraction StartInteraction(); 260 } 261 }