如何使用Java发送以太坊交易

在表达了我对区块链技术的关注之后,让我们对区块链进行一些实践。 特别是以太坊。

我需要使用Java发送事务,因此我查看了EthereumJ 。 您有三种选择:

  • 全节点–启用同步,这意味着整个区块链都已下载。 这需要很多时间,所以我放弃了这种方法
  • “轻”节点–禁用同步,因此您只是成为网络的一部分,而不会获取链的任何部分。 不能完全确定,但是我认为这对应于geth的“轻”模式(以太坊CLI)。 您可以将消息(例如交易消息)发送给其他对等方以进行处理并存储在区块链上,但是您自己没有区块链。
  • 离线(无节点)–只需创建并签名交易,计算其原始表示(以太坊RLP格式),然后通过集中式API(例如etherscan.io API )将其推送到区块链。 Etherscan本身就是网络上的一个节点,它可以执行所有操作(因此它充当代理)

在进一步介绍之前,也许值得指出一下区块链的一些常规属性(至少以太坊和流行的加密货币)–它是一个分布式数据库,依赖于由谁拥有的对等网络(覆盖)运行客户端软件(钱包或其他)。 交易的形式为“我(私钥所有者)希望将此金额发送到该地址”。 事务可以在其中存储其他数据,例如,表示它们的含义。 然后,交易由同行进行验证(当前使用基于工作量证明的共识)并存储在区块链上,这意味着每个连接的同行都将获得新创建的区块(每个区块由多个交易组成)。 简而言之,这就是区块链,以太坊也不例外。

为什么要发送交易? 我想不出简单明了的用例,也许您只想实现比现有钱包更好的钱包。 例如, 在我的情况下,我想将散列链的头存储在区块链上,以免被篡改。

在我的特定情况下,我对存储作为交易一部分的特定数据比对交易本身更感兴趣,因此我有两个节点互相发送非常小的交易(随机选择发送者和接收者)。 我知道我可能可以通过智能合约来做到这一点,但是“每次只需一步”。 初始代码可以在此处找到 ,并且很大程度上基于EthereumJ示例。 由于EthereumJ在内部使用spring,而我的应用程序使用spring,因此花了一些额外的精力来允许两个节点,但这与手头的任务无关。 这段代码中最重要的部分可以在下面的文章中进一步看到,只需稍作修改即可。

您应该在类路径上具有一个user.conf文件,并带有一些默认值,并且该文件可以基于默认的ethereumj config 。 更为重要的部分是外部user1和user2 conf文件(在一般情况下,它们只能是一个conf文件)。 这是一个示例 ,具有以下重要参数:

  • peer.networkId –使用的是实际生产网络(= 1)还是测试网络(= 3)。 显然,除了生产之外,您还需要测试网络。 在测试网络上,您可以使用水龙头获得免费的乙醚。 为了使用测试网络,下面还有两个参数blockchain.config.name = ropstengenesis = ropsten.json 。 请注意,目前有更多的测试网络,用于试验工作量证明的替代方法。
  • peer.privateKey –这是最重要的位。 这是您的秘密密钥,可让您控制自己的区块链“帐户”。 只有使用该私钥,您才能签署交易(使用椭圆曲线算法)。 私钥有一个对应的公钥,该公钥基本上是您在网络上的地址-如果有人想发送资金,他会将其发送给您的公钥。 但是只有您可以从您的帐户中转入资金,因为没有其他人拥有私钥。 这意味着您必须保护它。 在这种情况下,它以纯文本格式存在于文件中,如果您使用大量的乙醚,这可能不是理想的选择。 考虑使用一些密钥管理解决方案(如此处所述 )
  • peer.ip.list –这是可选的,但更可取–您需要有一个要连接的对等方列表,以引导您的客户端并使之成为网络的一部分。 那里的对等节点连接到其他对等节点,依此类推,依此类推,因此最终是一个互连的网络。 请注意,如果在服务器/集群/堆栈上使用端口号,则需要与端口号结合使用,这需要一些其他网络配置–您必须打开一些端口并允许传出和传入连接。
  • database.dir –这是将存储区块链和已发现对等方列表的目录。 它使用了leveldb,而我发现ethereumj使用了一个过时的leveldb,该版本在我的机器上不起作用。 所以我排除了它们并手动使用了较新的版本
  • sync.enabled –是否要获取sync.enabled链。 通常您不需要,因为这会花费很多时间,但是那样您就不是一个完整的节点,并且不会对网络有所贡献。

