heyuan 发布的文章 - 六币之门
首页
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
搜 索
1
融资周报 | 公开融资事件11起;加密技术公司Toposware完成500万美元融资,Polygon联创参投
112 阅读
2
六币日报 | 九只比特币ETF在6天内积累了9.5万枚BTC;贝莱德决定停止推出XRP现货ETF计划
76 阅读
3
融资周报 | 公开融资事件27起;L1区块链Monad Labs完成2.25亿美元融资,Paradigm领投
74 阅读
4
六币日报 | 美国SEC再次推迟对灰度以太坊期货ETF做出决定;Do Kwon已出黑山监狱等待引渡
72 阅读
5
【ETH钱包开发06】查询某个地址的交易记录
55 阅读
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
登录
搜 索
标签搜索
新闻
日报
元歌Eden
累计撰写
1,087
篇文章
累计收到
0
条评论
首页
栏目
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
页面
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
用户登录
登录
找到
1087
篇与
heyuan
相关的结果
2023-03-24
全面系统的 Web3 学习路线,助你成为 Web3 开发专家
今天学习 Web3 和区块链开发就像昨天以 10 美元购买比特币一样。区块链行业的薪水是非常可观的,全球范围内从事 Web3 的程序员平均年薪约为 14 万美元,当然国内可能会比这个平均年薪低一些,但仍然高于 Web2.0 的程序员。这可能是作为一个开发人员现在可以做出的最佳投资选择。但是互联网上缺乏关于 Web3 的高质量资源,你很快就会发现,你虽然想学习 Web3 的开发,但是却不知道从哪儿开始。我从 12 年跟着同学玩 BTC,后来把 6 个多 BTC 换了一个 LOL 两百多个皮肤的账号。即使现在 BTC 暴跌,6 个多 BTC 也能值 80 万左右人民币,但是我的那个 LOL 账号估计连卖几百块都难。中间好几年没有怎么继续接触数字货币。直到 17 年左右才开始重新接触数字货币,刚开始和朋友合伙挖矿,那时候天天跑机房,闲鱼买显卡,隐约记得那阵 RX 460 470 480 显卡性价比极高。后来开始炒币,天天盯盘,各种币都买,也碰到过百倍币。赚过一些钱,也赔过很多钱。19 年我和朋友合作开发了一个区块链项目,用在本地一家大型的工业园区的建筑工地中,用来对建材进行追踪治理,很大程度上节约了成本,当然也得罪了一些人,因为区块链的可追溯性让一些原本能够在建材上面偷工减料的人没了钱赚,不过这种方式是园区的总经理大力支持的,实施下来虽然有阻力,但控制成本、追踪治理的效果也很显著。在这个过程中,我也一直关注 Web3 的发展,从只知道概念,到逐渐学会了 solidity 语言、DApp 的开发等。但是从来没有认真细致地系统性归纳自己在 Web3 方面的知识体系。所以趁最近时间充足,多花些时间根据我个人对 Web3 的实际经验,整理一套关于 web3 和 Solidity 的学习路线。这个学习路线足以让你从一个对 web3 完全零基础的 web2.0 开发人员过渡到 Solidity 语言专家和区块链专家。区块链基础知识区块链是 web3 的基础。你首先要了解它是如何工作的,以及它为什么会彻底改变我们交换商品和支付的方式。区块链技术不仅仅是和加密货币有关,而是已经成为真正的分布式云计算系统,能够运行完整的后端(为了和 web2.0 时代的后端进行区分,我有时也习惯称它为链端)来为前端的去中心化应用程序 (DApp) 提供动力。在学习完区块链基础知识后,你应该能够准确回答出以下问题:Web1.0、Web2.0 和 Web3 的区别? 什么是区块链? 什么是分布式账本? 什么是加密货币? 什么是加密钱包? 什么是区块链浏览器? 去中心化应用基础知识当你了解了什么是区块链、Node、共识机制和这些技术的主要组件后,你应该会思考:“我可以使用区块链开发什么样的应用程序?”建立在区块链之上的应用被称为去中心化应用或者被称为 DApp,它在大的结构上和传统 Web2.0 应用很像,包含两个部分:使用 JavaScript 或 React、Vue、Svelte 等框架/库构建的标准前端。 使用 Solidity/Solana/Rust 等语言构建的后端,它们建立在区块链之上。 你除了要了解什么是去中心化应用,还要了解 DApp 的前端和后端是如何通信和交换数据的,你需要学习前端开发和后端开发,并且需要掌握 API 的基本原理。前端开发相关知识前面我有提到,去中心化应用需要有一个标准的前端项目,这就是为什么在开发你的第一个 DApp 之前,需要去学习前端开发的理由。前端框架非常多,也非常复杂。我建议你只选择其中一门就可以了,比如当前使用人数最多的 React。后端开发相关知识DApp 的后端和传统 Web2.0 的后端有很多不同之处,其中最明显的是 DApp 的后端需要使用区块链作为去中心化数据存储的主要方式,而传统后端通常使用数据库或对象存储来存储数据。但是大多数技术原则仍然保持不变。这里我建议你去选择一些比较流行的技术,比如学习 Node 和 Express。或者学习基于 React 和 Express 的全栈框架 Next.js。以太坊概念和原理以太坊是在计算机网络中运行的一种软件,同时也是一种数字货币。大多数 DApp 现在都运行在以太坊区块链之上,智能合约概念也是由以太坊联盟首先推出的,然后被其他区块链抄袭。每个区块链都有自己的生态系统,我们要从其中选择一条。它们各自有各自的特点和优势,但是我推荐以太坊,原因是互联网上面关于以太坊的资料非常丰富。要想在 2022 年成为 web3 和 Solidity 开发人员,了解以太坊的概念和原理是关键。当你学完以太坊的概念和原理有,你应该能够准确回答以下问题:什么是账户? 什么是交易? 什么是块? 什么是以太坊虚拟机? 什么是 Gas? 什么是节点? 什么是以太坊网络? 什么是共识算法? 什么是以太坊三难困境? 什么是信标链? 什么是侧链? 什么是合并? 智能合约的概念以太坊和智能合约的关系就像微信和小程序,两者都需要了解。智能合约是存储在基于区块链的平台上的软件,可以自动执行协议。可以编写智能合约的语言有 Solidity、Rust 和 Vyper,其中最流行的是 Solidity。它是所有 DApp 的关键组件,运行 DApp 的业务逻辑并允许你在区块链上存储信息。Solidity&Remix了解了智能合约,接下来你要学习怎么样编写自己的智能合约,并使用它来支持你自己的 DApp。虽然有多种语言可以编写智能合约,但我仍然推荐你学习 Solidity。Solidity 是一种用于编写智能合约的高级、面向合约的编程语言,它允许程序员编写为区块链 DApp 提供动力的自执行代码。Remix 是一款专门支持 Solidity 编写智能合约的编辑器。它运行在浏览器中,默认情况下,编译部署测试都不需要任何配置。HardHatRemix 虽然很强大,但根据我的经验来看,在本地搭建智能合约开发环境会有更好的体验。而 HardHat 就可以帮助我们实现这个目的,让我们在 VSCode 中编写 Solidity 智能合约项目。HardHat 可以在多条链上创建、测试和部署 DApp,比如 Polygon、Ropsten、Ethereum Mainnet 等。你还可以用它启动本地以太坊节点来测试你的智能合约,不需要将它们部署到公共区块链上。Web3.js/Ethers.js当你能够使用 Solidity 编写智能合约后,你还需要学习如何将你的前端连接到使用 Solidity 开发的后端。虽然和传统的 Web2.0 有些差异,但通讯方式仍然是类似 HTTP 或者 WebSocket 的东西。在这个点上,有两个库可以选择:Web3.js 和 Ethers.js。Web3.js 功能更加全面,Ethers.js 更加轻量。在用户数量上相差不多,但是在 npm 上面 Web3.js 的下载量会更高一些,你可以优先学习 Web3.js。Alchemy在 Web2.0 中有很多云厂商可以为我们提供部署的基础设施服务,国外的有 AWS,国内有阿里云等。我们可以把 Alchemy 想象成 Web3 中的 AWS,它为部署 DApp 提供了所有需要的基础设施。Alchemy 还具有更多功能,比如为我们提供了 API 来部署 NFT 集合,而且不需要编写一条行 Solidity 代码;连接到链上事件的通知;以及带有智能套接字和扩展以太坊 API的增强型 Web3 库。DApp 的类型在开发我们的 DApp 之前,我们要先学习一些其他 DApp,了解我们可以做哪些 DApp。常见的类型有加密货币、加密钱包、区块浏览器、NFT 市场、DeFi 应用和基于区块链的游戏。每一种类型的 DApp 你都应该去了解。开发第一款 DApp当你把上面的东西全部学会后,就应该来做一个 DApp 来验证你的学习成果了。如果你不知道该开发什么样的 DApp,那我给你的建议就是做一个加密货币或者 NFT 市场。如果你实在不知道自己该做什么 DApp,我可以告诉你一个技巧,你可以去一些招聘网站,看看那些高薪招聘 Web3 开发人员的公司都在做些什么,然后你照着做就可以了。truffle&ganache&drizzleWeb2.0 的世界里有各种各样的框架,Web3 同样不例外。truffle 是一款区块链框架,它提供了开发区块链应用中会用到的大多数功能。适用于任何以太坊虚拟机(EVM)区块链的开发环境、测试框架和资产管道。除了 truffle 自身以外,它还提供了 ganache 和 drizzle。ganache 用于开发个人区块链,可以部署合约、开发应用和测试。drizzle 是一组前端库,在编写 DApp 的前端时更加容易和更加可观测。它是基于 Redux 的。测试智能合约和传统的 Web2.0 应用不同,区块链的特别之处在于不可逆转性,一旦添加了智能合约,就无法编辑和召回了,而且在部署时也需要花费 Gas 费。所以测试对 Web3 的 DApp 而言尤其重要。测试智能合约的方式有:节点测试 功能测试 性能测试 API 测试 MoralisMoralis 为区块链项目提供托管后端。自动将你的用户余额同步到数据库中,你还可以设置链上警报、观看智能合约事件、构建索引等等。所有功能都通过易于使用的 SDK 实现的。而且 Moralis 提供的所有功能默认都是跨链的。简单来说,Moralis 可以让你在几秒钟内创建一个成熟的 DApp,利用基于钱包的身份验证系统的强大功能可以直接从区块链获取数据,并把它们保存在 NoSQL 数据库中,这些功能都只需要几行代码就可以轻易实现。总结我的思路是概念优先。在真正开发之前,我从来没有让你写代码。我认为如果你连自己要做什么都不知道的话,是没办法直接写代码的。先从基本概念入手,一定不会错。至今为止,Web3 的变化依然很大,这篇文章也会有时效性,如果有了新的变化我也会同步更新。学习 Web3 什么时候都不晚,希望你可以早日加入 Web3 世界!
2023年03月24日
6 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-9 离职黑屋
(19) 离职黑屋郝公子年前有关丰厚年终奖的小道消息最终被证实是谣传。我们部门非但没有得到可观的奖金,作为不能给集团带来直接利益,每年还需大量资金投入的IT部门,外加集团分管技术领导贪腐等原因,部门年终奖被取消了。我真是欲哭无泪,赔了夫人又折兵。郝公子找到我,为年前放的那个烟雾弹向我表达了深深的歉意。为了安抚我那颗受伤的心,他主动为我打探来了离职的详细流程。我把离职申请交给了组长老周,老周再三挽留,见我去意已决,也不再规劝,在离职申请书上签了字。我带着离职申请书又敲了部门经理办公室的门。经理很是痛快,大笔一挥,就签下了名字,整个过程头都没抬。像我这样的虾兵蟹将,经理平时都没正眼瞧过。我估摸从加入公司到离开公司,他都不晓得我姓甚名谁。谁承想这个国企进来的时候不容易,想要离开更是困难重重。离职申请虽然获得了领导的批准,但我还需要经历一个月的脱密期才能真正地走完离职流程。由于我曾经参与了国家大型项目的研发,掌握着国家的机密,我必须在把所有秘密从脑袋里清除掉后,才被允许离职。事实上,哪里有什么国家机密,我们平常做得最多的就是从网上,从书里摘抄别人的技术方案,然后改改名字,调整下措词,包上一层皮,就变成了不可外泄的核心技术。那些所谓的核心机密在网上随处可见,当然欺骗一些不懂技术的领导还是绰绰有余。技术在这里从来都不是最重要的。不过既然组织上有脱密的规定,谁也不能破例,我坚决服从组织上的安排。离职申请被批准后的第二天,我所有的办公用品立马被公司收回。公司有专门为离职人员提供的脱密办公区,我们称之为小黑屋。集团所有离职人员必须在小黑屋呆上一定日期后才被允许离开。作为入职不满一年的新员工,我的脱密期只有一个月,倒也不算太过漫长。倘若你为公司服务了超过十年,那么你的离职脱密期至少是半年,层级更高的领导甚至是一年。脱密期间,我每天必须来公司报道,按时打卡,跟正常上下班无异。公司会照常发放基本工资,因为没有绩效,所以工资比往常低不少。这种不用干活还给钱、无功受禄的好事听起来似乎还不错。实际上,对于我们这群想赶紧抽身的人却是一种煎熬。其实整日无所事事地坐在一个密室里,倒还不如被雪花般的任务包围,这样日子还能过得快一些。被关小黑屋后,我一边按时上下班,一边在网上投递简历。一二三四五,脱密真辛苦,一台破手机,一坐一上午。许多互联网公司的面试可以在电话里进行,我在小黑屋里经历了几场电话面试。不过,由于小黑屋信号差,外加自身紧张,面试过程沟通不甚流畅。在与几家心仪公司失之交臂后,我决定还是等脱密期结束后再正式找工作。我把简历发给老潘,想让他帮我内推一下他们公司的技术团队。老潘却直摇头,他说并不是对我的技术信不过,而是不建议我去他们公司。在他眼里,他们公司的程序员就是一群混子,拿钱不干事,有事就推脱。难题解决不了,简单事又不愿意干。为了打消我迎难而上,死乞白赖去他们公司的想法,老潘给我讲了不少他所在产品组跟开发组斗智斗勇的事儿。那些互相使绊子,送黑锅的事迹,惊得我是一身冷汗。有人的地方就有江湖,江湖上,人人都想争夺话语权。产品跟技术水火不容的那些事儿,时常被业界讨论,还生出了许多网络段子在技术圈里流传。我先前听过不少,只是没承想在老潘公司,两伙势力对抗之如此激烈。老潘他们公司在业界以产品精良而著称,技术实力并不算很强。程序员在他们公司地位肯定不如产品经理不高。宁做鸡头不做凤尾。我更愿意找一家程序员地位比较高的公司。并不指望对别人颐指气使,但也不至于忍气吞声,被人凌辱。小黑屋很是逼仄,但囿不住我对未来的无限畅想。(20) 求职之路脱密的一个月里,我度日如年。周遭几个同病相怜的人靠玩手游消磨时光,而我没有丝毫懈怠,整日裸泳于知识的海洋。我越学越觉得自己菜,越觉得自己菜就越想学。幸好在学习上形成了一个良性循环。自我感觉进步神速,特别渴望去市场上检验一下自己的卖价。立夏过后没几天,我的离职流程终于顺利走完。我把工牌上交,悄摸地就走了,没有给老东家留下任何挽留我的机会,从此相忘于江湖。虽有了自由之身,我却不敢有片刻清闲,迅速投入到了兵荒马乱地找工作中去。开启一段新的求职历程,我原本以为自己已经准备充足。可是真到了需要面对洗礼的时候,我又不争气了起来,紧张又焦躁。可开弓没有回头箭,我只得硬着头皮就是干。老潘建议我先找一些不知名的企业练练手,见识一下当前互联网技术领域的面试流程与面试难度。等我各个方面都准备得都差不多了,再去投递心仪的公司,这样被录取的几率会更大一些。我接受了老潘的建议,在几大招聘网站上投递了近百封简历,每日焦急地等待着面试邀请。知名国企这个背景在求职过程中并没有给我有所加分。反倒是由于近一年都是在国企里做方案设计,没有从事一线编程,很多公司由此怀疑我的技术能力。投递出去的简历很多都石沉大海,杳无音信。幸好在2014年,中国互联网行业还处于红利期,当时的求职环境对于程序员特别有利。新兴的互联网公司不断涌现,并且急速扩张。老牌知名互联网公司积极拓展新业务。编程人员供不应求。我陆续接到一些小公司的面试邀请,开始忙碌起来。许多小公司出于对成本考虑,一般会选择市郊租金比较便宜的地段。我经常是上午还在昌平跟面试官谈笑风生,下午就得赶到大兴参加笔试。终日在北京城里奔波,几乎每条地铁线路都留下了我的足迹。辛苦倒也谈不上,只是一次又一次地被公司拒绝,让人有些沮丧。别看许多初创公司规模不大,但人家的要求可不低。更希望找一个在方方面面都能上手的人,用技术圈的术语来说就是全栈工程师。在编程上荒废了近一年,我需要恶补的知识实在是太多。专注钻研一个领域就已经耗费了我大部分精力。短时间内,我肯定无法胜任全栈,所以悲剧在所难免。一轮轮面试下来,给人最深的体会就是:公司在面试应聘者的时候,恨不得希望他能有研制出原子弹的本事。事实上,被招进去后,大多数人都成了流水线上的螺丝钉。互联网技术更新换代的速度极快,可以天计。在面试过程中,我已经听到了太多闻所未闻的新技术,新名词。一次次面试失败,一次次总结经验教训。被算法难到了,就恶补算法;被编程框架问住了,就恶补框架。我深知技术这个领域没有什么捷径可走,唯有天道酬勤。业界对于程序员的考察从来都很简单粗暴。不需要你有多么出众的口才,也不需要你有多么好看的皮囊。借用国外开源大神Linus的一句话就是:“Talk is cheap,show me the code。”点击进入下一章点击从第一章开始阅读ps:欢迎各位关注我,文章更新的消息会在「掘金动态」里滚动,同时七筒也欢迎大家在动态的评论区给我评论。此致敬礼,感谢各位厚爱。
2023年03月24日
5 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-24 加班狂魔
(52) 放纵自我跟李亚男分手后,恢复单身的老潘跟我约饭多了起来。果然女人是男人友谊的最大羁绊。我几次建议老潘搬回幸福公寓继续跟我一起住,老潘推辞不受。后来,我才发现,原来这厮不愿与我合租,是怕我搅乱他的良宵美景。他破罐子破摔,放飞自我,肆意纵情,在网上不断地撩妹约炮。难道一个李亚男就让他变成了这样?我不知道二人究竟建立了多深的感情?分手对老潘有多大的打击?我只知道老潘如此这般作践自己,对他是百害而无一利。我规劝老潘,嫖海无涯,回头是岸。不知是我面子够大,还是老潘资金有所匮乏,他渐渐也有所收敛。由电商巨头阿里巴巴发起的双十一狂欢购物节已经成为了电商领域年度最大的盛会。去年,阿里巴巴在美国纳斯达克上市,市值一路飙升,可谓风光无限。作为阿里巴巴上市之后的第一个双十一,今年他们大秀肌肉,活动力度特别大。行业龙头吃肉,小弟们喝汤。老潘就职的公司主营奢侈品销售,旗下有一款业内知名的购物App。临近双十一,老潘作为App的产品经理,每天被雪花般的需求压着。为此,他通宵达旦,吃睡公司,甚是忙碌。寒冬将至,雾霾来袭。一年一度的逃离北上广的相关文章再次风靡于朋友圈。文章鞭辟入里,讲述各种缘由,楼价高涨、交通堵塞、空气污染,生活压力加剧......文章素材翔实,有着各种事例,程序员小张,卖煎饼的大李,开黑车的老王......总之,结论就是北上广不欢迎穷人。不过,今年的舆论风向倒是有所改变。有一些人站出来,发表了不同的观点。他们大都是先前逃离北上广、回家乡打拼的人。回到家乡后,他们失望地发现,家乡的楼价也涨了,雾霾也重了,堵车也是家常便饭了。北上广的弊病正迅速在中小城市里蔓延。一向不抱怨生活的老潘,最近频频跟我诉苦。他正犹豫做完双十一后是否离开北京这个伤心之城。换个地方,或许风景独好。2014年11月16日,北京集中供暖后的第一天,重度雾霾席卷华北大地。月朦胧,鸟朦胧,空中雾霾浓。山朦胧,树朦胧,喉咙有点痛。花朦胧,叶朦胧,医院排长龙。公寓附近超市的防霾口罩均已脱销。上班路上,我不得不埋头衣袖,掩鼻前行。双肩包被地铁口的护栏勾住,我一使劲儿变成了单肩包。晨会上,康神说潜龙的开发进度不容乐观,急需增加人手。我跟王旭被安排进了"潜龙"后台开发小组。不知是福是祸,我俩也没有选择的余地,一切听从领导安排。加入潜龙项目这天刚好是我的农历生日。徒增一岁,在他乡的第5个生日,没有礼物也没有蛋糕。晚饭过后,老妈打来电话,对我好一番嘱托。慈母口中语,游子伏案思。电话那头老姚一直在老妈旁边小声嘀咕,老妈充当着我俩的传话筒。成年后,父与子大抵都这样吧,明明互相挂念却故作矜持。老潘把借我的钱还清了,还给我发了个88块钱的大红包。嘘寒问暖不如红包巨款,也算他有良心。沉默许久的大学舍友群里也活跃了起来。昔日兄弟们借着我生日契机发了几个小额红包。等到手机屏幕被红包占满后,我们又开启了漫无边际地扯淡。我一边敲代码调试程序,一边有一搭没一搭地在群里跟他们聊近况。留在邮大读研究生的李冀,被导师外派到一家创业公司做实习生,跟我一样每天加班加点,忙成狗。回老家找了份国企工作的冯振,朝九晚五,老婆孩子热炕头,羡煞众人。去欧洲留学的马天华,整日跨国游荡,不务正业,在朋友圈里晒着巴黎的埃菲尔铁塔,伦敦的大本钟,好个逍遥自在。毕业一年多,大家都还没变,还是那般猥琐。下班回到公寓住所,我躺在床上,像往常一样在网络里四处游荡。在时针逼近12之时,我突然意识到遗漏了一项重要仪式。我快速下床,打开电磁炉,煮了碗面条,还加了个蛋,权当长寿面。待我吃完面条,时针正好划过12。24岁生日就这样过去了。若孤独是人生的必修课,当下我只盼望赶紧修满学分,尽早毕业。(53)生如咸鱼由于潜龙的定位以及开发需求一直在变化,项目排期一再拖延,可交付的时间却雷打不动。于是,开发周期最后被压缩了近三分之一。公司在年底将会举行一场新产品发布会,CEO会在大会上重点推介几款公司新产品,潜龙将会压轴出场。CEO关注的产品,部门领导必然很是重视。工期被压缩,按期上线的形势并不乐观,可延期发布又不可能。于是,整个潜龙项目组开启了无休止的加班模式。我便过上了996的生活(所谓996就是每天上班时间是早九点到晚九点,一周上六天班)。明面上说是996,实际上到了晚上九点,大家根本就走不了,一般都得熬到10点甚至更晚。互联网领域,大部分公司都提倡自愿加班。所谓自愿就是不用支付额外的加班费用。大家心有抱怨,却也无人反抗,为了三五斗米折腰。当然,也不是所有人都厌恶加班。客户端组有个刚入职的应届生,许是技术能力稍逊需要加班加点赶工;或是刚走入职场,体力充沛,拼劲儿十足。他买了张行军床放在工位旁,还从家里带来了洗漱用品。最近一段时间,他一直吃睡在公司,以公司为家。有几次我来公司稍早,瞧见他正躺在行军床上,四仰八叉地酣睡。杀猪般的呼噜声在屋子里回荡。金子总会发光,优秀的人终不会被遗忘。小伙的光荣事迹被同事发到公司内网论坛,一时间他成为了公司热议人物。部门老总知悉后,写了一封催人泪下的表扬信。不过,领导在表扬信的最后明确指出并不提倡大家效仿,老总们希望我们每个人都能有一个健康的体魄,为公司努力奋斗五十年。领导话讲得很是漂亮,可真实的研发任务压在每个人头上,不加班加点根本就干不完。当然,能力强如我师父王旭那般的人,他们能够很快把任务做完。可即便如此,他们也不会干完活就立刻回家,因为有一只无形的手在摁压着他们的脊背。九点过去了,十点过去了,十一点过去了,大家仍端坐在工位上紧张忙碌。各级老大巡视办公区,一个个端着泡满枸杞的茶杯,矗立在一隅,望着兢兢业业的小弟们,满脸欣慰。在这样的气氛烘托下,若是你提前回家,便会有一种在战场上败退,当了个逃兵的感觉。于是,在每个加班到深夜的日子里,有一部分人在大部分时间里都是演员。他们积极地扮演着老板们喜欢的样子。只有老板喜欢,才能有一个好的绩效。有了好的绩效才能有不菲的年终奖。有了不菲的年终奖,日子才能过得舒坦些。学好文武艺,卖与资本家。日子一天天地重复着,我忙得来不及思考人生。每天行尸走肉般地挤着地铁上下班,吃着那仅仅为了饱腹并不可口饭菜,聆听着那繁琐无趣又不可或缺的开发会议。秋分过后,昼短夜长。又是一个漫长的黑夜,大风吹散雾霾,美妙星辰,灿烂霓虹。黑色大幕拉开,我坐在办公室落地窗前,借着喝水的间隙,凝望远处。对面的千度大厦,旧浪大楼如我们朗云大厦一般,灯火通明。加班已经成为我们这个行业的生存常态。十多年前,软件园这里还是一片荒地,遍地飞禽走兽。短短几年光景,这里已经成为了帝都夜生活最丰富的区域之一。北京城的广大出租车司机特喜欢来这片区域接活,因为这里永远有拉不完的客人。我们这群程序员时常会成为司机们忙碌一天的最后一位客人。周五,康神召开组会,他见大家都神情呆滞,面露疲态,便给我们画起了大饼。他说项目交付后,会安排一场出国游犒劳我们。听王旭说,去年组里团建,行政小姐姐给他们提供了十多条旅游路线。上山下海,宝马香车,飞机游轮,应有尽有,活动特别丰富,公司也很大方,提供人均三千元的预算。不过对于那些方案,组里人都不甚满意,要么太累,要么太远,要么太贵。他们又是头脑风暴,集思广益,又是发起投票,尊重民意。几轮磋商,终于达成一致。阳春三月,他们在天津一家五星级宾馆里睡了三天三夜,打了三天的麻将。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
7 阅读
0 评论
0 点赞
2023-03-24
区块链不谈技术的都是韭菜——区块链技术组成及架构
三个最底层的技术数据关系加密化数据不可篡改点对点网络让数据永不下线核心技术概念区块挖矿和共识机制Merkle Tree区块链适合什么不适合什么?区块链应用交易模型身份认证体系智能合约结语最近一直在研究区块链,算是从以前听说过,到现在大概了解一些。先说下自己学习过程中的感受,那就是“干!能不能把话说明白些。”大部分学习材料都存在结构混乱,或者对一个点单薄,无法深入浅出。至于那些还在拿着露天麦喊什么是区块链,错过后悔一辈子的,都是骗子。我相信现在很多投资机构都在瞄区块链,今年,即使AI也没有区块链这么火爆。那么对于一个区块链项目,到底靠不靠谱,是在画饼,还是真的可能搞成,所有人都应该擦亮眼睛。三个最底层的技术谈区块链最好先抛开各种币的价格,价格这种事你懂的,贵和便宜根本不是人能控制的。但是基于区块链技术去做项目,却是实实在在可以可持续发展。所以,了解区块链技术比炒币来的实在。“区块链”三个字并不能阐明这项技术的全部,如果要非要用可以完整表达的命名,我觉得应该叫“Peer-to-Peer Encrypted Non-Tampered Database”,即“点对点的加密化不可篡改数据库”。它不一个数据库(比如MySQL,MongoDB),也不是一类数据库(比如SQL,NoSQL),它是一种数据库架构,它在数据库本身的技术上还上升了一层,考虑到数据的可靠性如何保证,以及数据库服务如何不下线。因此,你不能把它跟普通的某个有名字数据库拿来类比,甚至,你可以在某一个具体的区块链实现时,使用其他的数据库来帮助存储和检索数据。数据关系加密化在我们普通的数据库中,无论是关系型还是非关系型,我们的不同记录之间可能存在关系,也可能不存在关系,但在区块链中,一条数据一定和另外一条数据存在联系,即使在现实的业务逻辑上没有联系,但是它总是存在于链上,无法脱离链而存在,总有一条路径从一个数据出发到达另外一个数据,不信往下读。“区块”表达了区块链里面数据关系的最终呈现形式,一条记录,无论它是什么信息,最终它(或它的检索信息)都要被放置在一个区块中。而区块与区块之间,是一个“链表”的数据关系,会编程的人都知道什么是链表,就是后一个数据中存在指向前一个数据的索引键。因此,区块链上的任何两个数据永远可以通过这些索引键最终连在一起,数据无法逃离这个逻辑。但是“区块链”这三个字无法阐述这样的数据结构和普通数据库结构之间的不同,因为上面描述的的这种链表数据结构,用普通的数据库也可以构建出来,只要你想要的话。真正的价值在于,区块链用密码学的原理,现有的加密技术,把这些索引关系进行了层层加密,以至于在保存的数据中,这些索引键并没有那么明显,而是需要通过各种计算才能得到。比如区块在保存一堆交易信息时,采用了merkle树的方式进行保存,父节点是两个子节点的double hash得到的结果,而merkle算法确保了交易信息不能被篡改。我们这里还不需要知道具体的加密都有什么用,我们需要了解的是,区块链里面到处是加密,这是一个显著的特点。数据不可篡改区块链上的数据是不可篡改的,大家都这样说。但其实,数据是可以改的,只是说改了以后就你自己认,而且被修改数据所在区块之后的所有区块都会失效。区块链网络有一个同步逻辑,整个区块链网络总是保持所有节点使用最长的链,那么你修改完之后,一联网同步,修改的东西又会被覆盖。这是不可篡改的一个方面。更有意思的是,区块链通过加密校验,保证了数据存取需要经过严格的验证,而这些验证几乎又是不可伪造的,所以也很难篡改。加密并不代表不可篡改,但不可篡改是通过加密以及经济学原理搭配实现的。这还有点玄学的味道,一个纯技术实现的东西,还要靠理论来维持。但事实就是这样。这就是传说中的挖矿。挖矿过程其实是矿工争取创建一个区块的过程,一旦挖到矿,也就代表这个矿工有资格创建新区块。怎么算挖到矿呢?通过一系列复杂的加密算法,从0开始到∞,找到一个满足难度的hash值,得到这个值,就是挖到矿。这个算法过程被称为“共识机制”,也就是通过什么形式来决定谁拥有记账权,共识机制有很多种,区块链采用哪种共识机制最佳,完全是由区块链的实际目的结合经济学道理来选择。挖完矿没完,拿比特币来说,接下来矿工要把被广播到网络中的交易打包到这个区块里,一笔交易是不是合法的呢?发起这笔交易的人是不是伪造了一笔交易?要确保一笔交易的合法性,必须从已经存在的前面的区块里面去找到这笔交易的来源的真实性,而如何验证交易真实性呢?在前面的区块里,保存着交易来源的merkle root hash,只要找出这个交易所在的区块,再做一次merkle校验,就可以判定交易是否是合法的。得到merkle root hash是通过区块内的所有交易不断加密得到的,因此,只要交易是假的,就得不到这个merkle root hash。加密在这里又帮助实现了数据的可靠性。除了这些,区块链里面的加密比比皆是,这些加密规则和算法,使得整个区块链遵循一种规律,让篡改数据的成本特别高,以至于参与的人对篡改数据都没有兴趣,甚至忌惮。这又是玄学的地方。点对点网络让数据永不下线如果区块链没有p2p网络,仅仅是按照前面的描述,有加密体系,有链式特征,然后运行在某一台(组)服务器上,按照我们现在中心化的模式运行,看上去也挺好玩的。但是发明者想玩的更大些,加密体系让数据不可篡改,但是我直接抛颗原子弹把你机房炸掉,不是不可篡改,是直接玩儿完了。为了防止被原子弹炸掉机房,发明者设计了点对点的网络(客户端和客户端直接通信,不经过某一台特定的服务器)到区块链里面。简单说就是在这个点对点网络里面,所有人的电脑里保管着一模一样的一个数据结构(其实就是一个完整的“区块”“链”),他们相互通过网络连接,进行同步,当矿工创建了新的区块,其他人就会把这个区块同步到自己保管的数据结构中。因此,无论这个网络上哪一个节点被炸,其他节点都还活着,新加入的小伙伴就可以从这些节点里同步数据到自己的电脑。想要让区块链数据消失,那把地球炸了吧。而这种加入点对点网络的设计,就叫“去中心化”,只要网络上还有一个节点活着,区块链的数据就不会消失。更让政客们害怕的是,这些保存的数据,节点上的用户可以随便看,无所谓,完全公开。节点用户既然把数据同步过来了,你就可以随便用,就是你的数据了,想怎么用就怎么用。试想一下,哪天淘宝说我要把自己的数据区块链化……目不忍视……核心技术概念前面仅仅阐述的是区块链之所以是区块链的基础。本节要讲的是,现在已经有区块链在你面前了,我们需要去剖析区块链里面所使用的具体技术点或架构。区块前面已经提到区块了。那么到底什么是区块呢?区块是区块链的主要数据存储结构,一个区块包含区块头和区块体两个部分。而区块头则是区块的重头戏。区块链中的一个区块结构示意图(注:漏掉了version信息)对于一个区块而言,它就是一个特殊的数据结构。它的区块头包含了一些固定信息:版本(客户端版本,每次升级客户端软件,这个信息就会不一样),块高度(其实就是表示这是链中的第几个区块),块哈希(这个区块的hash值,是挖矿得到的),上一个块的块哈希(这个字段是重点中的重点,是形成链表结构的关键),时间戳(区块创建时间),难度和Nonce(这两个字段和挖矿有关,后文讲挖矿的时候详细讲),merkle root(区块体的merkle根hash值,后文会简单介绍merkle树,详细会在其他文章讲)。除了这些字段,如果做一个自己的区块链,还可以添加一些其他信息到区块头中。区块体是保存具体内容的位置,在比特币的区块链中,区块体保存的是一段时间的交易信息。在其他区块链中,这里可不一定保存的是交易信息,可能是其他信息,总之区块体是保存该区块链用来做什么业务的具体业务信息。在部分区块链实现中,一个区块还可以有区块尾,用来保存一些区块创建结束之后的信息,这些信息可能是区块头和区块体已经创建完以后,附加上去的,比如区块的长度、容量等信息。这就是一个区块。而一个区块头中的previousHash字段,保存的是上一个区块的hash值,因此,通过这个区块就知道了上一个区块是哪个,上一个区块又能知道上上个区块,直到可以追溯回整个链条的第一个区块。这就是区块链。区块是如何构成链的的示意图就像上图一样,后面一个区块总是指向前一个区块。一旦一个区块生成,并且后面有区块指向它,那它就不能被修改,因为一旦修改,所有的hash都需要重新计算。但是我们知道,hash算法的特点是,想要得到这个hash必须用原始内容进行一遍hash算法,所以,如果给的内容和原始内容不同,是得不到这个hash的,所以,中间某个区块链被修改而得到的hash,不可能被后面的区块指向,区块链就会断掉。断掉的区块链加入到网络中,要么不被认可,别的节点不会把你当作合法节点,要么你要再同步一遍,从网络中重新复制最长的链到你的本机覆盖原来的链。但是你可能会有两个疑问:1.这个blockHash又不是内容的hash,怎么确保区块体内的信息不被修改呢?要是我不改blockHash,只改内容,那不是可以瞒天过海?2.如果有两个区块同时指向了一个区块,而这两个区块的区块体不一样,这该怎么办?第一个问题,我们需要通过后面的挖矿和merkle tree两部分结合,知道这个原理。第二个问题,实际上,这种情况非常常见,挖矿成功的概率其实是100%,关键在于哪一位矿工先挖到矿,一般当矿工挖到矿之后,会向全网广播,其他没有挖到矿的矿工就会停止。但是由于网络延时等情况,可能在短时间内多个矿工一起挖到矿,他们都创建了新的区块,并且广播到了网络中。这种情况叫“分叉”。当分叉发生的时候,有两种办法。但都是顺其自然,不人工干预。后面挖新块的矿工,会自己决定把哪一个分支最后的块作为自己的前一个块。如果在比较短的块数内,一条链明显长于另外一条链,那么长的链会被保留,短的会被抛弃,挖短链的矿工算是白干了一场。所有的网络节点在同步的时候,都会选择当前最长的链进行同步,后面挖矿的矿工创建新块的时候也是选择最长的链。但是还有一种情况,就是短链的矿工不依不饶,或者短时间内两条链无法分出胜负,甚至最后每条链都有了很多块跟在后面。一帮人的转账总不能有两个账单吧,如果两个账单最后发现还不一样就麻烦了。所以遇到这种情况,矿工们会决定分家。也就是一个区块链变成了两个链,其中一条链把前面的所有链复制出来,成为独立的链,从此这两条链再无瓜葛,虽然前面的区块都是一摸一样的,但是后面井水不犯河水。这种情况叫“硬分叉”,BitCoin Cash就是这样诞生的。新产生的链继承了前面的区块,但是后面的区块完全是挖这条链的矿工决定的。硬分叉的好处是,对于原来的用户而言,突然之间,自己的一份资产变成了两份????至于区块体,真的是根据区块链应用的业务需求来设计。比如比特币,就被设计为交易模型,所有区块体里面的交易记录放在一起,就是一个长长的账单,每一分钱的来龙去脉写的一清二楚,如果当初红十字会用区块链来捐款,那就不会有那么大的风波。但是其他区块链应用不一定是交易模型,比如用于记录医疗信息的区块链,用于记录用户位置的区块链……所以,对于区块链技术本身而言,点到这里即止,再往下说就是比特币特有的技术了。挖矿和共识机制前面已经多次说了挖矿。简单说挖矿过程就是一堆矿工在抢创建一个新区块的权利的过程。在加密货币的世界里,抢到这个权利,就会在这个区块的最前面加上一笔转账给自己的交易,而这个交易的钱是凭空而来的,所以又叫“挖矿奖励”,而且数额还不少,所以矿工才挤破脑袋抢这一个记账权。但是在其他非币区块链应用里,假如没有这个奖励,怎么激励矿工挖矿呢?这也是区块链领域里一个玄而又玄的话题,至今没有答案。那么挖矿挖矿,到底是怎么一个技术上的算法过程呢?在矿机程序里,规定了如何得到一个hash,而这个规定,就被称为共识机制,所有矿工按照这个共识机制去进行某个算法,看谁先得到一个符合条件的结果,而这个结果又可以被轻而易举的验证是符合条件的(验证是否符合共识机制)。不同的区块链,共识机制不同,目前比较知名的是PoW和PoS,以及在这两者基础上衍生出来的其他共识机制。为了能够把挖矿过程讲清楚,我们只拿比特币遵循的PoW来进行演示。SHA256(SHA256(version + prevHash + merkleRoot + time + currentDifficulty + nonce )) < TARGET矿机执行上面公式,只要满足上面这个公式(执行结果为真),就算挖到矿。现在对这个公式进行解释。矿机会做一个double sha256的运算,运算的参数其实全部是块头里面的信息,但是因为这个时候区块还没有生成,所以这些信息是暂时保存的,如果抢到记账权,就把这些信息记录进去version是当前运行矿机的客户端软件版本,每次版本升级,可能对一些参数会有影响,比如区块大小从1M扩容到2M,但是对于挖矿算法而言是不变的prevHash是前一个区块的hash值merkleRoot是当前矿机内存里暂存的交易的merkle算法得到的根hash,merkle会在下文讲time是当前时间戳currentDifficulty是当前难度,这个当前难度是由一个公式算出来的,这个公式是 currentDifficulty = diff_1_target/TARGET 这个公式里面的diff_1_target可以认为是一个常量,在比特币客户端里面是不变的,值为0x1d00ffff。当然,其实它也有可能变,但怎么变都差不多这个值,我们还是把它当作常量。而TARGET我们在下面会讲到。nonce是一个正整数,nonce的值就算矿机要找的值。当矿机开始执行double sha256算法时,nonce为0,如果执行完一次,无法满足上面那个公式,那么nonce就自加1,再执行一遍算法,如果不满足公式,继续加1再执行,就是这样一直加上去,直到找到一个nonce满足上面的公式,就算挖到矿。所以,这个nonce每一次挖矿都可能不一样,它是完全随机出现的,到底是多少完全看运气。但不管怎样,你看每个区块里面但nonce值,就知道矿机做了多少次运算,也就知道挖到矿有多难了。TARGET是用以对比的目标值,它是一个特定值,比特币的发明者希望10分钟产生一个区块,所以最初设计的TARGET就是为了让currentDifficulty能够到一个合适的值,保证10分钟一个块。但是实际情况并不可能保证10分钟一定出一个块,如果算力下降,时间就会加长,这时就应该调整一下难度,使出块时间尽可能恢复在10分钟左右。所以2016个区块(2周)TARGET就会调整一次,而如果真实的情况是产生2016个区块的时间超过2周,那么TARGET就会适当增加,从而使currentDifficulty减小,下面2016个区块的难度就会降低一些。相反,则提高难度。这个调整算法本文就不展开了。所以TARGET是一个2016次不变,但总体而言一直在变的值,它的目标就是让产生一个区块的时间大概在10分钟左右。这就算比特币的挖矿,矿工们每天看着自己的机器,反复不断的执行这个公式,寻找那个nonce,日复一日,年复一年。当矿机找到nonce之后,就夺得了记账权,就可以把内存中的交易信息调出来,打包到区块体中。而merkle root是通过交易记录计算得到的,所以不可能矿工在打包时又去做手脚,一旦他伪造了某一条交易,打包进区块体的交易就不能得到他挖矿时使用的那个merkle root,也就无法得到挖矿时找到的那个hash。当然了,实际上比特币挖矿可能还要麻烦一些,比如说还有nonce溢出、矿池……Merkle Tree前面说了好多次Merkle,它到底是什么?Merkle Tree是一种数据结构,比特币里面就是一棵二叉树,也就是每个父节点有两个子节点那种。我之前写过一篇文章《区块链如何运用merkle tree验证交易真实性》里面详细讲了一些Merkle Tree的原理以及问题。这里主要还是做一个科普,不深入讲。区块头里面的Merkle Root是怎么来的呢?它是通过对区块体内的记录做Merkle算法得到的。以比特币为例,一个区块里面包含n个交易,我们把这些交易两两分组,每两个一组,得到n/2组,如果有单数,那么最后一个交易复制一份凑数。先对每个交易做hash提取,这样就得到来n个hash,然后对每组的hash做double hash运算:parentHash = sha256(sha256( hash1 + hash2 ))也就是把这个组里的两个hash连起来,再计算得到一个新hash,这个新hash就算这两个hash的父节点。得到所有组的父节点之后,按照同样的逻辑,得到父父节点,如此一直下去,最后得到一个根节点,这个根节点就是merkle root。merkle算法大致是这样,但它不仅限于区块链领域,在其他任何验证领域都可能用到,而且也不一定是这里讲的必须两个得到一个的算法,也可以是任意个得到一个的算法,总之merkle是一种对多个记录进行运算得到一个根hash的算法。而可以想象,对参与算法的任何一个交易做小小的改动,都会导致得到的merkle root不一样,所以区块里面只需要保存merkle root就可以了。这就算密码学的力量。区块链适合什么不适合什么?区块链数据的特征主要有两点:1.公开透明,任何节点对数据有完全的权利去查看;2.难以伪造或篡改。因此,区块链非常适合两类场景:1.证据;2.监督。如果区块链上的信息得到法律认可,那么但凡拿出区块链上的证据,侵权方将百口莫辩。而试想,如果将税收完全迁移到区块链,每个公民的每一笔税收,最后都用到哪里,一清二楚,这可能是令某些人害怕的点。但区块链有两大缺点:1.要挖矿,还有分叉风险,也就是说一个数据放到区块链上,要等很久才能成为不可篡改的可信数据。2.分区块,数据被割裂存放,这给查询带来巨大的麻烦,非常影响效率。所以,区块链不适合那种即时性要求高的场景,无论是信息交换的即时性(例如聊天)还是查询的即时性(如搜索引擎)。区块链不是万能的,某些服务明明中心化模式效率更高,成本更低,却偏要为了风口搞区块链化,那只能看韭菜长没长齐。还有一点令人担心的是,由于区块链上信息的公开透明,而且不可删除,是否会对个人隐私造成极大的损害,试想一下,当年给冠希哥修电脑的小哥通过区块链网络炫耀自己发现的照片……那对当事人的伤害……连人死了都不会消散……区块链应用随着风口的来临,区块链应用此起彼伏。但目前比较成熟的,无非三种模式:1.比特币;2.以太坊智能合约;3.比特股。其他的,不多说,读者自己看着办。一个区块链应用,它的架构是怎样的呢?在区块链本身之上,还需要有哪些其他的技术来支撑呢?区块链应用体系架构图(邵奇峰等《区块链技术:架构及进展》)区块链应用,如比特币、以太坊,与区块链本身有比较大的耦合度,也就是说区块链作为数据库无法较为独立的成为应用中的一个模块,和我们现在流行的B/S架构稍有不同,区块链应用中会把区块链拆解之后,于应用其他层进行融合,最终实现应用的整体功能。我们以比特币为例来讲一个区块链应用,比单纯一个区块链本身多了哪些部分。比特币是一个基于区块链的账单系统,它除了区块链,还要包含:1.交易模型;2.身份认证体系(类似PKI);3.智能合约。交易模型交易模型就是区块体内保存的交易记录。之所以比特币里面的每一笔钱的来龙去脉都一清二楚,就是依赖于交易模型。我们现实中银行里面的一个账号,只会告诉你一个账号现在有多少钱,曾经花了多少钱,收入多少钱,还欠多少钱。但是不会告诉你“某一笔你花掉的钱,来自你某一笔收入”。但比特币里面必须告诉你这样的逻辑,一条交易包含“输入”和“输出”两个部分,比如你要转10BTC,那么你的账号必须有一个或多个“输入”加起来总和等于或超过10BTC,而输出就是指你要把这10BTC转给谁。但是有一种情况,当所有“输入”加起来为10.5BTC时怎么办,就像你有100块毛爷爷,去买70块的东西一样,需要“找零”。所以“输出”有的时候会有一个是转给自己的,就是“找零”。比特币交易输入与输出示意图而实际上,输出在另外一个交易中,又是这个新交易的输入。在区块体里面,这些交易记录,以及它们的输入输出都被如实记录。除此之外,还要进行merkle计算,将merkle root存到区块头中。身份认证体系既然是交易,那么必然涉及到交易双方的身份。比特币交易的两端是两个账号,至于到底是谁它不管,但它通过加密算法,保证这一笔交易是哪一个账号发起的,发起交易的人要对交易信息进行签名。你可能听过非对称加密、公钥和私钥。比特币账号最关键的就是这个私钥,一旦私钥丢失,你就无法证明自己是这个账号的主人,也就无法从账号中进行转账要做的签名动作,你就不能再花这个账号里面的币,也就丢失了币。那么签名是怎样的一个过程?怎么证明这个交易是我发出的?怎么证明这钱是转给我的?密钥、地址与钱包密钥 通常指的是保护比特币资产的对应于所有权用户的私钥,个别时候也会模糊的统称私钥和公钥为密钥,这里我们以狭义的私钥解释为准。地址 比特币的收款地址,大部分情况下是指对公钥的封装(个别时候除了公钥还有脚本)。钱包 一种比特币客户端软件,是私钥的容器,通常通过有序文件或者简单的数据库实现。比特币钱包包含私钥和公钥数据,尽管公钥数据理论是是不需要存储的。一般来说,用户的公钥和比特币地址可以划等号,但实际上不是。比特币地址是一串比公钥短很多的字符串,主要是为了方便输入。而公钥则用于各种非对称加密。比特币公钥到比特币地址公钥和地址都是公开在比特币网络中的,只有私钥是用户自己保存,不能给任何人。当一个交易发起时,交易发起方用“自己的私钥”和“接收方公钥”对交易进行签名,那么网络中的其他人就可以用发起人的公钥去验证这个交易是不是他发起的,对于接收方而言,要提供自己的私钥进行解密运算,来证明这个交易确实是发送给自己的。而比特币客户端(钱包)就是干这个加密解密和签名的事。智能合约比特币本身已经有智能合约的雏形,只是它所采用的编程语言脚本能力比较弱,能实现的合约逻辑不复杂。以太坊则是在这个基础上扩展链智能合约部分,使智能合约的编程能力大大增强。在上文提到的输入和输出,输出其实就被作为另外一个新交易的输入。比特币的输出不单单是告诉系统要转给哪个地址多少钱,输出实际上是一段比特币脚本。这段脚本也经过复杂的非对称加密,要运行这段,想要得到一个输出里面的钱,把这笔钱作为自己交易的输入,必须用自己的私钥先解密脚本,然后运行脚本,脚本运行完,这笔钱就可以作为自己交易的输入了。结合前面的知识,只有拥有对应的私钥才能解密,所以,只有输出记录对应的比特币地址对应的那个用户才能解密脚本,得到这些钱。在这个过程里面,“脚本”是一个关键,除了上面这种最简单的转账逻辑,还可以通过一些条件判断来实现稍微复杂一些的编程,比如只有当满足某些条件的时候,解密后的脚本才能运行。于是,基于这种设计,比特币的脚本系统可以用来实现多重签名、保证合同等功能,也就是智能合约的雏形。结语对于区块链的研究,我也是刚刚开始,必定有不少地方没有理解透,有些地方也有误解。但对于想要了解这个领域的朋友,希望你们先了解区块链背后的技术原理(不必对技术细节掌握透彻),读一些比较成熟的可信的材料(我一不小心发现前人已经在《计算机学报》上发表类似综述的文章了,读者可以阅读《区块链技术:架构及进展》),而不是道听途说就信以为真。一旦你掌握了这些技术原理,就会发现,其实它的限制挺多,有美好的地方,也有没必要的地方,那些莫名奇妙的项目就坑不到你了。原文载于我的博客:http://www.tangshuang.net/4133.html 如果后期又发现一些错误,会在我的博客去更新,所以请关注我的博客。
2023年03月24日
6 阅读
0 评论
0 点赞
2023-03-24
2个未来技术概念:Web3.0 和元宇宙
最近互联网世界的两个流行语 Web 3.0 和 元宇宙。看到这些新平台提供的发展潜力,许多公司正在探索 Web 3.0 和元宇宙技术所提供的可能性。虽然这两种技术趋势都在描述数字现实和网络的未来,但它们在做什么和如何去做方面是不同的。但是,这两个概念及其功能彼此不同。下面就来了解这两个流行语,以更好地了解互联网的未来发展方向。定义简而言之,元宇宙揭示了将在互联网上拥有的不断扩展的日常体验(例如游戏、社交、学习和工作),而 Web 3.0 试图通过去中心化技术解决互联网当前的问题(例如所有权、隐私和控制)。什么是元宇宙?元宇宙(Metaverse)是来自 1992 年科幻小说《雪崩》出版物存在的一个术语。在小说中,作者将元宇宙(Metaverse)描述为基于虚拟现实的互联网继任者。这本书设想了一个未来,人们可以在虚拟世界中用自己的化身并与他人互动。这就是大多数人理解的元宇宙(Metaverse):使用增强现实 (AR) 和虚拟现实 (VR) 技术构建的 3D 沉浸式世界。在那里,用户可以通过笔记本电脑、台式机和 VR 耳机等设备作为 3D 化身相互交流和互动。元宇宙可以是中心化的、去中心化的或两者兼而有之。什么是 Web 3.0?与此同时,号称网络的第三波浪潮,即 Web 3.0,是以太坊的联合创始人 Gavin Wood 在 2014 年首次提出的一个术语。它的定义要广泛得多,也更难确定。尽管如此,它通常指的是使用分散的基于区块链的机制将用户的数据存储在区块链上并赋予它们控制权。Web 3.0 是从 Web 2.0(万维网开发的第二次浪潮)在后端和基础设施变化方面向前迈出的重要一步。Web 2.0 是关于将网络带给大众,而 Web 3.0 是关于权力下放和从中央当局手中夺回控制权。Web 2.0 和 Web 3.0 最显着的区别在于后者基于区块链技术。区块链是一个分布式数据库,允许安全、透明和防篡改的交易。它还使其成为开发在公共区块链或点对点网络上运行的去中心化应用程序 (dApp) 的理想选择。涉及的技术Web 3.0 由区块链技术支持的去中心化网络组成,它还采用了尖端技术,如人工智能 (AI)、机器学习 (ML) 和语义网(一种新形式的网络内容,关注意义而非数据结构),提供更加民主化、高效和个性化的用户体验;它优先考虑集体所有权、个性化和内容共享。另一方面,元宇宙(Metaverse)专为虚拟世界而设计, 元宇宙(Metaverse) 中的体验构建块包括 AR、VR 和 MR(混合现实)。AR将虚拟物品融入到我们身边的物理环境中,而VR技术让你通过3D计算机建模进入3D虚拟世界。增强现实眼镜和虚拟现实耳机是带我们进入虚拟世界的设备。可能的场景去中心化自治组织 (DAO)、去中心化金融 (DeFi) 和不可替代代币 (NFT) 是 Web3.0 中出现的一些产物。例如,用户现在可以通过购买存在于区块链网络上的代币来拥有互联网的一部分:可替代的(例如比特币和以太币等加密货币)和不可替代的(例如 NFT 艺术收藏品)。至于元宇宙(Metaverse),可以看到不同的领域,如游戏、社交网络/娱乐和房地产,现在都在进入虚拟现实技术,为用户提供更逼真和身临其境的体验。例如,Horizon Worlds 是 Facebook(或 Meta)发布的社交 VR 平台,人们可以在其中与他人互动和玩游戏。还可以使用虚拟办公室应用程序(例如 Nth Floor)安排与元宇宙中的同事的工作会议。它的另一个主要机会是新的营销机会,许多品牌,如耐克、H&M 和沃尔玛,都在创建自己的虚拟世界,用户可以在其中购买产品并与品牌建立联系。此外,元宇宙中还有区块链场景,例如虚拟世界 Decentraland 和视频游戏平台 Sandbox。这些应用程序是完全去中心化的,这意味着它们归用户所有或通过 DAO 控制。总结总而言之,虽然这两个概念在本质上并不相同,但它们肯定在许多方面相互关联,并彻底改变了未来互联网和世界。
2023年03月24日
9 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-10 敲定工作
(21)面试朗云朗云是我特别喜欢的一家互联网公司,其福利待遇在业内有口皆碑。在离职率居高不下的互联网领域,朗云就像是一朵盛开的奇葩,其员工的忠诚度远高于业界平均水平。朗云成立于上世纪90年代末期,旗下有多款体验特别好的社交软件。经过十多年发展,朗云在网络世界里构建起了一个庞大的社交帝国,常年霸占着流量入口。学生时代我就非常向往这家公司,在我认为自己有足够的知识储备去应聘一家大企业的时候,我第一时间就想到了它。我有情,好在朗云也有意。简历投递过去,约莫一周后,我就收到了朗云一个部门的面试邀请。那是初夏的一个早晨,既无春天的泠冽朔风,也无盛夏的似火骄阳,是帝都最为舒适的时节。我从住所启程,前往西二旗参加朗云的技术面试。脚刚踏出公寓门口,整个人瞬间被温暖的晨曦包围。天空作美,心情也舒畅开来。公寓门前两侧的几株桃树此时已经挂满了粉白桃花,于清风中摇摆,无比烂漫。鼎沸的桃花映入眼帘,我不禁驻足观望起来。兴之所至,我从兜里掏出手机,准备定格眼前的美好。望着呈现在屏幕之上的美景,我忽地萌生出些许诗意,心中默默吟道:他年我若为青帝,报与菊花一处开。话毕,突有一股冷风从裤管里灌进,直冲云霄,我打了个哆嗦,不禁菊花一紧。我扫了眼手机时钟,已是八点一刻,顿时诗意全无,撒开腿朝地铁站的方向跑去。正值上班早高峰,车站的月台上满是黑压压的人头。挤上地铁后,我一头扎进车厢角落里,点亮手机屏幕,翻起技术面经来。温故知新,希冀待会能人品大爆发,一举拿下朗云。地铁重新发动,开足马力,大口大口地吞噬着我跟西二旗之间的距离。约莫二十分钟后,地铁平稳地停靠在了西二旗站。车门打开,喧嚣迎面扑来。13号线的码友与昌平线的码友于此处交汇。无论大家从何方而来,到何处而去,基本都是行色匆匆。困意笼罩西二旗。等我被人群裹挟出地铁站后,这才觉察笼罩西二旗的不止是困意,还有如针细雨。由于出门前还是晴空万里,丝毫没有下雨的预兆,所以我并没有带伞。一些没有带雨伞的人聚集在出站口,踌躇不前。我心说蒙蒙细雨何足挂齿,当即冲出人群,撒丫子往车站外跑去。我一路躲闪,来到了站前广场外的公交车站。费了九牛二虎之力,挤上了一辆开往软件园的摆渡车。等我抵达朗云大厦时,身上已经湿了七八。凉风袭来,我不禁瑟瑟发抖起来。我拢了拢被雨水冲刷变了形的头发,大步流星地进了大厦一楼大厅。一位帅气的保安小哥立马迎了上来。我表明来意,小哥将我安置在了访客等候区。访客区零星坐了几位同龄人,应该也是应聘者。他们一个个信心满满的样子,让我忽地紧张了起来。我赶紧掏出手机,翻看面经,临时抱抱佛脚。几分钟后,听见不远处有人呼唤:“姚博启同学,在吗?”我抬起头,赶忙举手示意。一位身穿黑色小西服的漂亮姐姐向我走来。听声音,漂亮姐姐应该就是几天前在电话里约我来面试的那位HR。HR姐姐把我带进了朗云的办公区。我被安置在了大厦五层的一间会议室里。因为面试官还在开晨会,我不得不坐在面试间里暂且等候。HR姐姐给我端了杯热水后便走开了。会议室里只剩我一人,趁此间隙,我观察起了周遭环境。视野正前方的玻璃幕墙上残留着几行代码片段。我猜极有可能是前一个应聘者留下的解题思路,心说没准待会能派上用场。我走上前,观摩了一番。是一道比较常见的排序算法题。我在脑子里大致回忆了一下解题思路,不算很难。继续巡视,另一面的幕墙上挂着一条让人倍感温暖的横幅,亲爱的应聘者,我在面试你的时候,你也在面试我。待我熟悉了周遭环境后,紧张情绪才有所缓解。我重新坐回座位,闭上眼,开始在脑袋里梳理最近几场面试所积累的知识。几分钟后,一阵短暂的敲门声将我从冥思中拉了回来。我以为面试官来了,便正襟危坐起来。扭过头去,才发现并非面试官,而是刚才接待我的那位HR姐姐。姐姐面带笑容,把一件未拆封的文化衫放在了我面前,细声细语道:“同学,看你衣服都淋湿了,别着凉了,快去洗手间把这个换上吧。”说实话,那一瞬间我真想哭,从来没有一个这么年轻漂亮的姑娘对我表示过如此的关心。无论她是以个人名义还是公司名义,都没有。我那脑袋忽然不争气地闪现赤身裸体、以身相许的念头。不过,理智很快战胜了淫意,我是连声感谢。(22) 敲定工作那天也不知是被谁附体,整个面试过程,我超常发挥,激情四射,对答如流。面试官出的那几道算法题,先前我从未见过,却都解了出来。也许是那件印有朗云logo的文化衫给我带来了好运,或许是其他。总之,我一路过关斩将,一天之内连续面了三面。面试官送我下楼的时候,表示对我很满意,甚至都询问了我最快能入职的时间。应该是胜券在握。回到公寓,我跟老潘描述我面试时的神勇状态:“可谓是灵光乍现,诸神附体,仿佛瞬间被打通了任督二脉。”我讲得激情澎湃,老潘却投来一脸不屑:“你这哪里是什么灵光乍现?是你契而不舍地练习,最终做到了举一反三,触类旁通。再加上恰巧面试官跟你气场合拍,你俩一起完成了这个宇宙大和谐的画面。”细细咂摸老潘的话,倒还真有几分道理。在面试朗云之前,我已经被若干家公司打击过,可谓是遍体鳞伤。知耻后方能后勇,求职的这段时间里,我始终紧绷着一根弦。无论是吃饭时,如厕中,还是地铁上,小路旁,脑子时刻被面试题所填满。一遍又一遍地复盘过去那些失败的面试,积极寻找着每次面试中的不足和今后应对的策略。没有公司会拒绝一个具有实力并且真诚的应聘者。几天后,我拿到了朗云的口头offer。这是我跳槽后的第一个offer,还是一个大offer。我奖励了自己一顿烧烤。我这人比较容易满足,在拿到了朗云这样互联网领域一流公司的offer后,就停下了面试的脚步。虽然朗云还没有跟我谈薪资,但无论薪资多少,我都已决定投入它的怀抱。老潘却劝我再找找看,多拿几家公司offer,也好有个对比,等到跟HR谈薪资的时候也有底气。才不到一年的功夫,老潘就已经混成了职场老油条,处处指点江山。找工作这段时间,每天晚上我都会跟老潘举行卧谈会。我向他取经,他会给我讲一些在互联网企业日常工作的注意事项。比如,如何跟上级汇报才能显得自己是超额完成工作;什么时候该表现自己,什么时候该收起锋芒;面对公司大佬的矛盾,如何站队,站错队会有什么样的后果等等。我受益颇丰。饮水思源,我请老潘吃了许多次外卖,口头上也对他表达了深深的感谢。不过这厮却得寸进尺,问我借给他那五千块钱能不能当做学费支付给他。友谊是钱能衡量的吗?友谊是无价的。对于老潘这种无利不起早的俗人,我必须予以严惩。我拿出计算器,按照利率细细地给老潘核算了下我那五千块钱所产生的利息,威胁他必须连本带利一起归还。月末,老潘在领了工资,第二天就把欠的钱还给我了。翻看他的工资条,我才知晓这厮的工资已经涨到了每月10k。如果算上季度奖,年终奖,一年下来差不多是税前15w。2014年,对于一个毕业才一年的本科生来说,能够拿到税前15w已经是相当不错了。作为过来人,老潘建议我多找几家公司做备胎也有道理。万一朗云那边再有什么变化,我也有后路。此后,我继续奔走在北京那几个互联网公司聚集区。从中关村到西二旗,从五道口到望京西,处处留下了我的脚印。自从拿到朗云的offer后,好运便接踵而至。我陆续又拿了其他家还不错的offer。在一无所获时,我痛苦心急,茶饭不思。但等我手上积攒了太多offer时,又变成了焦虑不安,茶饭不香。朗云公司福利好,新丰公司技术强,搜噶公司位置棒,爱美丽公司加班少,千寻公司给钱多......我顿时陷入了选择恐惧之中,遂求助许多学长,众位同窗。他们给出的建议几乎包含了我所有的offer,各有各的道理,一圈下来约等于白问。老潘倒是直截了当:“你那几个公司都还不错,就简单粗暴一点,选择给钱最多的那个。”不过这次我并没有听从老潘的建议,反而选择了钱最少却给我温暖最多的朗云。朗云给我开的月薪跟老潘差不多,一万出头。这待遇已经达到了我的预期,我没有老潘那么大的野心。他说如果他跳槽,至少要拿到月薪15k,才会考虑。朗云HR很快就给我发了正式offer,并打来电话跟我商量好了入职时间。翻阅电子邮箱里入职邀请函,我几次都乐出声来。终于要进入梦寐以求的互联网领域,开启我的互联网打拼生涯了。不过,我也有所担忧。不知道什么时候才能跟我爸挑明,我已经从国企离职这件事。他至今还以为我在银行里上班劳作。媒人在给我找寻相亲对象时,对外宣传最多的就是知名国企的名号。没有万贯家财,也只能给别人一个美好未来的期许。至于是不是空头支票抑或空中楼阁,媒婆是不打保票的。点击进入下一章点击从第一章开始阅读
2023年03月24日
9 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-16 农村青年
(34) 农村青年周末,我带着四叔跟老姚转了转北京城那几个写进教科书里的著名景点。旅游对于许多家庭来说是生活必需品,一年到头,必须出门三五趟。近则郊区周边,远则海外港湾。旅行可以放松心情,促进家庭和睦。不过,旅游对于我家来说,十年前是不敢想的奢侈品,现在也不过是偶尔用来解馋的消费品。财富积累讲究开源节流,老姚没有开源的门路,攒钱只能靠节流。所以当听到长城缆车索道需要每人一百元的时候,他果断拒绝,强忍着腰疼,腿疼,扶着栏杆慢慢地走下山。在景区,一根黄瓜可以卖到十元钱,一份盖饭便宜的也要三十元。好在东西都明码标价,童叟无欺。也因此,我妄想欺骗老姚,在景区进餐的想法也幻灭。我们不得不硬生生地挺着辘辘的饥肠赶回公寓。我在公寓附近找了家便宜的刀削面馆,三十多元钱解决了三个人的肚子。老姚吃得很是香甜,嘴巴不住地夸赞自己的省钱之道,还教育我粒粒皆辛苦。填饱肚子狗,我拖着灌了铅一样的双腿返回住所。找来几张旧报纸铺在房间的石灰地上,在上面又铺了床被子。我睡在地上,老姚睡我的床,四叔睡老潘的床。十多平米的小屋里硬生生地塞了三个人。当然,如果严格遵守公寓门口张贴的管理告示,老姚跟四叔是不被允许在我房间里留宿。不过,没有什么事儿是送一包烟不能解决的,如果有,那就送两包。公寓的保安小哥在收了我两包烟、两瓶啤酒后,原先不可一世的态度发生了一百八十度转变。甚至主动提出为我们放哨,允诺如果房东来访,他会第一时间告知我。四叔跟老姚的突然到访让我身体很累,不过心情却甚是愉悦。听着乡音,聊着家长里短,一切都很亲切。入睡前,我与四叔闲聊,他讲了几件老家最近发生的事儿,我浑身不住地冒冷汗。广袤的农村有着广袤的土地,广袤的土地上住着广大的人群。原来农民都是靠天吃饭,春种秋收,一年到头都扎在土地上,没有多少空闲时间。现如今,农业器械如播种机,收割机越来越先进,种地早已不再是高强度的工作,农村许多劳动力就闲了下来。科技进步最先解放与受益的并不是那些五六十岁的中老年人,而是那批二十岁左右的农村待业青年。一些人在接受完九年义务教育后,不再继续求学。如果是十多年前,这些人会成为农村的青壮年劳动力。他们或在家务农种地,或学一门手艺,如瓦工,木匠,然后随着包工队外出打工,成为各大城市里农民工中的一份子。不过,当下就业形势发生了改变。劳动密集型的产业逐渐升级改造,低端劳动力过剩。与此同时,成长于安逸时代的年轻人也不如父辈那般肯吃苦受累,就算有一份在工地搬砖夯土的工作,大部分人也都会拒绝。好在那些工业,制造业或者服务业比较发达的省份里,待业青年可以去工厂做流水线上的工人,或者去饭店歌厅当服务员,赚钱养家倒也不成问题。不过在一些仍然以农业为主的省份,可供待业青年从事的工作并不多,于是这群人就走上了另外的道路。就在一个月前,我们村东头一条街上,十多户人家被一伙摩托车飞贼洗劫一番。据传损失最大的是村支书姚钱盛家,他家丢了五万多现金。不过,姚钱盛对外宣称只是丢了几件不值钱的金银首饰。这事儿过后,姚钱盛雇人把自家院墙又加盖了半米,同时墙上还安装了玻璃渣,防护电网。我翻看四叔手机上姚钱盛家院墙的照片,看起来特像电视剧里反动地主家中的堡垒据点,就差几挺机枪和几个打手。丢钱还算小事儿,有些人还丧了命。隔壁村有一个开小卖部的人家,盗贼在偷窃时,被主人堵在了家里。经过激烈地打斗,主家男人被盗贼捅了十几刀,一命呜呼,最后人财两失。作案的人基本都是一群二十岁左右的无业游民,他们聚集在一起,打架斗殴,抢劫偷盗,甚至是杀人越货。农村不像城市那样有着严密的监控网络和热心的人民群众,因为缺乏有效的人证物证,许多案子都过了好多年还没有破。贫瘠的农村,贫瘠的物质与精神。路不拾遗,夜不闭户的美好愿景,恐怕只存在于乌托邦式的文学作品中。现实情况下,鸡毛蒜皮都得斤斤计较,蝇营狗苟很是常见。贫穷只会让人瞧不起,甚至连孩子都无法娶妻。富有就怕旁人眼犯红,要时刻提防着坏人的惦念。近几年,村里一些长年在外打拼,攒下些许积蓄的人,很多都举家搬到县上,市里居住。村中荒废坍塌,杂草丛生的院落越来越多。年轻人远离家乡,只留下七八十岁的老人守着故土。像我这样从乡下走出来的孩子,一路披荆斩棘,埋头苦读数载,考入城市大学。毕业后,混入城市中,讨得一份安身立命的工作,每日勤勤恳恳换得一份温饱。诸如空气不好,地铁拥挤,老板谩骂......这些不良待遇都可以不走心,付之一笑。令人心扉痛彻的是“从小到大,梦想被不断地修正。它变得越来越小,也越来越现实。”如今,它已经变成了在帝都能有属于自己的小房子。即便是这样居有定所的基本生活需求,在经过多年的劳心费力后,到头来发现还是求之不得。随着年岁增长,志气被消磨殆尽,又不得不考虑再次转战他乡。回望远方是那归不了的故乡,俯瞰脚下是这难捱的他乡。在追名逐利的社会风气影响下,看到别人盆满钵满,宝马香车,广厦万间,又免不了心急。可是,转而一望,方圆五公里都瞧不见一个真实的励志故事。没有家底,没有资源,没有贵人,在这寒门难出贵子的大形势下,残酷的现实让我们开始得过且过,随波逐流。游戏度日,混一天算一天慢慢地成为了生活常态。可意志消沉,怨天尤人从来都解决不了问题,反而会使原本还算平静的心变得戾气满满。唯有背着行囊,举步前行,希冀未来能有一番别样的光景。至少,目前大多数人还相信,知识能改变命运,勤劳终能致富。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
7 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-18 养儿防老
(37) 求助电话日子熬到了周末。没有想去玩的地方,亦没有陪玩的人,但我还是期盼周末,从每周一就开始期盼。周六晚上,我光着膀子坐在电脑前玩仙剑。游戏正酣时,突然从屋外传来了一阵巨大的声响。随后一声响彻云霄的CNM在公寓走廊里回荡。大于17米长的走廊满足产生回声的条件。于是,余音绕梁,久久不能散去。骂人者中气十足,声如洪钟。闻声识人,应该是住我隔壁的健身大哥---柳力。我推开门,果不其然。当下,健身大哥正跟门卫小哥扭打在一起。二人面红耳赤,手脚并用,互有损伤。狠话与脏话在走廊里交替穿梭。几个女租户推开门,瞧见状况后,立马又关上门,生怕惹火烧身;几个男租户有开着门看热闹的,也有上前欲劝架的;当然,还有我这样正犹豫是关门,是看热闹,还是前去劝架的。虽然健身大哥有着一身的腱子肉,但目前来看,他似乎并没有占据上风。因为门卫小哥手上有一根警棍,一寸长一寸强。泰山压顶,黑虎掏心,猴子偷桃,公鸡啄米,武二郎打虎,司马光砸缸……二人招数变化无穷。眼下这个情形,我也不知道该帮谁,因为这两个人我都不太喜欢。住我隔壁的健身大哥总喜欢把垃圾堆在门外,搞得走廊里臭气熏天。而门卫小哥又是个势利眼,经常借着职务之便,吃拿卡要,占尽小便宜。二人从走廊一头打到另一头,均已经气喘吁吁。打得有些累了,门卫小哥便扶着墙休整。健身大哥趁其不备,一把夺过门卫小哥手上的警棍。目前,双方应该可以开始分胜负了。失去了武器的门卫小哥,免不了被一顿煎炒烹炸。不过,门卫小哥倒是挺识时务,他没有选择硬撑,而是撒腿就跑。健身大哥见状后,愣了片刻,而后冷笑了几声,飞奔追了出去。楼道里一片狼藉,散落了一地的垃圾发出阵阵酸臭味。看客们大都捂住口鼻,回身扣上房门,热闹暂时告一段落。我已无心游戏,选择躺在床上,静静聆听着屋外的声响。由于下午经历了一个长长的午睡,此时我巨有精神,迟迟唤不来困意。于是,我一边摆弄手机,一边等待健身大哥与门卫小哥的王者归来。王者没有等来,最终我见到了周公。凌晨两点多的时候,许久不联络的老潘突然给我打来了电话。自从我俩分道扬镳后,老潘这厮就深陷爱情的泥淖,不可自拔。久不碰面,我跟老潘的交流日益减少,最后趋近于零。当然,老潘也不是那种有了媳妇忘了爹的人。他偶尔也会在我朋友圈的状态下回复形如“大姚有空出来聚聚呀、大姚周末去后海喝酒呀、大姚撸串否......”起初我也是贱,竟以为老潘是真情实意,便借坡下驴,答复他:“那明天可好、周日怎样?”然后,老潘就会陷入长时间的沉默。隔了许久,他终于找寻到了拒绝我的说辞。什么家里养的猫要去做绝育、女朋友闺蜜来北京需要陪逛、公司部门要团建聚餐等等。三番五次鼻子碰灰,我总算是看清了老潘那虚情假意的嘴脸,也就不再自讨没趣。半夜三更,老潘找我,指定没什么好事儿。我睡眼朦胧,打开手机的扬声器,漫不经心道:“潘总,都你妈几点了?”老潘沉默片刻,而后语气凝重道:“手里有钱吗?”想到上周他刚在朋友圈晒了跟李亚男去日本京都游玩的照片,我猜测这厮一定是泡妞把钱给造没了。目前应该是到了山穷水尽,家里揭不开锅的境地。我挖苦道:“李亚男把你吃空了?你挣得可不比我少啊。”老潘叹了一口气:“哎,我爸住院了。”处于迷糊状态的我瞬间清醒了过来,我从床上坐起来,打开壁灯。我问老潘:“在哪儿?北京吗?”老潘的声音里夹杂着些许哭腔:“嗯,阜外医院。”我一边穿衣服,一边回话:“好,我马上就过去。”我从抽屉里找出信用卡,揣进兜里。入职朗云后,为了给王旭涨信用卡积分,在他的推荐下,我办了张招商银行信用卡。鉴于朗云员工的信誉比较好,信用卡的额度目前已经累积到了五万。(38) 养儿防老夜已经深了,楼道里一片寂静。我小心翼翼地锁上房门,蹑手蹑脚地走出公寓大门。健身大哥与保安小哥正坐在公寓门口的台阶上,一边喝酒一边聊天。二人手里还都夹着烟卷,吞云吐雾,互诉衷肠。保安小哥不停地揉搓着胳膊,胳膊周围泛着红色,想必是在先前的决斗中受了伤。健身大哥黑T恤衫的领子豁了个大口子,应该是保安小哥的杰作。讲道理,二人此时应该是剑拔弩张,互相捅刀,可呈现在我眼前的却是反常的和谐画面。缘何刚才还互骂祖宗,扬言弄死对方的两个人,突然间就握手言欢了呢?我满是狐疑。不过,当下我并没有太多功夫去深究,老潘那里急需我。我叫了辆出租车,很快就来到了阜外医院,在脑卒中重症监护室外见到了老潘。老潘比上次见面胖了许多,还留起了长发和山羊胡,一副浪荡公子哥的造型,跟富二代郝公子是一个套路。想必是受李亚男影响,没有人家富二代的命,却拼命扮演富二代,难不难受?别不别扭?老潘快步迎上来,我掏出信用卡递给了他:“卡上有五万的额度,你先拿去用,应应急。”老潘接过信用卡,双手合十:“真不想用你的钱,我这实在是没办法了。上个月为了给李亚男冲业绩,存款都买了她公司的理财产品。我爸这刚住院没多久,信用卡的额度就刷光了。”几个月前,李亚男跳槽去了一家新成立的P2P公司做理财顾问。为了帮李亚男拓展客户,老潘几次打电话给我,向我推荐李亚男公司的理财产品。对于新兴事物,我一向持谨慎态度,不会轻易尝试,便拒绝了他的好意,为此老潘还有点不太高兴。去年潘弟结婚买房,老潘补贴家里不少。年初跟李亚男结识后,二人一直过着奢靡生活,花销也是不菲。据我所知,老潘并没攒下多少积蓄。即便如此,为了给李亚男冲业绩,他还是把手头仅有的三万块钱投了进去。不知精明的老潘是被爱情冲昏了头脑,还是被理财产品的高收益迷住了心窍。我扫视周遭,并未见到李亚男,便随口问了一句:“李亚男没来呀?”刚才还一脸和气的老潘突然面露狰狞,攥紧拳头,咬牙切齿道:“我现在真想抽她。”老潘一向是宠妻狂魔,今天一反常态。我大吃一惊:“怎么?吵架了?”老潘咽了咽唾沫:“下午我爸被急救车送来北京,我给她打去电话,让她买点洗簌用品带过来。她说她正在跟一个很重要的大客户谈业务,实在走不开。这我他妈的都忍了。后来她忙完了那狗屁大客户,给我打来电话,第一句竟然是问我晚上吃什么?感情我爸这都住进重症监护室了,她竟一点儿都没放在心上。”说着说着,老潘啪啪甩了自己两嘴巴子,着实把我吓了一跳。想必也是因为潘父目前情况危急,他内心极度慌张,才会如此激动。我拉住老潘的手,说道:“我艹,你疯了。”老潘眼角泛着泪光,带着些许哭腔道:“我他妈真是眼瞎了,怎么找了这么个主儿。明天就分,不,他妈的现在就分。”老潘掏出手机给李亚男打了过去。对方却一直是关机状态,无法接通。“哥,咋啦?”身后传来一个男人的声音。我回过头去,一个染着黄毛的小伙从走廊的长椅上坐了起来。老潘白了黄毛一眼:“没咋地,咱爸都这样了,你还能睡着,我也真是佩服你。”黄毛走上前来,老潘指着他对我说:“这是我弟,潘伟虎。”我心说潘父给孩子起名也真是随意,要是老潘再有个三弟,大概率会叫潘伟豹。黄毛伸出手:“哥,麻烦您了。”我伸手过去,跟黄毛象征性地握了握。黄毛见老潘不愿搭理他,便很知趣道:“哥,你们聊,我下去抽根烟。”黄毛从兜里掏出烟盒,一边点烟一边往楼下走去。重症监护室里的护士时不时地从病房里走出来,询问老潘这个药用不用?那个药打不打?进口的还是国产的?老潘始终就是一句话:“紧着好的、能救命的用。”医生的每一次询问都是一笔不小的费用,我的信用卡很快就派上了用场。(39) 失了风度忙活了大半夜,等医生告知潘父已脱离生命危险时,晨雾升起,天已经大亮。期间,老潘多次劝我回去休息。晚上光顾着看保安小哥与健身大哥的热闹,本来睡得就晚。再加上三更半夜,老潘又把我从睡梦中叫醒,当下我已经困得睁不开眼。不过,瞧见潘弟那副不靠谱的样儿,我又觉得老潘一个人在医院肯定忙不过来,也就没走。在他乡,朋友即是兄弟,更何况我跟老潘有着曾同室而眠的交情。潘父从重症监护室转移到了普通病房,老潘那颗悬着的心终于放了下来,他执意让我走。我转身欲出病房,这时李亚男拎着一袋子水果迎面走了过来。咣当咣当,银色高跟鞋敲打着地板。我跟李亚男打了个照面,互相点了点头。彼此并不太熟,也就没继续寒暄。我望了眼老潘,只见他脸色突变,忽地凶神恶煞起来。一股寒气从身后袭来,周遭气氛有些不对劲,我便收住了脚步。老潘迎上前,一把抢过李亚男手上的水果袋,使劲往地上一摔。苹果、橙子在狭小的病房里,四下滚落。老潘努力压着怒火:“让你买的脸盆毛巾,牙缸牙刷呢?你拎一袋子水果来给谁吃?”老潘先是小声嘀咕而后声音越来越大,最后都快要蹦起来了。虽然老潘平日脾气有些暴躁,但我从未见过他对女人如此失态。我赶忙上前劝阻,免得扩大事态。可老潘却不依不饶,他硬拉着李亚男的胳膊往病床那里凑,边走边喊:“你过来,看看床上躺着的那个,嘴巴插着管子,你觉得他能吃吗?”潘父隔壁病床上住了一位半身不遂的老汉。想必是被吵闹声打扰到了休息,老汉不住地哼唧。老汉那虚弱状态就算心里有火也发不出来,不过他旁边的陪护大婶可一看就不是善茬。大婶紧盯着老潘,操着一口浓重的京腔:“喂喂,医院不是打架的地儿,要闹出去闹,别影响我们家老头子,他经不住。”老潘瞪着北京大妈,宛若一头看见了红布的斗牛。瞧他那架势想要把火撒到北京大妈身上。我赶忙上前拦住了他,把他推出了病房外。李亚男气得脸色苍白,蹲下身子,一一捡起散落四处的水果。随后跑出病房,走到楼道尽头,把水果一股脑地扔进了垃圾桶里。老潘站在楼道里,靠墙弓着腰,气喘吁吁。我的视线在老潘跟李亚男身上来回交换。李亚男扔完垃圾,从楼道尽头快步向老潘走去,手还攥着拳头。李亚男大有河东狮吼的架势,我挡住了李亚男,规劝她别跟老潘一般见识,先回家,回头我让老潘一定负荆请罪。李亚男长舒一口气,最终听从了我的建议,转身欲走。忽地,老潘快跑两步,挡住了李亚男的去路,而后一把拉住她,双手用力将她摁在了墙上。老潘恶狠狠道:“把我在你们公司存的理财钱赶紧给我取出来,我这着急用。”李亚男费尽力气,企图挣脱开束缚,却也徒然,便摆出一副要杀要剐随你便的姿态,还用言语刺激老潘道:“当初是签了合同的,三年的定期,你要是有本事就自己去要。”老潘气的胸脯上下颤抖,骂道:“cnm,那钱要拿来救命的。”李亚男眼泪瞬间决堤般涌出,很快就哭花了妆容,可她并未屈服,语气更加强硬道:“潘伟龙,你再不松手,我就报警了。”楼道里陆续有人上前围观,大家对老潘指指点点。几个上了年纪的老太太开始劝说老潘,几个富有正义感的中年男子准备出手搭救李亚男。我上前把老潘拉开,劝慰他钱的事儿日后再说,当下是好好照料他爸。在众人不断地施压下,老潘最终松开了手,怒气无处安放,便都聚集到了脸上,令人不寒而栗。李亚男活动了下手腕,一边擦拭眼泪,一边展平褶皱的衬衣。老潘扭过头去,摆出一副老子多看你一眼老子死全家的神态,却又忍不住用余光扫视身后这位泪人。僵持片刻后,李亚男踩着高跟鞋,头也不回地朝着楼梯口跑去,而后光速般地消失在了我的视线里。看热闹的人都散了,老潘点了一支烟,刚送到嘴边,就被值班护士给抢了过去。护士指着公共场所禁止吸烟的牌子,把老潘好生数落了一顿。老潘欲哭无泪。我陪着老潘在楼道里静默了十多分钟,他的情绪这才有所好转。安抚好老潘后,我困得天昏地暗,实在扛不住了,起身回家。刚走到楼梯口,潘弟拎着两个煎饼果子从楼下晃晃悠悠地走了上来,嘴角还残留着一些豆腐脑的卤子,看来是刚刚饱餐了一顿老北京早点。潘弟一边比划一边说:“大门口有个医闹跟保安打了起来,脑袋都出血了,警察都来了......”老潘抢过潘弟手中的煎饼,塞给了我一个:“大姚,先吃个煎饼垫垫肚子,我爸这算是稳住了,今天真是多亏你了。”我拍了拍老潘肩膀,安慰说:“都会好起来的。”老潘一脸真诚:“大恩不言谢,那钱我尽快还你。”我摆手道:“不急,你先过了眼下这关再说吧。”我再次挥手,转身走到楼梯口时,听到身后传来潘弟的声音。他正向老潘询问附近哪里有网吧。我不禁叹了口气,开始心疼起老潘来。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
9 阅读
0 评论
0 点赞
2023-03-24
区块链交易隐私如何保证?华为零知识证明技术实战解析
摘要:本文通过介绍华为如何在同态加密及零知识证明框架的集成介绍来介绍了一些对金融领域交易隐私保护的思路,通过代码结和应用场景描述了zksnark如何集成到现有联盟链体系保护交易隐私。本文分享自华为云社区《区块链交易隐私如何保证?华为零知识证明技术实战解析》,作者:麦冬爸 。什么是零知识证明?证明者在不泄露任何有效知识的情况下,验证者可以验证某个论断是正确的。图1给出一个有趣的例子,Alice把自己的签名的信封放到一个保险箱中,Bob说他知道这个保险箱的密码,Alice让Bob证明给她看。Bob打开保险箱,把信封拿出来给Alice。Alice验证信封上的签名,确认了Bob确实知道这个密码。这个例子就是Bob没有告诉Alice密码却证明自己知道密码的的过程很好的解释了零知识证明的概念。基于非对称加密和数字签名的证书认证过程,其实也是一个零知识证明的过程,验证者并不需要知晓CA证书,就可以验证对方是由CA签发的下一级证书。零知识证明技术不管应用于金融还是其他领域,都可以对隐私保护,性能提升,或者安全性等场景带来很多帮助。下面,主要从隐私维度来分享华为零知识证明相关技术。图1 零知识证明零知识证明应用于同态加密保护交易隐私,使能金融业务目前金融转账交易场景中对于隐私保护已经越来越重视,隐私也成为区块链急需解决的一个重要问题。那基于如下问题, A向B转账10元,需要区块链节点记账,但是不想让区块链节点知道交易金额以及最新余额,也是金融场景中一个非常常见的问题。图2 同态加密基于这种场景如何解决区块链技术应用于金融的隐私和可用性?华为目前引入同态加密(解决隐私问题)。同态加密(英語:Homomorphic encryption)是一种加密形式,它允许人们对密文进行特定形式的代数运算得到仍然是加密的结果,将其解密所得到的结果与对明文进行同样的运算结果一样。换言之,这项技术令人们可以在加密的数据中进行诸如检索、比较等操作,得出正确的结果,而在整个处理过程中无需对数据进行解密。在此基础上创新式提出了同态加密范围证明(一种针对数字的零知识证明技术,在不泄露具体数字值的情况下,获得数字的范围,从而验证数字所代表的交易的有效性)。基于集成到区块链系统中的同态加密库以及修改同态加密库实现的零知识证明能力实现了隐私转账的能力,一个密文和另一个密文相加或相乘实现转账中的密文交易,零知识证明在整个的计算过程中不暴露任一方的信息证明对方可以完成转账这一流程,在不泄露具体数字的情况下得到数字的范围。从而验证数字所代表交易的有效性。使用同态加密库的app端sample代码示例下面我们看一下零知识证明在代码中是如何应用的,Demo代码使用地址:support.huaweicloud.com/devg-bcs/bc…。下面讲解的代码都可以在上面的地址中下载全量代码查看。图3 同态加密链代码1图4 同态加密链代码2图3是同态加密的链代码,首先定义好一个transaction的结构,在进行初始化,基于Query方法可以根据B的地址调用链码获取B的公钥 ,第二个红框获取A的当前加密余额,PrepareTxInfo方法构建A向B的转账信息,最后通过invoke调用完成A到B的转账的过程。在图4 transfer链代码方法中,首先通过getstate获取A和B两个账户的当前余额,然后最重要的一步,要去验证他的余额,所以说我们这个方法validatetxinfo,基于范围/等式证明验证交易数据的合规性,基于同态加密算法计算交易后的账户余额,最后更新交易后A账户和B账户的余额。同态加密的这一步中,应用了零知识证明的相关的这个技术和能力来实现了这个同态加密更加的高效和安全。基于zksnark的零知识证明技术交互式证明和非交互式证明图5 交互式证明零知识证明又分为交互式证明和非交互式证明,有两个有趣的例子很好的解释了这个概念。如上图5所示,男子向女子声称有CD处的钥匙,女子不相信说“你拿出来给我看啊”,男子想“你让我拿我就拿多没面子啊”,男子说”这样吧,按下面步骤玩个游戏”1.女子站在A点2.男子从B点走到C点或者D点3.男子从B点消失后,女子从A点走到B点4.女子喊话“从左边出来”,或者“从右边出来”5.男子按照女子的要求从对应一侧走出女子说“你肯定作弊,刚才我喊左边出来,你刚好就是从左边进去的”,男子说:“你回到A点,我们再来一遍”如果每次都成功,说明B确实有CD处的钥匙,该证明是需要A,B不停的交互。非交互式零知识(NizK)证明方案由算法设置、证明和验证定义,具体来说,我们有params=Setup(),其中输入是安全参数,输出是ZKP算法系统的参数。证明语法由证明=证明(x,w)给出。该算法接收某些NP语言L的实例x和见证w作为输入,并输出零知识证明。验证算法接收证明作为输入,并输出位b,如果验证者接受证明,则该位等于1。通俗一点就比如说我有一个秘密,我不想告诉别人,但是我又得让别人相信。我是知道这个秘密的,类似于这种,但是我们为什么需要有这种非交互式呢?因为交互式证明的其实只对原始的验证者有效,其他的任何人都不能够信任这个证明。这种场景下呢,就会导致这个验证者可以和这个证明人串通,证明人可以伪造证明。验证者也可以用这种方式做一些伪造。因此,验证者必须保存一些数据,直到相关的证明被验证完毕。这样就会造成一些秘密参数泄露的这种风险。这种交互式证明也有它的用处,就比如说一个证明人只想让一个特定的验证者来去验证,但是这个证证明人和验证者必须保持在线,并且去对每一个验证者执行同样的计算。什么是zk-snark?zk-SNARK 是 Zero-knowledge succinctnon-interactive arguments of knowledge 的缩写,他的意思是: zero knowledge:零知识,即在证明的过程中不透露任何隐私数据: succinct:简洁的,主要是指验证过程不涉及大量数据传输以及验证算法简单; non-interactive:无交互。证明者与验证者之间不需要交互即可实现证 明,交互的零知识证明要求每个验证者都要向证明者发送数据来完成证明,而无交互的零知识证明,证明者只需要计算一次产生一个 proof,所有的验 证者都可以验证这个 proof。 zk-SNARK 是证明某个声明是真却不泄露关于该声明的隐私信息的一 个很有创新性的算法,他可以证明某人知道某个秘密却不会泄露关于这个秘密的任何信息。这个算法可以解决什么问题呢?它是对所有零知识证明问题的通用解决方法,由加密数字货币zcash首次使用并开源。zk-SNARK的优点:1.通用库,可以解很多零知识证明问题2.验证证明性能较高(300tps)zk-SNARK的不足:1.底层模型不容易理解,用户需要根据具体的零知识证明问题,在上层构建自己的业务模型,这块开发的工作量较大。2.生成每笔交易时延较长(57s)应用场景ZKP的应用场景包括匿名可验证投票、数字资产安全交换、安全远程生物识别认证和安全拍卖,具体如下。匿名可核查投票:投票是保障一个国家或控股公司民主的重要组成部分。然而,选民的隐私可能在投票过程中被泄露。此外,投票结果很难得到安全的核实。ZKP是实施匿名可核查投票的一种可用方法。根据ZKP的使用,符合条件的选民可以在不泄露身份的情况下投票表决显示他们的权利。此外,ZKP允许符合条件的选民要求提供可核查的证据,证明他们的选票包含在负责报告投票结果的机构的最终计票中。数字资产的安全交换:数字资产是二进制数据的集合,它们是唯一可识别和有价值的。如果两个用户希望交换其数字资产,则用户的隐私,包括身份和交换数字资产的内容,可能会在交换过程中泄露。根据ZKP的使用,数字资产可以在不泄露用户隐私的情况下交换。此外,ZKP生成了可验证的证据,其中包含数字资产交换的过程。安全远程生物识别身份验证:远程生物识别身份验证是一种可用于通过使用指纹、面部图像、虹膜或血管模式等生物识别模式识别用户访问权限的方法。但是,在实施远程生物识别认证时,用户的生物识别模式可能会泄露给不受信任的第三方。使用ZKP可以解决这个问题。此外,ZKP生成还提供了可核查的证据,其中包括识别用户访问权限的过程。安全拍卖:政府拍卖是政府从多个供应商中选择最低出价的拍卖,这些供应商以竞争性方式销售其商品和服务。本次拍卖包括两个阶段。在第一阶段,多个供应商投标,但公众不知道。在第二阶段,这些投标是开放的。政府选择中标供应商,后者出价最低。然而,中标供应商的选择可能会泄露其他中标供应商的投标和身份。ZKP可以解决这个问题。ZKP为每个输标供应商生成可核查的证据。该证明证实输标供应商的投标与中标供应商的投标之间的差额是正的。zk-snark应用于区块链的挑战及实现零知识证明是指一方(证明者)向另 一方(验证者)证明一个陈述是正确的,而无需透露除该陈述正确以外的任何信 息,适用于解决任 何NP问题。而区块链 恰好可以抽象成多方验证交易是否有效(NP问题)的平台,因此,两者是天然相适 应的。将零知识证明应用到区块链中 需要考虑的技 术挑战分为两大类:一类 是适用于隐私保护的区块链架构设计方案,包括隐秘交易所花资产存在性证明、匿 名资产双花问题、匿名资产花费与转移、隐秘交易不可区分等技术挑战;另一类是零 知识证明技术 本身带来的挑战,包括 参数 初始化阶段、算法性能以及安 全问题等技术挑战。华为集成了zksnark架构到区块链系统中来解决上面的挑战。我们知道有多种方法可以为区块链启用zkSNark。这些都降低了配对函数和椭圆曲线操作的实际成本。1. 提高合约虚拟机的性能相较第二种更难实现。可以在合约虚拟机中添加功能和限制,这将允许更好的实时编译和解释,而无需在现有实现中进行太多必要的更改。下面的转账场景就是基于此种方案的实现。2. 仅提高某些配对函数和椭圆曲线乘法的在合约虚拟机的性能通过强制所有区块链客户端实现特定的配对函数和在特定椭圆曲线上的乘法作为所谓的预编译契约来实现。好处是,这可能更容易和更快地实现。另一方面,缺点是我们固定在一定的配对函数和一定的椭圆曲线上。区块链的任何新客户端都必须重新实施这些预编译的合同。此外,如果有人找到更好的zkSNark、更好的配对函数或更好的椭圆曲线,或者如果在椭圆曲线、配对函数或zkSNark中发现缺陷,必须添加新的预编译合同。转账应用图6 转账初始化图6包含了对这个余额初始化的一个过程,及生成交易也就是真正转账的过程,下一步就是验证,证明,完成验证,最后一步,才是生成交易,也就是收款的一个过程。拿初始化举个例子,比如说爱丽丝初始化了一个100块钱的一个余额,然后鲍勃十块钱。转账的过程如下,爱丽丝转20块钱给鲍勃,就会生成生成一对Spending key / Paying Key ,相当于临时交易的一个账户,Paying Key给对方,SpendingKey留给自己,用于证明交易链上的交易是谁的。然后再基于这个生成相应的这个交易和相关的证明。完成交易生成这一步。下一步进行转账的验证证明的这个过程,验证逻辑如下, 验证逻辑:Nullifier NF.axxxxx1 和NF.axxxxx2 是否在Nullifiers 列表中,也就是说,是否有被花过;验证NF.axxxxx1 和NF.axxxxx2 是格式是否合法的花费凭据,且对应的commitment在链上(Proof + Merkle tree root),这里有需要验证Merkle tree root在 是有效的;验证input == output 金额守恒,即:100 + 0 = 80+0+20;数字范围满足要求:100-20 >0 && 20 > 0,把这个过程都验证完了以后呢,最后一步就是完成验证。完成验证的话,他其实还会做一些这个类似于交易内容的隐藏,身份隐藏,交易行为的隐藏,来保护整个的这个转账交易的过程的这个安全性。包括做一些类似于混淆电路的能力。有混淆的交易内容,且加密,验证者并不知道使用链上是哪个Commitment作为输入,只知道没有被花过,且在链上。身份隐藏让其无法确定接收方是谁,交易行为隐藏让其无法确定这个交易是发送还是接收。做一些安全性的保证之后呢,然后来完成整个的验证的过程。最后,生成交易,然后收款,整个转账过程就结束了。基于零知识证明的一个简单的一个能力,包括一个基础的转账,被华为集成在整个零知识证明使用接口中。集成的整个零知识证明架构也能用来开发一些零知识证明基础应用,做一些简单的解决方案。总结交易隐私保护这块的技术应该是比较多的,零知识证明技术并不一定是一个最好的选择,在安全领域中还有很多诸如同态,秘密分享,不经意传输,或者基于TEE硬件的一些隐私保护能力,可以去做一些隐私保护。但是零知识证明其优点也是很显著,未来区块链的隐私保护仍然任重而道远,如何实现快速高效、可信的零知识证明算法以及如何实现能够抵抗量子计算的零知识证明算法,都是需要进一步解决的问题。基于线上我们提供的一些基本的能力,要是大家感兴趣,可以到之前的网址下载相应的代码示例。点击关注,第一时间了解华为云新鲜技术~
2023年03月24日
8 阅读
0 评论
0 点赞
2023-03-24
区块链钱包开发(Android篇)
简介本文主要内容为区块链钱包移动端(Android)开发,介绍比特币钱包和以太坊钱包的开发过程,包含钱包的主要功能: 创建钱包,钱包余额,导出钱包,钱包转账等。Demo地址区块链钱包在日常生活中,大家都会买个钱包用于存放政府机构发行的纸币,那么什么是数字资产世界的钱包呢?比特币钱包以太坊钱包:Mist、Parity、MyEhterWallet、ImToken、MetaTask、Ledger(硬件钱包)助记词等价于私钥 Keystore + 密码 等价于私钥 EOS钱包NEO钱包量子钱包On-chain给一个钱包地址发送数字货币, 这笔交易在全网广播、被确认、被打包进区块。这是发生在链上的,被称为on-chain交易。on-chain钱包需要自己保管私钥。 Off-chain相对于on-chain交易是off-chain交易。通常,通过交易所进行的交易是off-chain的,本人并没有私钥。私钥在交易所,由交易所托管。所以交易所的钱包也是中心化的钱包。 冷钱包冷即离线、断网,也就是说私钥存储的位置不能被网络所访问。例如纸钱包、脑钱包、硬件钱包等等。 热钱包热即联网,也就是私钥存储在能被网络访问的位置。 例如存放在交易所的、在线钱包网站、手机App钱包都属于热钱包。通常而言,冷钱包更加安全,热钱包使用更加方便。 非确定性钱包 钱包随机生成 确定性钱包(HD Wallets) 同一个种子,能够派生一样的密钥对集合 全节点钱包除了保存私钥外,全节点钱包还有保存了所有区块的数据,最为著名的是bitcoin-core。 轻钱包它不必保存所有区块的数据,只保存跟自己相关的数据。基本可以实现去中心化。 中心化钱包在交易所中的钱包,以及类似 OKLink 提供的保险柜服务。 比特币钱包bitcoin.org/en/develope…比特币钱包的组成 比特币钱包地址的创建过程 BIP32 BIP39 BIP43 BIP44 BitcoinJ创建钱包 Bitcoin钱包收款和转账 比特币钱包组成比特币钱包分为两部分:钱包程序和钱包文件钱包文件保存私钥和转账记录Wallet containing 0.01 BTC (spendable: 0.01 BTC) in: 0 pending transactions 1 unspent transactions 0 spent transactions 0 dead transactions Last seen best block: 1384907 (2018-08-22T03:38:42Z): 0000000000000030fe01a48a7cd6b0c52909a7d019084d195ae3ebd2889c82ec Keys: Earliest creation time: 2018-08-20T07:51:29Z Seed birthday: 1534751489 [2018-08-20T07:51:29Z] Key to watch: tpubD92y4mcSrbcSxANfCgiWx7h7sGquSF4ogNPcUxC2GECSwgWBMNPMo2C8nxez2ngvSS4UfaGhSunemWoqZ6aAAzLb4WLsmQxDirfFgE9tG5J addr:mq5gdvJDuDEmNKFPbgMn8pGm3pyJvkSsHv hash160:68e9c9e06890527cd0f0b59d83333502ac127bef (M/0H/0/0) >>> UNSPENT: 0.01 BTC total value (sends 0.00 BTC and receives 0.01 BTC) confidence: Seen by 7 peers (most recently: 2018-08-22T03:33:33Z). Appeared in best chain at height 1384907, depth 1. Source: NETWORK a82c35c2133bd357bfa462f82d75b28787afcdcd20c8b89cd2b78f48138d6e9f updated: 2018-08-22T03:31:53Z in PUSHDATA(71)[304402205d3e0974b4604b92e09f83950b183100bd47243c9cb548f2213a9ca26e83bdd3022018278c7ce9b65982e6c67ba9acf8e6e3898f1dad80702bb1e32c4a0b61195e0f01] PUSHDATA(33)[02f8769ecddd821cc9b75c554978b4a674df28c098e640fd0188b88bf019bc31fa] outpoint:8294b8dcf6513ab13321d4dd1642bf1c19600a313bf1ebe8511521dcd4dd0277:0 out DUP HASH160 PUSHDATA(20)[8843beff2291c5a00aa00fbd8a541f800c83b86d] EQUALVERIFY CHECKSIG 1.1899548 BTC out DUP HASH160 PUSHDATA(20)[68e9c9e06890527cd0f0b59d83333502ac127bef] EQUALVERIFY CHECKSIG 0.01 BTC prps UNKNOWN ## ## 复制代码钱包程序钱包程序,创建公钥来接受satoshi,使用私钥来使用satoshi。钱包程序可以拆分出3个独立的模块:公钥分发模块、签名模块、网络模块 比特币单位: 1比特币(Bitcoins,BTC) 0.01比特分(Bitcent,cBTC) 0.001毫比特(Milli-Bitcoins,mBTC) 0.000001微比特(Micro-Bitcoins,μBTC或uBTC) 0.00000001聪(satoshi)(基本单位) 1 bitcoin (BTC) = 1000 millibitcoins (mBTC) = 1 million microbitcoins (uBTC) = 100 million Satoshi 复制代码根据三个模块的组合,可以分为全服务钱包、只签名钱包(离线钱包和硬件钱包)、只分发钱包。BIP协议Bitcoin Improvement ProposalsBIP32BIP32:定义了层级确定性钱包(hierarchical deterministic wallets),是一个系统可以从单一个 seed 产生一树状结构储存多组 keypairs(私钥和公钥)。好处是可以方便的备份、转移到其他相容装置(因为都只需要 seed),以及分层的权限控制等。作用:1、备份更容易。按照比特币的原则,尽量不要使用同一个地址,一个地址只使用一次,这样会导致频繁备份钱包。HD钱包只需要在创建时保存主密钥,通过主密钥可以派生出所有的子密钥。 2、私钥离线更安全。主私钥离线存储,主公钥在线使用,通过主公钥可以派生出所有的子公钥。例如:给每个商品提供一个收款地址。 3、利于管理,权限控制。树状结构类似于公司的组织架构,可以给各个部门指定一个密钥分支。 4、记账。只使用公钥即可记账。 BIP39BIP39:将seed 用方便记忆和书写的单字表示。一般由 12 个单字组成,称为 mnemonic code(phrase),中文称为助记词或助记码。例如: average green proud remember advance trick estate oblige trouble when cube personWordlists工具BIP43BIP43BIP43对BIP32树结构增加了子索引标识purpose的拓展m/purpose'/*BIP32的索引:m/0'/*BIP44的索引:m/44'/*。BIP44BIP44:基于BIP32和BIP43,赋予树状结构中的各层特殊的意义。让同一个 seed 可以支援多币种、多帐户等。各层定义如下:m / purpose' / coin_type' / account' / change / address_index复制代码purporse': 固定值44', 代表是BIP44 coin_type': 这个代表的是币种, 可以兼容很多种币, 比如BTC是0', ETH是60', 例如:btc一般是 m/44'/0'/0'/0, eth一般是 m/44'/60'/0'/0 account':账号 change': 0表示外部链(External Chain),用户接收比特币,1表示内部链(Internal Chain),用于接收找零 address_index:钱包索引 钱包最佳实践使用助记词(BIP39) 使用层级确定性钱包(HD Wallets)(BIP32) 使用多目的HD Wallets(BIP43) 使用多币种,多账号的HD Wallets (BIP44) 比特币钱包地址创建过程1、生成128bit~256bit作为私钥2、通过secp256k1椭圆曲线算法得到私钥对应的公钥3、将公钥进行SHA-256,得到公钥Hash4、将3的结果进行RIMEMD-1605、将4中结果添加1个字节版本号6、将5中结果进行两次SHA-256,取前4个字节作为checksum7、将6中结果添加到5中结果的末尾8、将7中结果进行Base58,结果为比特币地址BitcoinJ创建钱包Bitcoinj是比特币协议Java版本实现的库。添加依赖:dependencies { implementation 'org.bitcoinj:bitcoinj-core:0.14.7' implementation 'org.slf4j:slf4j-api:1.7.25' implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' implementation 'com.google.zxing:core:3.3.3'//二维码 } 复制代码Android最大方法数的限制,60K 开启multiDexEnabledandroid { compileSdkVersion 28 defaultConfig { multiDexEnabled true } } dependencies { implementation 'com.android.support:multidex:1.0.3' } 复制代码创建新钱包File walletFile = activity.getFileStreamPath("wallet-protobuf"); //创建钱包 wallet = new Wallet(Constants.NETWORK_PARAMETERS); //创建WalletFiles,设置自动保存Wallet WalletFiles walletFiles = wallet.autosaveToFile(walletFile, 3 * 1000, TimeUnit.MILLISECONDS, null); //立即保存 walletFiles.saveNow(); 复制代码钱包创建源码分析:Wallet KeyChainGroup DeterministicKeyChain DeterministicSeed protected DeterministicKeyChain(DeterministicSeed seed, @Nullable KeyCrypter crypter) { this.seed = seed; basicKeyChain = new BasicKeyChain(crypter); if (!seed.isEncrypted()) { rootKey = HDKeyDerivation.createMasterPrivateKey(checkNotNull(seed.getSeedBytes())); rootKey.setCreationTimeSeconds(seed.getCreationTimeSeconds()); addToBasicChain(rootKey); hierarchy = new DeterministicHierarchy(rootKey); for (int i = 1; i <= getAccountPath().size(); i++) { addToBasicChain(hierarchy.get(getAccountPath().subList(0, i), false, true)); } initializeHierarchyUnencrypted(rootKey); } // Else... // We can't initialize ourselves with just an encrypted seed, so we expected deserialization code to do the // rest of the setup (loading the root key). } 复制代码 获取钱包地址Address address = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); address.toString(); 复制代码在获取地址的过程中会调用RIMEMD-160算法处理公钥hash://Utils.java public static byte[] sha256hash160(byte[] input) { byte[] sha256 = Sha256Hash.hash(input); RIPEMD160Digest digest = new RIPEMD160Digest(); digest.update(sha256, 0, sha256.length); byte[] out = new byte[20]; digest.doFinal(out, 0); return out; } 复制代码处理公钥hash后会进行Base58算法://VersionedChecksummedBytes.java public final String toBase58() { // A stringified buffer is: // 1 byte version + data bytes + 4 bytes check code (a truncated hash) byte[] addressBytes = new byte[1 + bytes.length + 4]; addressBytes[0] = (byte) version; System.arraycopy(bytes, 0, addressBytes, 1, bytes.length); byte[] checksum = Sha256Hash.hashTwice(addressBytes, 0, bytes.length + 1); System.arraycopy(checksum, 0, addressBytes, bytes.length + 1, 4); return Base58.encode(addressBytes); } 复制代码从文件中加载钱包//读取钱包文件 File walletFile = activity.getFileStreamPath("wallet-protobuf"); if (walletFile.exists()) { InputStream inputStream = new FileInputStream(walletFile); //反序列化 wallet = new WalletProtobufSerializer().readWallet(inputStream); //设置自动保存 wallet.autosaveToFile(walletFile, 3 * 1000, TimeUnit.MILLISECONDS, null); //清理钱包 wallet.cleanup(); } 复制代码创建地址二维码String s = BitcoinURI.convertToBitcoinURI(address, null, null, null); Bitmap bitmap = Qr.bitmap(s); BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bitmap); bitmapDrawable.setFilterBitmap(false); mQrImageView.setImageDrawable(bitmapDrawable); public static Bitmap bitmap(final String content) { try { final Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); hints.put(EncodeHintType.MARGIN, 0); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); final BitMatrix result = QR_CODE_WRITER.encode(content, BarcodeFormat.QR_CODE, 0, 0, hints); final int width = result.getWidth(); final int height = result.getHeight(); final byte[] pixels = new byte[width * height]; for (int y = 0; y < height; y++) { final int offset = y * width; for (int x = 0; x < width; x++) { pixels[offset + x] = (byte) (result.get(x, y) ? -1 : 0); } } final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8); bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(pixels)); return bitmap; } catch (final WriterException x) { log.info("problem creating qr code", x); return null; } } 复制代码Bitcoin钱包收款和转账比特币钱包余额需要统计所有钱包地址对应的UTXOSimplified Payment Verification (SPV):节点无需下载所有的区块数据,而只需要加载所有区块头数据(block header的大小为80B),即可验证这笔交易是否曾经被比特币网络认证过。布隆过滤器(Bloom Filter):过滤掉那些不包含有目标地址的交易信息,这一步能避免掉大量不相关的数据下载。创建区块链//创建区块链文件 File blockChainFile = new File(getDir("blockstore", Context.MODE_PRIVATE), "blockchain"); //创建SPVBlockStore,管理区块数据 blockStore = new SPVBlockStore(Constants.NETWORK_PARAMETERS, blockChainFile); //加载检查点 final InputStream checkpointsInputStream = getAssets().open("checkpoints-testnet.txt"); CheckpointManager.checkpoint(Constants.NETWORK_PARAMETERS, checkpointsInputStream, blockStore, earliestKeyCreationTime); //创建区块链对象 blockChain = new BlockChain(Constants.NETWORK_PARAMETERS, wallet, blockStore); 复制代码同步区块链//添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> private void startup() { Log.d(TAG, "startup: "); peerGroup = new PeerGroup(Constants.NETWORK_PARAMETERS, blockChain); peerGroup.setDownloadTxDependencies(0); // recursive implementation causes StackOverflowError peerGroup.addWallet(wallet);//设置钱包,重要 try { PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_ACTIVITIES); peerGroup.setUserAgent(USER_AGENT, packageInfo.versionName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } peerGroup.setMaxConnections(8); int connectTimeout = (int) (15 * DateUtils.SECOND_IN_MILLIS); peerGroup.setConnectTimeoutMillis(connectTimeout); int discoveryTimeout = (int) (10 * DateUtils.SECOND_IN_MILLIS); peerGroup.addConnectedEventListener(mPeerConnectedEventListener); peerGroup.addDisconnectedEventListener(mPeerDisconnectedEventListener); peerGroup.addDiscoveredEventListener(mPeerDiscoveredEventListener); peerGroup.setPeerDiscoveryTimeoutMillis(discoveryTimeout); //添加节点探索器,重要 peerGroup.addPeerDiscovery(new PeerDiscovery() { private final PeerDiscovery normalPeerDiscovery = MultiplexingDiscovery .forServices(Constants.NETWORK_PARAMETERS, 0); @Override public InetSocketAddress[] getPeers(final long services, final long timeoutValue, final TimeUnit timeoutUnit) throws PeerDiscoveryException { return normalPeerDiscovery.getPeers(services, timeoutValue, timeoutUnit); } @Override public void shutdown() { normalPeerDiscovery.shutdown(); } }); peerGroup.startAsync(); peerGroup.startBlockChainDownload(null); } 复制代码比特币收款获取测试用比特币:testnet.manu.backend.hamburg/faucet 刚收到的币可能需要几分钟后才能使用//监听比特币接受事件 wallet.addCoinsReceivedEventListener(mWalletListener); //刷新余额 Coin balance = wallet.getBalance(Wallet.BalanceType.ESTIMATED); 复制代码比特币转账比特币测试链转账查询 创建一个Tx,对Tx进行签名,对Tx进行P2P网络广播Address address = Address.fromBase58(Constants.NETWORK_PARAMETERS, to); //转账金额,以mBTC为单位 Coin coin = MonetaryFormat.MBTC.parse(amount); //创建请求 SendRequest sendRequest = SendRequest.to(address, coin); try { //创建Transaction Transaction transaction = wallet.sendCoinsOffline(sendRequest); //通过P2P广播 BlockChainService.broadcastTransaction(BitcoinWalletActivity.this, transaction); } catch (InsufficientMoneyException e) { Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); e.printStackTrace(); } public static void broadcastTransaction(Context context, Transaction transaction) { Intent intent = new Intent(ACTION_BROADCAST_TRANSACTION, null, context, BlockChainService.class); intent.putExtra(ACTION_BROADCAST_TRANSACTION_HASH, transaction.getHash().getBytes()); context.startService(intent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: "); if (intent != null) { byte[] txHash = intent.getByteArrayExtra("tx"); if (txHash != null) { Sha256Hash sha256Hash = Sha256Hash.wrap(txHash); Transaction transaction = BitcoinWalletManager.getInstance().getWallet().getTransaction(sha256Hash); peerGroup.broadcastTransaction(transaction); Log.d(TAG, "onStartCommand: " + sha256Hash.toString()); } } return super.onStartCommand(intent, flags, startId); } 复制代码以太坊钱包github.com/ethereumboo…以太坊钱包功能与比特币钱包功能类似,获取用户余额,管理地址和密钥,转账、智能合约调用。以太坊钱包一般不用在本地维护区块链数据,只需要使用JSON-RPC访问钱包文件KeyStore = 私钥 + 密码如果使用ImToken创建钱包,创建了助记词,密码用来加密钱包地址对应的子私钥,加密的结果就是Keystore.{ "address": "001d3f1ef827552ae1114027bd3ecf1f086ba0f9", "crypto": { "cipher": "aes-128-ctr", "ciphertext": "233a9f4d236ed0c13394b504b6da5df02587c8bf1ad8946f6f2b58f055507ece", "cipherparams": { "iv": "d10c6ec5bae81b6cb9144de81037fa15" }, "kdf": "scrypt", "kdfparams": { "dklen": 32, "n": 262144, "p": 1, "r": 8, "salt": "99d37a47c7c9429c66976f643f386a61b78b97f3246adca89abe4245d2788407" }, "mac": "594c8df1c8ee0ded8255a50caf07e8c12061fd859f4b7c76ab704b17c957e842" }, "id": "4fcb2ba4-ccdb-424f-89d5-26cce304bf9c", "version": 3 } 复制代码以太坊钱包地址创建过程1、使用Secp256k1创建公私钥2、通过Keccak算法得到公钥Hash值,进而得到长度为40的地址字符串3、一般的,会在地址字符串签名加前缀"0x"Web3j创建钱包Web3j添加Web3j依赖implementation 'org.web3j:core:3.3.1-android' 复制代码创建新钱包这里不涉及BIP协议,为非确定性钱包Wallet.createStandard() 出现OOM, Out of Memory juejin.cn/post/684490…File walletDir = contextWrapper.getDir("eth", Context.MODE_PRIVATE); //生成密钥对 ECKeyPair ecKeyPair = Keys.createEcKeyPair(); //WalletFile = KeyStore WalletFile wallet = Wallet.createLight(PASSWORD, ecKeyPair); String walletFileName = getWalletFileName(wallet); File destination = new File(walletDir, walletFileName); objectMapper.writeValue(destination, wallet); 复制代码加载钱包文件File[] files = walletDir.listFiles(); wallet = objectMapper.readValue(files[0], WalletFile.class); 复制代码通过助记词创建钱包涉及BIP协议,但没有遵循bitcoin地址只使用一次的原则,钱包一般只使用派生出来第一个地址可通过工具检查派生的地址是否正确//创建助记词 public List<String> createMnemonics() throws MnemonicException.MnemonicLengthException { SecureRandom secureRandom = new SecureRandom(); byte[] entropy = new byte[DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8]; secureRandom.nextBytes(entropy); return MnemonicCode.INSTANCE.toMnemonic(entropy); } //m / 44' / 60' / 0' / 0 //Hardened意思就是派生加固,防止获取到一个子私钥之后可以派生出后面的子私钥 //必须还有上一级的父私钥才能派生 public static final ImmutableList<ChildNumber> BIP44_ETH_ACCOUNT_ZERO_PATH = ImmutableList.of(new ChildNumber(44, true), new ChildNumber(60, true), ChildNumber.ZERO_HARDENED, ChildNumber.ZERO); //通过助记词生成HD钱包 public void onCreateWallet(View view) { byte[] seed = MnemonicCode.toSeed(words, ""); DeterministicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed); DeterministicHierarchy deterministicHierarchy = new DeterministicHierarchy(masterPrivateKey); // m / 44' / 60' / 0' / 0 / 0 DeterministicKey deterministicKey = deterministicHierarchy .deriveChild(BIP44_ETH_ACCOUNT_ZERO_PATH, false, true, new ChildNumber(0)); byte[] bytes = deterministicKey.getPrivKeyBytes(); ECKeyPair keyPair = ECKeyPair.create(bytes); try { WalletFile walletFile = Wallet.createLight(PASSWORD, keyPair); String address = walletFile.getAddress(); mAddress.setText("0x" + address); } catch (CipherException e) { e.printStackTrace(); } } 复制代码导出钱包导出KeyStorepublic String exportKeyStore(WalletFile wallet) { try { return objectMapper.writeValueAsString(wallet); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } 复制代码导出私钥public String exportPrivateKey(WalletFile wallet) { try { ECKeyPair ecKeyPair = Wallet.decrypt(PASSWORD, wallet); BigInteger privateKey = ecKeyPair.getPrivateKey(); return Numeric.toHexStringNoPrefixZeroPadded(privateKey, Keys.PRIVATE_KEY_LENGTH_IN_HEX); } catch (CipherException e) { e.printStackTrace(); } return null; } 复制代码导出助记词一般可以将助记词加密存储,导出时解密。注意无法从KeyStore或者私钥导出助记词。例如:使用IMToken导入私钥或者KeyStore创建的钱包,没有导出助记词的功能 如果是通过助记词创建的,就会有导出助记词的功能ETH交易获取Robsten测试网络ETH查询余额private Web3j mWeb3j = Web3jFactory.build(new HttpService("https://ropsten.infura.io/1UoO4I/")); BigInteger balance = mWeb3j.ethGetBalance(mAddress, DefaultBlockParameterName.LATEST).send().getBalance(); BigDecimal balance = Convert.fromWei(balance.toString(), Convert.Unit.ETHER); 复制代码ETH转账转账记录查询BigInteger transactionCount = mWeb3j.ethGetTransactionCount(mAddress, DefaultBlockParameterName.LATEST).send().getTransactionCount(); BigInteger gasPrice = mWeb3j.ethGasPrice().send().getGasPrice(); BigInteger gasLimit = new BigInteger("200000"); BigDecimal value = Convert.toWei(mAmountEdit.getText().toString().trim(), Convert.Unit.ETHER); String to = mToAddressEdit.getText().toString().trim(); RawTransaction etherTransaction = RawTransaction.createEtherTransaction(transactionCount, gasPrice, gasLimit, to, value.toBigInteger()); ECKeyPair ecKeyPair = Wallet.decrypt("a12345678", mWalletFile); Credentials credentials = Credentials.create(ecKeyPair); byte[] bytes = TransactionEncoder.signMessage(etherTransaction, credentials); String hexValue = Numeric.toHexString(bytes); String transactionHash = mWeb3j.ethSendRawTransaction(hexValue).send().getTransactionHash(); 复制代码Token交易获取某Token余额调用ERC20代币智能合约,获取当前地址的余额//创建Function private Function balanceOf(String owner) { return new Function("balanceOf", Collections.singletonList(new Address(owner)), Collections.singletonList(new TypeReference<Uint256>())); } Function function = balanceOf(mAddress); //调用智能合约 String s = callSmartContractFunction(function, CONTRACT_ADDRESS); List<Type> decode = FunctionReturnDecoder.decode(s, function.getOutputParameters()); if (decode != null && decode.size() > 0) { Uint256 type = (Uint256) decode.get(0); BigInteger tokenBalance = type.getValue(); } private String callSmartContractFunction( Function function, String contractAddress) throws Exception { String encodedFunction = FunctionEncoder.encode(function); org.web3j.protocol.core.methods.response.EthCall response = mWeb3j.ethCall( Transaction.createEthCallTransaction( mAddress, contractAddress, encodedFunction), DefaultBlockParameterName.LATEST) .sendAsync().get(); return response.getValue(); } 复制代码Token转账//创建Function private Function transfer(String to, BigInteger value) { return new Function( "transfer", Arrays.asList(new Address(to), new Uint256(value)), Collections.singletonList(new TypeReference<Bool>() )); } Function transfer = transfer(to, new BigInteger(amount)); //获取私钥,进行签名 ECKeyPair ecKeyPair = Wallet.decrypt("a12345678", mWalletFile); Credentials credentials = Credentials.create(ecKeyPair); String transactionHash = execute(credentials, transfer, CONTRACT_ADDRESS); //执行合约调用 private String execute( Credentials credentials, Function function, String contractAddress) throws Exception { BigInteger nonce = mWeb3j.ethGetTransactionCount(mAddress, DefaultBlockParameterName.LATEST).send().getTransactionCount(); BigInteger gasPrice = mWeb3j.ethGasPrice().send().getGasPrice(); BigInteger gasLimit = new BigInteger("200000"); String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction( nonce, gasPrice, gasLimit, contractAddress, encodedFunction); byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signedMessage); EthSendTransaction transactionResponse = mWeb3j.ethSendRawTransaction(hexValue) .sendAsync().get(); return transactionResponse.getTransactionHash(); } 复制代码
2023年03月24日
6 阅读
0 评论
0 点赞
1
...
80
81
82
...
109