如前所述,我不需要完整的节点,只需要发送事务即可。 轻型节点可以做到(区别应该只是将sync.enabled从true切换为false),但是在最初成功连接到对等节点之后,我开始遇到奇怪的异常,我没有时间去研究,所以我无法加入网络(可能是由于我当前正在使用的无线网络太差)。

幸运的是,有一种完全“脱机”的方法–使用外部API来发布您的交易。 您所需要做的就是您的私钥和一个库(在本例中为EthereumJ)来准备您的交易。 因此,您可以忘记在前面的段落中阅读的所有内容。 您只需要在签名后进行RLP编码的交易即可。 例如:

byte[] nonce = ByteUtil.intToBytes(getTransactionCount(senderAddress) + 1);
byte[] gasPrice = getGasPrice();
Transaction tx = new Transaction(
    nonce,
    gasPrice,
    ByteUtil.longToBytesNoLeadZeroes(200000),
    receiverAddress,
    ByteUtil.bigIntegerToBytes(BigInteger.valueOf(1)),  // 1 gwei
    data.getBytes(StandardCharsets.UTF_8),
    CHAIN_ID);
            
tx.sign(ECKey.fromPrivate(senderPrivateKey));
            
byte[] rawTx = tx.getEncoded();
            
restTemplate.getForObject(etherscanUrl, String.class, "0x" + BaseEncoding.base16().encode(rawTx));

在此示例中,我使用Etherscan.io API ( 对于Ropsten网络也有一个测试) 。 它还有一个手动输入表格来测试您的交易 (链接用于Ropsten测试网络)。

上面的参数是什么?

  • nonce –这是每个用户(=每个私钥)进行交易的序列号。 每个后续交易都应具有一个随机数,即即上一首+ 1的随机数。这样,​​任何人都无法重播同一笔交易并消耗发送方的资金(已签名的交易包含随机数,因此您不能使用同一原始交易表示并重新提交)。 如何获得随机数? 如果您连接到以太坊网络,则有一个ethereum.getRepository().getNonce(fromAddress); 。 但是,在断开连接的情况下,您需要获取发件人的当前事务数,然后对其进行递增。 这是通过eth_getTransactionCount端点完成的。 请注意,它以十六进制形式返回,因此您必须对其进行解析,例如{"jsonrpc":"2.0","result":"0x1","id":73}
  • 天然气价格,最高天然气价格–用于支付交易费用(不是免费发送)。 您可以在这里阅读更多内容 。 您可以通过调用“ eth_gasPrice” API端点来获取当前的汽油价格。 最好是定期定期获取汽油价格并将其缓存一段时间,而不是每次交易都获取价格。 如果您已连接到网络,则可以自动获取汽油价格。
  • receiverAddress –代表接收者公钥的字节数组
  • value –您要发送多少以太。 最小单位实际上是“ gwei”,该值以gweis(1 ETH的分数)指定。
  • data –您要放入事务中的任何其他数据。
  • chainId –再次与您使用的网络有关。 生产= 1,Ropsten测试网络= 3。 如果您好奇为什么必须在事务中对其进行编码,则可以在此处阅读 。

之后,使用私钥对事务的原始表示形式进行签名(原始表示形式为RLP(递归长度前缀) )。 然后将其发送到API(为此您需要一个密钥,可以在Etherscan上获得并将其包含在URL中)。 这几乎与您连接后的操作完全相同。 但是,现在您依靠的是中央方(Etherscan),而不是成为网络的一部分。

它可能看起来很“简单”,当您已经完成并掌握它时,听起来像是小菜一碟,但是细节太多了,没人能从您这里抽象出来,因此您必须先全面了解整个过程能够推动一项交易。 什么是随机数,什么是chainId,什么是测试网络,如何获取测试以太(罗普森水龙头的Google顶级搜索结果目前无法正常运行,因此您也必须弄清楚这一点),然后确定您是否要同步链,是否要成为网络的一部分,以解决奇怪的连接性问题和网络配置。 而且这甚至都没有提到智能合约。 我并不是说这很糟糕,这还不够简单,这是广泛采用的障碍。 不过,这可能适用于大多数编程。 无论如何,我希望以上示例可以使人们更轻松地开始工作。

翻译自: https://www.javacodegeeks.com/2017/08/send-ethereum-transactions-java.html

你可能感兴趣的:(java,区块链,比特币,python,分布式)