分类 技术前沿 下的文章 - 六币之门
首页
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
搜 索
1
融资周报 | 公开融资事件11起;加密技术公司Toposware完成500万美元融资,Polygon联创参投
107 阅读
2
六币日报 | 九只比特币ETF在6天内积累了9.5万枚BTC;贝莱德决定停止推出XRP现货ETF计划
74 阅读
3
六币日报 | 美国SEC再次推迟对灰度以太坊期货ETF做出决定;Do Kwon已出黑山监狱等待引渡
69 阅读
4
融资周报 | 公开融资事件27起;L1区块链Monad Labs完成2.25亿美元融资,Paradigm领投
68 阅读
5
【ETH钱包开发06】查询某个地址的交易记录
43 阅读
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
登录
搜 索
标签搜索
新闻
日报
元歌Eden
累计撰写
1,087
篇文章
累计收到
0
条评论
首页
栏目
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
页面
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
用户登录
登录
找到
109
篇与
技术前沿
相关的结果
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日
8 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-16 农村青年
(34) 农村青年周末,我带着四叔跟老姚转了转北京城那几个写进教科书里的著名景点。旅游对于许多家庭来说是生活必需品,一年到头,必须出门三五趟。近则郊区周边,远则海外港湾。旅行可以放松心情,促进家庭和睦。不过,旅游对于我家来说,十年前是不敢想的奢侈品,现在也不过是偶尔用来解馋的消费品。财富积累讲究开源节流,老姚没有开源的门路,攒钱只能靠节流。所以当听到长城缆车索道需要每人一百元的时候,他果断拒绝,强忍着腰疼,腿疼,扶着栏杆慢慢地走下山。在景区,一根黄瓜可以卖到十元钱,一份盖饭便宜的也要三十元。好在东西都明码标价,童叟无欺。也因此,我妄想欺骗老姚,在景区进餐的想法也幻灭。我们不得不硬生生地挺着辘辘的饥肠赶回公寓。我在公寓附近找了家便宜的刀削面馆,三十多元钱解决了三个人的肚子。老姚吃得很是香甜,嘴巴不住地夸赞自己的省钱之道,还教育我粒粒皆辛苦。填饱肚子狗,我拖着灌了铅一样的双腿返回住所。找来几张旧报纸铺在房间的石灰地上,在上面又铺了床被子。我睡在地上,老姚睡我的床,四叔睡老潘的床。十多平米的小屋里硬生生地塞了三个人。当然,如果严格遵守公寓门口张贴的管理告示,老姚跟四叔是不被允许在我房间里留宿。不过,没有什么事儿是送一包烟不能解决的,如果有,那就送两包。公寓的保安小哥在收了我两包烟、两瓶啤酒后,原先不可一世的态度发生了一百八十度转变。甚至主动提出为我们放哨,允诺如果房东来访,他会第一时间告知我。四叔跟老姚的突然到访让我身体很累,不过心情却甚是愉悦。听着乡音,聊着家长里短,一切都很亲切。入睡前,我与四叔闲聊,他讲了几件老家最近发生的事儿,我浑身不住地冒冷汗。广袤的农村有着广袤的土地,广袤的土地上住着广大的人群。原来农民都是靠天吃饭,春种秋收,一年到头都扎在土地上,没有多少空闲时间。现如今,农业器械如播种机,收割机越来越先进,种地早已不再是高强度的工作,农村许多劳动力就闲了下来。科技进步最先解放与受益的并不是那些五六十岁的中老年人,而是那批二十岁左右的农村待业青年。一些人在接受完九年义务教育后,不再继续求学。如果是十多年前,这些人会成为农村的青壮年劳动力。他们或在家务农种地,或学一门手艺,如瓦工,木匠,然后随着包工队外出打工,成为各大城市里农民工中的一份子。不过,当下就业形势发生了改变。劳动密集型的产业逐渐升级改造,低端劳动力过剩。与此同时,成长于安逸时代的年轻人也不如父辈那般肯吃苦受累,就算有一份在工地搬砖夯土的工作,大部分人也都会拒绝。好在那些工业,制造业或者服务业比较发达的省份里,待业青年可以去工厂做流水线上的工人,或者去饭店歌厅当服务员,赚钱养家倒也不成问题。不过在一些仍然以农业为主的省份,可供待业青年从事的工作并不多,于是这群人就走上了另外的道路。就在一个月前,我们村东头一条街上,十多户人家被一伙摩托车飞贼洗劫一番。据传损失最大的是村支书姚钱盛家,他家丢了五万多现金。不过,姚钱盛对外宣称只是丢了几件不值钱的金银首饰。这事儿过后,姚钱盛雇人把自家院墙又加盖了半米,同时墙上还安装了玻璃渣,防护电网。我翻看四叔手机上姚钱盛家院墙的照片,看起来特像电视剧里反动地主家中的堡垒据点,就差几挺机枪和几个打手。丢钱还算小事儿,有些人还丧了命。隔壁村有一个开小卖部的人家,盗贼在偷窃时,被主人堵在了家里。经过激烈地打斗,主家男人被盗贼捅了十几刀,一命呜呼,最后人财两失。作案的人基本都是一群二十岁左右的无业游民,他们聚集在一起,打架斗殴,抢劫偷盗,甚至是杀人越货。农村不像城市那样有着严密的监控网络和热心的人民群众,因为缺乏有效的人证物证,许多案子都过了好多年还没有破。贫瘠的农村,贫瘠的物质与精神。路不拾遗,夜不闭户的美好愿景,恐怕只存在于乌托邦式的文学作品中。现实情况下,鸡毛蒜皮都得斤斤计较,蝇营狗苟很是常见。贫穷只会让人瞧不起,甚至连孩子都无法娶妻。富有就怕旁人眼犯红,要时刻提防着坏人的惦念。近几年,村里一些长年在外打拼,攒下些许积蓄的人,很多都举家搬到县上,市里居住。村中荒废坍塌,杂草丛生的院落越来越多。年轻人远离家乡,只留下七八十岁的老人守着故土。像我这样从乡下走出来的孩子,一路披荆斩棘,埋头苦读数载,考入城市大学。毕业后,混入城市中,讨得一份安身立命的工作,每日勤勤恳恳换得一份温饱。诸如空气不好,地铁拥挤,老板谩骂......这些不良待遇都可以不走心,付之一笑。令人心扉痛彻的是“从小到大,梦想被不断地修正。它变得越来越小,也越来越现实。”如今,它已经变成了在帝都能有属于自己的小房子。即便是这样居有定所的基本生活需求,在经过多年的劳心费力后,到头来发现还是求之不得。随着年岁增长,志气被消磨殆尽,又不得不考虑再次转战他乡。回望远方是那归不了的故乡,俯瞰脚下是这难捱的他乡。在追名逐利的社会风气影响下,看到别人盆满钵满,宝马香车,广厦万间,又免不了心急。可是,转而一望,方圆五公里都瞧不见一个真实的励志故事。没有家底,没有资源,没有贵人,在这寒门难出贵子的大形势下,残酷的现实让我们开始得过且过,随波逐流。游戏度日,混一天算一天慢慢地成为了生活常态。可意志消沉,怨天尤人从来都解决不了问题,反而会使原本还算平静的心变得戾气满满。唯有背着行囊,举步前行,希冀未来能有一番别样的光景。至少,目前大多数人还相信,知识能改变命运,勤劳终能致富。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
5 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-18 养儿防老
(37) 求助电话日子熬到了周末。没有想去玩的地方,亦没有陪玩的人,但我还是期盼周末,从每周一就开始期盼。周六晚上,我光着膀子坐在电脑前玩仙剑。游戏正酣时,突然从屋外传来了一阵巨大的声响。随后一声响彻云霄的CNM在公寓走廊里回荡。大于17米长的走廊满足产生回声的条件。于是,余音绕梁,久久不能散去。骂人者中气十足,声如洪钟。闻声识人,应该是住我隔壁的健身大哥---柳力。我推开门,果不其然。当下,健身大哥正跟门卫小哥扭打在一起。二人面红耳赤,手脚并用,互有损伤。狠话与脏话在走廊里交替穿梭。几个女租户推开门,瞧见状况后,立马又关上门,生怕惹火烧身;几个男租户有开着门看热闹的,也有上前欲劝架的;当然,还有我这样正犹豫是关门,是看热闹,还是前去劝架的。虽然健身大哥有着一身的腱子肉,但目前来看,他似乎并没有占据上风。因为门卫小哥手上有一根警棍,一寸长一寸强。泰山压顶,黑虎掏心,猴子偷桃,公鸡啄米,武二郎打虎,司马光砸缸……二人招数变化无穷。眼下这个情形,我也不知道该帮谁,因为这两个人我都不太喜欢。住我隔壁的健身大哥总喜欢把垃圾堆在门外,搞得走廊里臭气熏天。而门卫小哥又是个势利眼,经常借着职务之便,吃拿卡要,占尽小便宜。二人从走廊一头打到另一头,均已经气喘吁吁。打得有些累了,门卫小哥便扶着墙休整。健身大哥趁其不备,一把夺过门卫小哥手上的警棍。目前,双方应该可以开始分胜负了。失去了武器的门卫小哥,免不了被一顿煎炒烹炸。不过,门卫小哥倒是挺识时务,他没有选择硬撑,而是撒腿就跑。健身大哥见状后,愣了片刻,而后冷笑了几声,飞奔追了出去。楼道里一片狼藉,散落了一地的垃圾发出阵阵酸臭味。看客们大都捂住口鼻,回身扣上房门,热闹暂时告一段落。我已无心游戏,选择躺在床上,静静聆听着屋外的声响。由于下午经历了一个长长的午睡,此时我巨有精神,迟迟唤不来困意。于是,我一边摆弄手机,一边等待健身大哥与门卫小哥的王者归来。王者没有等来,最终我见到了周公。凌晨两点多的时候,许久不联络的老潘突然给我打来了电话。自从我俩分道扬镳后,老潘这厮就深陷爱情的泥淖,不可自拔。久不碰面,我跟老潘的交流日益减少,最后趋近于零。当然,老潘也不是那种有了媳妇忘了爹的人。他偶尔也会在我朋友圈的状态下回复形如“大姚有空出来聚聚呀、大姚周末去后海喝酒呀、大姚撸串否......”起初我也是贱,竟以为老潘是真情实意,便借坡下驴,答复他:“那明天可好、周日怎样?”然后,老潘就会陷入长时间的沉默。隔了许久,他终于找寻到了拒绝我的说辞。什么家里养的猫要去做绝育、女朋友闺蜜来北京需要陪逛、公司部门要团建聚餐等等。三番五次鼻子碰灰,我总算是看清了老潘那虚情假意的嘴脸,也就不再自讨没趣。半夜三更,老潘找我,指定没什么好事儿。我睡眼朦胧,打开手机的扬声器,漫不经心道:“潘总,都你妈几点了?”老潘沉默片刻,而后语气凝重道:“手里有钱吗?”想到上周他刚在朋友圈晒了跟李亚男去日本京都游玩的照片,我猜测这厮一定是泡妞把钱给造没了。目前应该是到了山穷水尽,家里揭不开锅的境地。我挖苦道:“李亚男把你吃空了?你挣得可不比我少啊。”老潘叹了一口气:“哎,我爸住院了。”处于迷糊状态的我瞬间清醒了过来,我从床上坐起来,打开壁灯。我问老潘:“在哪儿?北京吗?”老潘的声音里夹杂着些许哭腔:“嗯,阜外医院。”我一边穿衣服,一边回话:“好,我马上就过去。”我从抽屉里找出信用卡,揣进兜里。入职朗云后,为了给王旭涨信用卡积分,在他的推荐下,我办了张招商银行信用卡。鉴于朗云员工的信誉比较好,信用卡的额度目前已经累积到了五万。(38) 养儿防老夜已经深了,楼道里一片寂静。我小心翼翼地锁上房门,蹑手蹑脚地走出公寓大门。健身大哥与保安小哥正坐在公寓门口的台阶上,一边喝酒一边聊天。二人手里还都夹着烟卷,吞云吐雾,互诉衷肠。保安小哥不停地揉搓着胳膊,胳膊周围泛着红色,想必是在先前的决斗中受了伤。健身大哥黑T恤衫的领子豁了个大口子,应该是保安小哥的杰作。讲道理,二人此时应该是剑拔弩张,互相捅刀,可呈现在我眼前的却是反常的和谐画面。缘何刚才还互骂祖宗,扬言弄死对方的两个人,突然间就握手言欢了呢?我满是狐疑。不过,当下我并没有太多功夫去深究,老潘那里急需我。我叫了辆出租车,很快就来到了阜外医院,在脑卒中重症监护室外见到了老潘。老潘比上次见面胖了许多,还留起了长发和山羊胡,一副浪荡公子哥的造型,跟富二代郝公子是一个套路。想必是受李亚男影响,没有人家富二代的命,却拼命扮演富二代,难不难受?别不别扭?老潘快步迎上来,我掏出信用卡递给了他:“卡上有五万的额度,你先拿去用,应应急。”老潘接过信用卡,双手合十:“真不想用你的钱,我这实在是没办法了。上个月为了给李亚男冲业绩,存款都买了她公司的理财产品。我爸这刚住院没多久,信用卡的额度就刷光了。”几个月前,李亚男跳槽去了一家新成立的P2P公司做理财顾问。为了帮李亚男拓展客户,老潘几次打电话给我,向我推荐李亚男公司的理财产品。对于新兴事物,我一向持谨慎态度,不会轻易尝试,便拒绝了他的好意,为此老潘还有点不太高兴。去年潘弟结婚买房,老潘补贴家里不少。年初跟李亚男结识后,二人一直过着奢靡生活,花销也是不菲。据我所知,老潘并没攒下多少积蓄。即便如此,为了给李亚男冲业绩,他还是把手头仅有的三万块钱投了进去。不知精明的老潘是被爱情冲昏了头脑,还是被理财产品的高收益迷住了心窍。我扫视周遭,并未见到李亚男,便随口问了一句:“李亚男没来呀?”刚才还一脸和气的老潘突然面露狰狞,攥紧拳头,咬牙切齿道:“我现在真想抽她。”老潘一向是宠妻狂魔,今天一反常态。我大吃一惊:“怎么?吵架了?”老潘咽了咽唾沫:“下午我爸被急救车送来北京,我给她打去电话,让她买点洗簌用品带过来。她说她正在跟一个很重要的大客户谈业务,实在走不开。这我他妈的都忍了。后来她忙完了那狗屁大客户,给我打来电话,第一句竟然是问我晚上吃什么?感情我爸这都住进重症监护室了,她竟一点儿都没放在心上。”说着说着,老潘啪啪甩了自己两嘴巴子,着实把我吓了一跳。想必也是因为潘父目前情况危急,他内心极度慌张,才会如此激动。我拉住老潘的手,说道:“我艹,你疯了。”老潘眼角泛着泪光,带着些许哭腔道:“我他妈真是眼瞎了,怎么找了这么个主儿。明天就分,不,他妈的现在就分。”老潘掏出手机给李亚男打了过去。对方却一直是关机状态,无法接通。“哥,咋啦?”身后传来一个男人的声音。我回过头去,一个染着黄毛的小伙从走廊的长椅上坐了起来。老潘白了黄毛一眼:“没咋地,咱爸都这样了,你还能睡着,我也真是佩服你。”黄毛走上前来,老潘指着他对我说:“这是我弟,潘伟虎。”我心说潘父给孩子起名也真是随意,要是老潘再有个三弟,大概率会叫潘伟豹。黄毛伸出手:“哥,麻烦您了。”我伸手过去,跟黄毛象征性地握了握。黄毛见老潘不愿搭理他,便很知趣道:“哥,你们聊,我下去抽根烟。”黄毛从兜里掏出烟盒,一边点烟一边往楼下走去。重症监护室里的护士时不时地从病房里走出来,询问老潘这个药用不用?那个药打不打?进口的还是国产的?老潘始终就是一句话:“紧着好的、能救命的用。”医生的每一次询问都是一笔不小的费用,我的信用卡很快就派上了用场。(39) 失了风度忙活了大半夜,等医生告知潘父已脱离生命危险时,晨雾升起,天已经大亮。期间,老潘多次劝我回去休息。晚上光顾着看保安小哥与健身大哥的热闹,本来睡得就晚。再加上三更半夜,老潘又把我从睡梦中叫醒,当下我已经困得睁不开眼。不过,瞧见潘弟那副不靠谱的样儿,我又觉得老潘一个人在医院肯定忙不过来,也就没走。在他乡,朋友即是兄弟,更何况我跟老潘有着曾同室而眠的交情。潘父从重症监护室转移到了普通病房,老潘那颗悬着的心终于放了下来,他执意让我走。我转身欲出病房,这时李亚男拎着一袋子水果迎面走了过来。咣当咣当,银色高跟鞋敲打着地板。我跟李亚男打了个照面,互相点了点头。彼此并不太熟,也就没继续寒暄。我望了眼老潘,只见他脸色突变,忽地凶神恶煞起来。一股寒气从身后袭来,周遭气氛有些不对劲,我便收住了脚步。老潘迎上前,一把抢过李亚男手上的水果袋,使劲往地上一摔。苹果、橙子在狭小的病房里,四下滚落。老潘努力压着怒火:“让你买的脸盆毛巾,牙缸牙刷呢?你拎一袋子水果来给谁吃?”老潘先是小声嘀咕而后声音越来越大,最后都快要蹦起来了。虽然老潘平日脾气有些暴躁,但我从未见过他对女人如此失态。我赶忙上前劝阻,免得扩大事态。可老潘却不依不饶,他硬拉着李亚男的胳膊往病床那里凑,边走边喊:“你过来,看看床上躺着的那个,嘴巴插着管子,你觉得他能吃吗?”潘父隔壁病床上住了一位半身不遂的老汉。想必是被吵闹声打扰到了休息,老汉不住地哼唧。老汉那虚弱状态就算心里有火也发不出来,不过他旁边的陪护大婶可一看就不是善茬。大婶紧盯着老潘,操着一口浓重的京腔:“喂喂,医院不是打架的地儿,要闹出去闹,别影响我们家老头子,他经不住。”老潘瞪着北京大妈,宛若一头看见了红布的斗牛。瞧他那架势想要把火撒到北京大妈身上。我赶忙上前拦住了他,把他推出了病房外。李亚男气得脸色苍白,蹲下身子,一一捡起散落四处的水果。随后跑出病房,走到楼道尽头,把水果一股脑地扔进了垃圾桶里。老潘站在楼道里,靠墙弓着腰,气喘吁吁。我的视线在老潘跟李亚男身上来回交换。李亚男扔完垃圾,从楼道尽头快步向老潘走去,手还攥着拳头。李亚男大有河东狮吼的架势,我挡住了李亚男,规劝她别跟老潘一般见识,先回家,回头我让老潘一定负荆请罪。李亚男长舒一口气,最终听从了我的建议,转身欲走。忽地,老潘快跑两步,挡住了李亚男的去路,而后一把拉住她,双手用力将她摁在了墙上。老潘恶狠狠道:“把我在你们公司存的理财钱赶紧给我取出来,我这着急用。”李亚男费尽力气,企图挣脱开束缚,却也徒然,便摆出一副要杀要剐随你便的姿态,还用言语刺激老潘道:“当初是签了合同的,三年的定期,你要是有本事就自己去要。”老潘气的胸脯上下颤抖,骂道:“cnm,那钱要拿来救命的。”李亚男眼泪瞬间决堤般涌出,很快就哭花了妆容,可她并未屈服,语气更加强硬道:“潘伟龙,你再不松手,我就报警了。”楼道里陆续有人上前围观,大家对老潘指指点点。几个上了年纪的老太太开始劝说老潘,几个富有正义感的中年男子准备出手搭救李亚男。我上前把老潘拉开,劝慰他钱的事儿日后再说,当下是好好照料他爸。在众人不断地施压下,老潘最终松开了手,怒气无处安放,便都聚集到了脸上,令人不寒而栗。李亚男活动了下手腕,一边擦拭眼泪,一边展平褶皱的衬衣。老潘扭过头去,摆出一副老子多看你一眼老子死全家的神态,却又忍不住用余光扫视身后这位泪人。僵持片刻后,李亚男踩着高跟鞋,头也不回地朝着楼梯口跑去,而后光速般地消失在了我的视线里。看热闹的人都散了,老潘点了一支烟,刚送到嘴边,就被值班护士给抢了过去。护士指着公共场所禁止吸烟的牌子,把老潘好生数落了一顿。老潘欲哭无泪。我陪着老潘在楼道里静默了十多分钟,他的情绪这才有所好转。安抚好老潘后,我困得天昏地暗,实在扛不住了,起身回家。刚走到楼梯口,潘弟拎着两个煎饼果子从楼下晃晃悠悠地走了上来,嘴角还残留着一些豆腐脑的卤子,看来是刚刚饱餐了一顿老北京早点。潘弟一边比划一边说:“大门口有个医闹跟保安打了起来,脑袋都出血了,警察都来了......”老潘抢过潘弟手中的煎饼,塞给了我一个:“大姚,先吃个煎饼垫垫肚子,我爸这算是稳住了,今天真是多亏你了。”我拍了拍老潘肩膀,安慰说:“都会好起来的。”老潘一脸真诚:“大恩不言谢,那钱我尽快还你。”我摆手道:“不急,你先过了眼下这关再说吧。”我再次挥手,转身走到楼梯口时,听到身后传来潘弟的声音。他正向老潘询问附近哪里有网吧。我不禁叹了口气,开始心疼起老潘来。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
7 阅读
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日
6 阅读
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日
5 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-14 钱迷心窍
(30) 上班摸鱼周一,我重新踏上辛苦劳作的征程。早高峰的地铁,乌压压满是人。地铁进站了,又是一场没有硝烟的战争。人挤人,人推人,人骂人,大家争先恐后,寸步不让。车门大开,身后的壮汉硬生生地把我挤进了地铁。刚参加工作那会儿,面对这种场面,我还会横眉冷对,现在却是完全麻木。我靠着屁股大的优势在车厢门口处开辟了一块不小的空间,而后点亮手机,在屏幕上划划点点,打发短暂却烦闷的路上时光。周遭的过客莫不是如此,无论自己占据的位置多么逼仄,总会有一方空间留给手机。21世纪,大千世界被浓缩在巴掌大的方寸之间。旁边一位正看综艺视频的小哥,为了不发出笑声,强忍着愣是把脸憋得通红。而我,为了不让体内一股胀气喷薄而出,进而引来周围人侧目,强撑着将其逼退回了肠道。等待着,放空着,游离着。终于列车抵达西二旗,喧嚣如约而至。我从西二旗地铁出来,坐上了前往中关村软件园的摆渡车。约莫十分钟,便来到了朗云大厦楼下。今日,大厦门口多了两盆巨大的招财树,枝繁叶茂,一人多高。寓意朗云在互联网领域里蒸蒸日上。矗立于门口的保安小哥还如往常那般颔首微笑,十分友善。乘电梯,过走廊,我快步走进办公区。四下扫视,这才发现工位好似换了人间。原先办公桌上那些蔫了的绿植全都被替换,从吊兰变成了绿箩。整个屋子宛若一片丛林,满目皆是绿油油。成年后,绿色被赋予了新的含义,不总是令人喜悦。不过,眼前这抹绿着实让人舒适无比。几位保洁阿姨穿梭于工位之间,认真地打扫着卫生。隔壁组有几个早到的同事,正围坐在一起闲聊,声音忽大忽小,不时还爆出狼嚎般的狂笑,有些令人讨厌。一如往常,我坐在工位上先发呆了几分钟,待到心绪平稳下来后,打开了电脑,登上聊天工具,办公系统。也不知是哪一次陪老娘看养生节目,把养生专家那清晨畅饮一杯水的建议记在了心里。在开启一天忙碌工作之前,我会先去躺茶水间,喝几杯温水。如果正赶上尿急屎紧,则会先跑一趟乃至几趟厕所。三分开水,七分冷水,倒入杯中,缓慢摇晃杯体数下,待其冷热混合均匀后,手高举,头微仰,二三百毫升咕咚下肚。爽到喉咙深处后,会不由自主地打个嗝。如果身旁无人,这个隔会拉个长音,直到胸腔共鸣消失殆尽。接下来,抚摸肚腩几下,将空杯子重新放回饮水机处,打开热水阀,把水杯重新灌满,保持步伐匀称,慢悠悠地走回工位。将水杯敞口,放在书桌一隅,等待沸水慢慢变成凉白开。在此期间,可以多次尝试轻抿杯中水面,如果温度适宜,则可多饮几口,如果烫嘴,则再放数分钟。对于程序员来说,上午绝对不是一个容易迸发灵感的时间段,所以不要惋惜一寸光阴一寸金,寸金难买寸光阴。该颓颓,该歇歇,因为整个下午乃至晚上,我们都会有大把辛劳的时间。为了打发无聊的上午时光,可以选择在网上冲浪。在浏览器里开几个新闻网站,大致了解了当下新闻热点,社会动态,免得吃饭时和同事之间闲聊没有谈资,不知对方所云。热门新闻总是有限,随后可以再去几个知名的程序开发者社区观摩一番。把业界又开源了哪些项目,各大网站又爆出了哪些漏洞,明星创业公司又融了多少钱,统统装进脑子里。程序员就应该时刻保持与时俱进,这样才能做到不会被时代的轮子所碾压。倘若如此操作,上午很快就会过去。王旭喊我去吃午饭的时候,我正在公司内部系统里浏览上个月的工资明细。幸好我眼疾手快,在察觉有人伫立身后时,立马叉掉了浏览器,差点就暴露了自己的薪水状况。薪资泄密这事儿在绝大多数互联网公司里都是高压线,谁都不能触碰,更不能讨论。不患寡而患不均。在大多数互联网企业里,老员工不得不接受一个现实,那就是工资时不时就会被新人所倒挂。所谓工资倒挂是指为公司工作多年的老员工,其薪水比不上刚入职的新员工。当然当初老员工入职的时候也曾倒挂过比他更老的员工。所谓往复循环,后浪总把前浪掀翻。之所以出现这种并非为公司贡献越久回报越多的现象是源于互联网这个行业尚处于高速增长期,人才缺口很大,招聘的成本水涨船高。为了吸引更多更好的人进来,各大公司不得不逐年抬高各级别岗位的起薪,已期在招聘市场上不被其他家公司所碾压。然而公司内部的调薪却很是缓慢,甚至很多公司入职即巅峰。几年下来,老员工的薪资甚至会低于没有工作经验的应届生。同工不同酬,为了不引发矛盾,进而稳住老员工。在我入职的第一天,公司的人力就告诫我薪资待遇一定要保密。(31) 钱迷心窍我登录邮箱,刷新邮件列表,几十封未读邮件。依次点开,都是一些同事休假,公司内部活动等无关紧要的事情。对此,我无多大兴致,直到瞧见了一封部门内部人事调整的公示邮件。李波终于如愿地成功上位,由高级专家荣升部门技术总监。康神接替波哥成为了架构组的新组长。我又看了看组内其他老员工的职级变化,大部分人都得到了晋升。王旭的职级如今已经比我高了两个等级。我刚来还不满半年,没有资格进行述职晋升。不过职级低点倒也无大碍,只要钱给到位就行。虽然公司有着严格的薪资保密协议,但在多次闲谈试探中,我也大概知晓了王旭目前的工资水平,应该是与我持平。一般来说,程序员这个行业,涨薪最行之有效捷径就是跳槽。我比王旭入职朗云晚,职级比他低,但薪资却比他高,这就是所谓的倒挂。不过,由于王旭有公司奖励的股票,如果算上这笔收入话,一年下来他的收入还是比我高不少。我一个月挣5000的时候,畅想要是能挣到一万,那该多好,生活过得绝对潇洒。如今,挣到一万了,又想着倘若拿到公司股票,待遇追上王旭,那该是一番怎样的光景。钱这个东西,应该是没有人嫌拿的多;工资这件事,几乎每个人都觉得自己挣得少。一些花钱大手大脚的人形容自己的生活状态是:月初,他吃什么,狗吃什么,月末,狗吃什么,他吃什么。不过对于我这种除去房租,再无其他大花销的人来说,月初月末其实对我都一样。当然,在老潘搬走后,我的日常支出发生了些许变化。单说房租就由原来的500涨到了1500。忽然多出来的这1000,一半是原来老潘应该交的那部分,一半是房东老太坐地起价上涨的租金。房东老太在得知老潘搬走后,极力劝说我去租幸福公寓顶层的小阁楼。顶层阁楼倒是便宜,月租只需800大洋,不过面积特别小,夏天热,冬天冷。房东三番五次游说我,还许诺了不少好处,比如网费减半,不收水费。我并不为所动,因为她这般热心肠并非是出于对我的关照,她心里有一套自己的小九九。由于近期政府大力推进棚户区危楼改造,公寓周遭一些年久失修,有安全隐患的房子被勒令整修。棚户区里一些老租户不得不重新找寻靠谱的房源。年前,为了孙子上学,房东老太举家搬去了东城区。老太雇了个看大门的保安,是她一个远方亲戚,高中辍学生。保安小哥住在公寓的门房,隔三差五就有人来敲他房门,寻租者络绎不绝。可,当下幸福公寓已经没有剩余的空房子。对于这种供不应求,能够坐地起价的大好时机,房东老太自然是不会错过。首先,她大幅度提高了房租,淘汰了一批没有支付能力的老租户。其次,她左腾右挪,最终在公寓顶层又整理出来了几个原本用于放置杂物的小阁楼。小情侣,小夫妻们肯定不会去住那五六平米的小阁楼,里面根本就塞不下两个人。于是,房东老太就打起了单身汉--我的主意。不过,我并没有就范,虽满是不爽,却还是答应了她的涨租要求。如果此时有记者采访我:你认为金钱能买来快乐吗?我肯定回答---能。至少在瞅见那五位数工资的时刻,我是快乐的。不过,转而一想,单单房租一项就要花掉其中不小的一部分后,内心又不免悲伤起来。独在异乡为异客,每涨房租倍思乡。家有良田数十亩,百平庭院炊烟升。若是来世走人间,但愿无德又无才。躬耕乡田过此生,不问前程与功名。点击进入下一章阅读点击从第一章开始阅读ps:欢迎各位关注我,文章更新的消息会在「掘金动态」里滚动,同时七筒也欢迎大家在动态的评论区给我评论。此致敬礼,感谢各位厚爱。
2023年03月24日
4 阅读
0 评论
0 点赞
2023-03-24
写给前端的区块链开发入门指南:零基础开发基于以太坊智能合约的 ICO DApp
张泉灵说,时代抛弃我们的时候连声再见都不会说,马云说对于新兴事物,绝大多数人是看不见、看不起、看不懂、来不及。自从学完 Coursera 上的 Crypto Currency 课程,搞懂区块链技术的本质后,对区块链的的所谓信仰变成了强有力的逻辑支撑,不管你看没看见,区块链正在吞噬整个世界!不甘平庸的工程师肯定会问,怎么在区块链技术和行业崛起的时候参与进去获取更大的成长?如果你选择参与,而不是旁观,真诚的邀请你在成为区块链应用研发工程师的路上和我同行。前端工程师学习区块链应用开发的 WHY、HOW、WHAT 可以用下图来概括,如果你同意我的观点,还犹豫什么?赶紧动手吧!为什么要选择区块链开发?未来已来,只是尚未流行!区块链技术的爆炸式发展引起了很多人的注意,相信看到这篇小册的你早就听说过比特币、ICO,甚至购买过区块链资产。区块链是个天然和钱离得很近的领域,离钱越近就越容易赚到钱,尽早开始准备并在区块链领域站稳脚跟的人将能享受到行业崛起的巨大红利,就像四年前的微信公众号,两年前的知识付费,一年前的微信小程序。然而,从对身边同学的观察来看,前端工程师很容易产生区块链是底层技术、离前端很远的错觉。实际上任何区块链应用落地都需要以为用户创造实实在在的价值为基础,区块链应用的用户不会仅限于少数极客,有普通用户就需要界面,有界面就需要前端工程师。区块链可以简单理解为分布式的、公开的、不可篡改的数据库,区块链应用在项目架构、前后端交互方式等方面和传统的端应用会有比较大的差别。从技术栈的视角来看,构建在分布式网络、公开账本、共识算法等三个核心要素之上的智能合约和 DApp 才是未来百花齐放的地方,底层协议会逐渐趋于稳定。那么,作为前端工程师,我们在区块链领域的机会到底在哪里?炒币?貌似不是长久之计。如果说做成任何事情都需要依赖技能和和运气两个要素,不同的事情只是两种要素的比重不同,那么理智的人会想尽办法让事情更依赖技能,而不是运气。为什么要选以太坊?以太坊(Ethereum)是目前最成熟的、最被广泛使用的、支持构建和部署基于智能合约的 DApp 的区块链应用平台,根据 State of DApps 的统计,目前运行在以太坊上的应用多达 1379 个,这些 DApp 全部由两部分组成:存储在以太坊网络上的智能合约(使用 Solidity 编写,和 JS 很类似,未来 EOS 也会支持使用 Solidity 编写智能合约),以及能和智能合约交互的用 Web 技术开发的 DApp。围绕以太坊的 DApp 开发生态是目前相对最成熟的,比如有开发框架 Truffle,有智能合约在线集成开发环境 Remix,还有专设的 StackExchange 开发者问答频道。别跑题了!怎么学习区块链开发?Blockchain is hard,虽然我们不愿承认,但事实摆在面前。围绕以太坊有大量的开发工具可以使用,但是它们的演化和迭代却非常快,很多工具、框架、库的教程可能过两周就就过时了,或者接口不再兼容了,这成了很多新同学入门区块链开发时最大的障碍,在坑里趟了半年的我写了个比较详细完整的教程(广告来了,其实就是掘金小册),姑且称之为:前端工程师写给前端工程师的区块链开发入门指南。学会某个新技术的最佳路径是先掌握最小可用知识(Minimum Actionable Knowledge),然后撸起袖子开始做,在做的过程中不断优化和迭代自己对新技术的理解和掌握。在这本小册里我会把最近半年摸索出来的以太坊智能合约、DApp 开发套路、最佳实践悉数分享给你,无需花费大量的时间去做诸如启动本地测试网络、编译和运行全节点之类的事情,在只依赖核心工具如 solc、Chrome 的情况下,用由浅入深的方式手把手带你熟悉 Solidity 智能合约开发、测试、部署,搭建和智能合约交互的 DApp 开发框架,为成为区块链工程师做好准备。文不如表,表不如图,在小册中使用了大量的图片(目前完成度 35%,插图 55副)和类比,即使你完全没接触过区块链,也能轻松理解区块链世界里面的关键概念。小册的内容划分为 5 大部分:入门篇(上):理解区块链原理与以太坊的运行机制,熟悉以太坊开发的基本概念,如账户、交易等; 入门篇(下):Solidity 开发入门,基于 Remix 的智能合约工作流; 进阶篇:基于现代前端环境的智能合约开发、构建、部署、测试工作流; 实战篇(上):设计、开发、部署、测试 ICO 智能合约; 实战篇(下):使用 web3、next.js 开发能和智能合约交互的ICO DApp; 我是谁?做过什么?我有过什么作品?掘金专栏作者:王仕军,11250 人关注; 掘金小册作者:《使用 npm script 构建超溜的前端工作流》,787 人购买; 微信公众号前端周刊创办和维护者,2600 订阅; 高质量技术视频教程作者:async/await、styled-components,网盘下载量近 3000 次。 有谁审阅过小册?他们怎么说?你会得到什么?在小册中,你将学会在自己熟悉的前端开发环境中组合使用 Ethereum、Solidity、JavaScript 编写、调试、测试、部署和管理自己的 DApp 的基本方法。具体包括:理解在以太坊上构建 DApp 需要掌握的关键概念,比如 Gas、Transaction; 熟悉以太坊不同测试网络,以及测试网络提供工具的使用方法; 熟悉 Solidity 语言,并用其开发真实的智能合约; 熟悉以太坊智能合约调试工具 Remix 的基本用法; 掌握设计、开发、测试、部署智能合约的工作流和最佳实践; 熟悉以太坊智能合约工具库 web3 最新版的基本使用方法; 熟悉 web3 和 next.js 结合使用的方方面面; 构建并掌握完整的、能被重用的智能合约、DApp 应用架构和构建工具链条; 适合什么群体?具备基本的 JavaScript 知识,最好是写过 Web 应用,熟悉 npm 使用的同学; 对区块链、以太坊、智能合约技术感兴趣,想做深入了解的前端同学; 期望使用区块链技术开发能实际落地的应用的前端同学; 期望储备区块链开发技能,为跨界区块链做好准备的前端同学; 期望从事区块链行业的计算机相关专业学生; 想抓取区块链行业红利,靠技能赚更多钱的同学; 你要准备什么?Chrome 浏览器,部分开发和调试功能是在浏览器中进行的; Node.js 运行环境,最好是 v8.x 以上版本,建议使用 nvm 来安装; 可以用来输入和执行命令的终端程序,比如 Mac 下的 iTerm,或者 Windows 下的 cmder; 你自己用起来舒服的编辑器,比如 VSCode,我写过两篇 VSCode 编辑器配置的文章,参见上和中; 2 小时的闲暇时间,读完这本小册,并能自己上手实践,因为纸上得来终觉浅; 读者福利免费加入读者交流群,和群友讨论和交流读书心得和疑惑问题,我相信,这本小册能让很多和你我志同道合的同学聚在一起; 读者群内 5月31日 前每天会有抽奖活动,奖品为有真实价值的区块链代币(抽奖使用微信小程序,发奖过程公开透明): 05 月 18 日 ~ 05 月 22 日,每天的奖品是价值 1 枚 EOS or 等值的 ETH ,据说握住会价值不菲; 05 月 23 日 ~ 05 月 31 日,每天的奖品是 1000 枚 * (2 份)Candy,李笑来操刀运作的糖果代币,拿三年试试? 凡在限时优惠期间购买本小册的读者,都会获赠专属 5 折折扣券,可用于购买廖雪峰老师的《数字货币与区块链原理》小册,更系统全面的理解和掌握区块链开发必备知识。 希望在成为区块链工程师的路上,你能与我同行!猛击下图享受七折限时优惠。或者直接点击这个链接:juejin.cn/book/684473…
2023年03月24日
7 阅读
0 评论
0 点赞
2023-03-24
区块链到底是个什么鬼?一幅漫画让你秒懂!
最近ICO很火,带来了非常多人关注这块。很多人都会问,区块链到底是什么?但说到区块链,网上各种各样的资料满天飞,看完之后,感觉懂了,又感觉完全没懂。一句话概括,如果互联网技术解决的是通讯问题的话,区块链技术解决的是信任问题。妈:“小明啊,什么是区块链?” 我:“(惊!)......妈,你从哪里听来的区块链。” 妈:“隔壁你蔡姨说他老公在炒什么币,老是喊着区块链balabala,楼上李大哥也喊着区块链创业balabalabala,区块链能卖钱吗?” 我:“妈,区块链很复杂,我下次再解释......” 妈:“你晚饭想吃开水拌面?” 我:“好吧 Σ(っ °Д °;)っ 我想想怎么说。”这么火的区块链,到底是什么呢?区块链到底是个什么鬼?一幅漫画让你秒懂 区块链技术是指一种全民参与记账的方式。所有的系统背后都有一个数据库,你可以把数据库看成是就是一个大账本。目前是各自记各自的账。 由于没有中心化的中介机构存在,让所有的东西都通过预先设定的程序自动运行,不仅能够大大降低成本,也能提高效率。而由于每个人都有相同的账本,能确保账本记录过程是公开透明的。 区块链技术是比特币的底层技术,比特币在没有任何中心化机构运营和管理的情况下,多年运行非常稳定,没有出现过任何问题,所以有人注意到了它的底层技术,把比特币技术抽象提取出来,称之为区块链技术,或者分布式账本技术。 根据西班牙最大银行桑坦德发布的一份报告显示,2020年左右如果全世界的银行内部都使用区块链技术的话,大概每年能省下200亿美元的成本。这样的数据足以说明“区块链”给传统金融领域带来的巨大变革和突破。 云计算通常定义为通过互联网来提供动态易扩展且经常是虚拟化的资源,但是提供云计算平台的往往是一个中心化机构。而区块链组成的网络一般是没有特定的机构,所以区块链更接近分布式计算系统的定义,属于分布式计算的一种。 Q币是一种中心化的电子货币,包括总量,发行方式都是由腾讯公司控制的。而比特币的总量,发行方式都是由程序和加密算法预先设定后,在全世界的多个节点上运行,没有任何人和机构可以修改,不受任何单一人或者机构来控制。一般称Q币为电子货币,或者企业代币。称比特币为数字货币或者加密数字货币。 如果说比特币是对传统货币的一种颠覆,那么比特币的基础技术——区块链则是对传统编程范式的一种颠覆。区块链技术被看作是一次Paradigm Shift。作为一个程序员在理解这些技术上有一点点优势,但也仅限于一点,因为对于任何一个新概念来说,要理解透它都是非常痛苦的(比如椭圆曲线加密算法,梅克尔树,不是每个程序员都知道这些)。根据我的经验,在学一个东西刚开始的时候,没有捷径,就是扎进去,一点点的磨着看,遇到不懂的就查资料。对应到区块链,就是看白皮书,我看以太坊白皮书,断断续续自己翻译,做笔记,看了差不多一个月,看完之后很多细节没懂。但却对区块链大概做了什么,解决问题的一些思想,概念有了全面的认识。有了思想的储备的好处是,看其它的东西就轻松了,因为大家解决同样问题的框架是类似的总结即使你不想进入全新的区块链应用开发大潮之中,你也会发现区块链相关的底层技术对平日的应用开发有不少启发和借鉴作用。一个新技术的诞生是有它顺应时代的合理性的(黑格尔语”存在就是合理的“)。作为程序员我们应该去了解它的合理性所在之处,取而用之。我们不一定非要用新技术去颠覆一个老应用,但可以用新技术去重塑一个老应用。更多阅读[屏幕适配之尺寸的相关概论《一》 ](http://mp.weixin.qq.com/s?__biz=MzI3OTU0MzI4MQ==&mid=2247485137&idx=1&sn=970c4aa3251853064406ed6c1cac1ed6&chksm=eb476a4fdc30e359331f414f5312a96e0cfabaf630922d0c59ffa3a8499e4aa68d5e44c07854&scene=21#wechat_redirect)什么是dp,dip,sp和px及他们之间的的关系?《二》破解Android版微信跳一跳,一招教你挑战高分记一次阿里面试经历|Java面试知识整理相信自己,没有做不到的,只有想不到的微信公众号:终端研发部
2023年03月24日
3 阅读
0 评论
0 点赞
2023-03-24
程序猿生存指南-25 逃离帝都
(54) 逃离帝都下定决心离开帝都这事儿,老潘可能思索了数个深夜,而告知我却只用了一通几分钟的电话。老潘有一个我不能及的优点,那便是做事果断,从不拖泥带水。决意要走,他便立即向公司提出了离职。老潘花了一周的时间将手上的工作交接完毕,随后开始着手搬家事宜。黄飞为了一台二手XBOX,前来帮老潘打包行李。而我不完全是为了蹭老潘允诺的那顿海底捞火锅。更多是缘于近两年的友谊。友谊它就像磷火,深处黑暗之中才显得光亮。老潘这三十平米的一居室被家具塞得满满当当。梳妆台,跑步机,微波炉,锅碗瓢盆,柴米油盐酱醋茶一应俱全。以我对老潘的了解,倘若他一直是孑然一身,这些东西断不会出现在他的屋中。看得出来,他与李亚男曾度过了一段快乐的同居生活。而今,劳燕分飞,佳人成仇人,不禁令人唏嘘。收拾行李过程中,老潘翻到了几件李亚男遗落的衣服。睹物思人,他便气不打一出来,对着衣服是一顿猛踩,而后一股脑地将其扔进了垃圾堆中。我们额头冒汗,手忙脚乱。老潘家那只英短蓝猫也没闲着。它在屋子里上蹿下跳,一会攀爬窗帘,一会儿撕扯床单,相当调皮。玩累了,它便匍匐一隅,宛若一位监工,凝视着我们。黄飞蹲下身子,用衣架逗它玩,问道:“潘哥,这猫你怎么处理?带去杭州吗?”老潘一边往快递箱中扔东西一边搭话:“李亚男那贱人想要,我没给她。我挂在二手宠物市场了。”黄飞将蓝猫抱在怀中,蓝猫蜷缩在他的臂弯里,用爪子玩弄着他的帽衫绳。瞧黄飞如此喜爱小动物,我便顺水推舟,对老潘说:“送给黄飞吧,我看他喜欢的不行。”老潘提前打预防针道:“原来李亚男一直给它吃鱼罐头,把这家伙的嘴巴喂刁了,养它可花不少钱呢。”黄飞把蓝猫放到地上,满不在乎道:“一只猫还能把我吃穷了?饿上它几顿,它就嘛也吃了。”老潘目送蓝猫跑去阳台,微微摇头说:“你要是喜欢就抱走吧。阳台那猫笼,猫砂还有几盒罐头,你都拎走,我也眼不见心不烦。”老潘说去杭州后,他要从头来过。于是,他把所有能卖的都卖了,能扔的都扔了,能送的也都送了。楼下收废品的老大爷得到了一三轮车的破烂。黄飞得到了一只猫和一台XBOX游戏机,而我得到了一台微波炉。老潘兑现了承诺,我跟黄飞狠宰了他一顿海底捞火锅。胡吃海喝过后,我跟黄飞带着战利品踏上了返回幸福公寓的路途。地铁上不允许携带宠物,我拎着微波炉,黄飞抱着猫笼,挤上了一辆公交车。蓝猫的哀叫声成功引起了车上乘客的关注。他们询问黄飞关于猫的价钱,年岁,品种等问题。对于这些问题,黄飞并不知晓,只能乱答一气。终于赶回了幸福公寓,黄飞把猫笼放在了离暖气最近的地方,生怕冻坏了他的新玩伴。新主人给这个新玩伴起了个新名字---盖伦,《英雄联盟》中一个游戏角色的名字。盖伦的住所是一栋两层别墅,下面是厕所,上面是卧室,空中还有一个吊床。四周通透,独门独院,极尽奢华。新到一个环境,盖伦还不太适应。任凭黄飞跪在地上如何好言相求,它就是躲在床底下,不愿出来。实在是逗累了,黄飞便不再白费力气,打开电脑,玩起了游戏。瞧黄飞那一脸没耐心的样儿,我觉得过不几天,他就会厌烦。他应该还不知道猫可是天底下最傲娇的动物。不幸被我言中,没过三天,黄飞就把盖伦抱到了我屋中。他实在是受不了盖伦的那恶臭的猫屎和暴躁的脾气。他一玩游戏,它就跳上键盘。他把它关进笼中,它就嚎叫不止。盖伦严重影响了黄飞的日常休息与娱乐游戏,他无计可施,又不忍心放它流浪,再三恳求我代为收留。盖伦被抱来的时候,眼角还挂着泪痕。想必是把黄飞逼急了,挨了一顿打。瞧它那楚楚可怜的样子,我实在于心不忍,便把它留了下来,成为它第三个主人。此后众多深夜伏案的日子里,盖伦都陪伴在我身边。或安静于一隅,或嚎叫求关注。它依旧傲娇,依旧挑食,依旧调皮,依旧无情,却给我带来了巨大的乐趣。(55) 奔赴杭州老潘南下杭州,倒也不是赤手空拳,毫无准备。他有一个大学同学在杭州阿里巴巴总部上班,已经帮他内推了几个部门。老潘有电商相关的职业背景,本身能力又很强,再加上杭州那边急缺人,应聘阿里很顺利。告别需要仪式,老潘把入职时间往后推迟了一周。他说他要重新游览一番帝都的美景,吃一遍帝都的美食,最后拥抱一下这座曾承载了他众多梦想的城市。其实我知道,他要告别的不是一座城而是曾经的自己。感恩节那天,老潘启程前往杭州,开始了他的杭漂生涯。清晨,我去老潘住处帮他搬运行李,送他去火车站。途中,路过一家7-11便利店,老潘进去买了两杯热豆浆和四个包子。从便利店出来,老潘一脸娇羞地问我:“你看收银台那妹子漂亮不?”为了瞻仰老潘口中的妹子,我踏入便利店买了瓶矿泉水。结账时,我特地留心偷瞄了几眼收银员。妹子高高的个子,甜美的笑容,有点儿郭碧婷的感觉。我从便利店出来,老潘不打自招:“每天上下班路过这里,我几乎都会注意到她。曾无数次闭目畅想,哪天买早餐,一定要向她索取联系方式,勾搭一番。”老潘的渣男行径让我对李亚男的厌恶感减弱了不少,鄙夷道:“本以为李亚男够渣,原来你也不是什么好鸟。”老潘白了我一眼,反问:“我要是够渣,还能被那贱人给踹了?”步履匆匆,我们已经走出了很远的距离,老潘仍恋恋不舍地回头张望。有贼心没贼胆,此后他与那小妹应该是很难再见了。一个怀春少年的春梦就此中断,不禁令人扼腕。挤进地铁,老潘在售票处驻足了片刻。我顺着他的视线仔细瞅了半晌,并未发现漂亮姑娘,也不知他是何用意。老潘悄声对我说:“看见那个四眼大高个了吗?”大高个足足有一米九,带着一副黑框眼镜,靠墙伫立,宛如一根电线杆。人群中很醒目,我一眼就定位到了。只不过对方是个胡子拉碴的大老爷们。我不禁大呼:“怎么?你俩还有故事?”“几个月前,我俩曾打过一架。”“嗷嗷,吓我一跳。”我为刚才脑袋中闪过的一丝不符合主流价值观的念想深感抱歉。“那天我给公交卡充值,他不小心把我公交卡扔到了地上,不但不道歉还骂我傻逼,把我气得不行。小爷我可不是吃亏的主儿,我立马从包里拿出一杯水,顺着窗口就泼了进去。那小子气冲冲地跑出来跟我打了一架。”“战况如何?”“互有损伤,我稍微占了点便宜。后来跟那小子又照面过几次,他假装不认识我,我也没再找麻烦。这种人一看就是那种欺软怕硬的贱骨头。”地铁上,老潘成了话痨,一直说个不停。在帝都的近六个春秋,他经历了太多难忘的事。一座千万人口的大都市,少了老潘就像是沙漠中少了一粒沙子,并不会有多少人在意。也许是怕被人遗忘,也许是离别前感触颇多,老潘选择把那些事儿讲给我这粒沙子听。12年大三实习那会儿,有一天他加班到午夜。他走出公司,发现身上没带一分钱,手机也没有了电。再回到公司,公司大门已经被锁。万般无奈,他一个人花了三个多小时从荒凉的西二旗走回邮大。一路上,有烂尾楼,有废弃工厂,有小树林,有立交桥,他靠唱歌给自己壮胆。14年刚跟李亚男在一起的时候,他俩去泰国游玩,夜游曼谷迷了路,老潘靠蹩脚的英文,边比划边猜,最后被人带进了一个人妖表演会所,花了近一千泰铢,李亚男骂了他一路的变态。他爸刚住院那会儿,他急缺钱,于是疯狂地接外包。小到学生作业,大到公司项目。基本是是来者不拒,他曾用两个通宵赚了一万人民币。李亚男跟他分手,不完全是因为他在医院把她给骂了一顿。李亚男说跟他在一起,她看不到未来。那个花臂男张旭是北京胡同土著,住在南城,家里有一个小院子等待拆迁,想必是能给李亚男一个光明的未来。……北京南站的候车厅里,人山人海。北京的火车站,无论春夏秋冬,满是漂泊的人。南下北上,东出西进,不甘平庸的人注定要为自己的宏愿奔波。距开往杭州的G33次高铁发车还有半个小时,我跟老潘立在检票口,等待着工作人员检票进站。我找话说:“前几天听新闻上说,杭州那边最近又出台了许多吸引人才的新政策。落户,购房,孩子上学什么的都特方便。”老潘叹了口气:“哎,也不知人家看重的是你的才能还是你的钱包。随着一大批高学历人涌入杭州,他们择业购房,当前杭州的房价也不低了。”我劝慰道:“如果不适应那里就回来,咱一技在手,到哪里也饿不死。”老潘点头如捣蒜。身后陆续有人起身前来排队,周围喧闹起来。扬声器里传来G33次列车开始检票进站的广播。此去经年,再次见面不知何时何处,得抓紧利用剩余时间,好好道个别。我与老潘相拥:“在杭州好好混,苟富贵,勿相忘。”“大姚,我做了逃兵,希望你能在这里扎根。早日找一个贤惠的媳妇,买一栋舒适的房子,过上好日子。”“嗯。”我有些哽咽。“有空来杭州玩,哥定会好酒好菜招待你,一定要带着妹子来,你要是一个人来,恕不接待。”我点头,泪水不受控制地在眼眶里打转。年纪大了,不忍别离。老潘面露笑意,挥手与我作别,而后迅速消失在拥挤的人流中。我不由自主地回想起了与老潘初次见面的场景。那时我们比现在更年轻,比现在更有朝气,比现在更无所畏惧。在返程地铁上,我收到了老潘发来车已启动的消息。打开微信,看到了他在朋友圈发的那条「我爱你北京,再见北京!」的状态。再见,老潘。点击进入下一章阅读点击从第一章开始阅读
2023年03月24日
5 阅读
0 评论
0 点赞
2023-03-24
一大波 Android 刘海屏来袭,全网\Maybe/最全适配技巧!
一、序Hi,大家好,我是承香墨影!Apple 一直在引领设计的潮流,自从 iPhone X 发布之后,"刘海屏" 就一直存在争议。不过不管你怎样,Android 也要跻入 "刘海屏" 的行列,尤其是 Android P 发布之后,也从系统级支持顶部凹槽屏幕设计。很多厂商也在逐渐推出 “刘海屏” 设计的手机,在国内比较常见的就是 OPPO R15 和 华为 P20。屏幕不一样了,迎来的就是一些适配上的问题。今天就来聊聊,Android 的 “刘海屏”,以及我们如何去适配它。二、刘海屏的背景介绍2.1 背景介绍刘海屏的外观,我想大家应该都有概念,不过不同厂商刘海屏的实现方式也有所不太,这一点需要先有个概念。就现在市场上的情况来说,会区分成两类,一类是标准的 Android P Api,另外一类就是厂商在 Android P 以下的系统,做的特殊适配。例如:华为 P20 就是采用的 Android P 标准 Api 的方式,而 OPPO R15 就不一样了,它有自己的适配 Api。2.2 那些需要单独适配就算是增加了刘海屏,你也可以发现,大部分都是“切割”的状态栏的区域,所以就面临了三种情况。有状态栏的页面,不会收到刘海屏的影响。 全屏未适配刘海屏的页面,系统会对刘海屏区域进行切割,让整体 UI 页面做下移处理,避开刘海屏的显示。 全屏已适配刘海屏的页面,可以兼容刘海屏,做到真正的全屏显示。 后面会单独讲解这几种方式的区别。2.3 抢先体验 Android P在手边没有对应系统的设备的时候,模拟器是一条不错的路,最近 Google 也发布了 Android P 的模拟器,还有一个办法就是找一些支持真机云测的平台,租用一台需要的远程设备,也是一个解决方案。我这里选择 Android P 的模拟器,有需要自己更新 SDK ,无脑下载更新就好。刘海的凹槽区域,大部分是为了给摄像头或者其他传感器留出区域。而在没有刘海的设备或者模拟器上,可以通过开发者选项里的 “Simulate a display with a cutout”,开启刘海屏的支持。如果你把所有的模式都试过一遍,你会发现,其实刘海屏的刘海,在 Android P 上,是有多种样式的,并非统一的。2.4 刘海屏的适配2.2 也讲清楚了,刘海屏的切割区域,都存在于状态栏上,所以在有状态栏的页面上,是无需我们特殊处理的,系统会帮我们处理好。而对于全屏的页面,就需要单独的处理了。我这里,简单做了一个全屏页面,每个横条都是等宽的这样能看到布局上的差异。从左至右分别是:关闭刘海屏、开启刘海屏但不支持、适配刘海屏。一个全屏的页面,当没有支持刘海屏又碰到了刘海屏,会导致 UI 下沉,如果这不是一个列表的布局,底部的控件就会被遮挡。例如下面这样的情况:还有一些被刘海遮挡区域的效果,其实主要是依赖 UI 设计师来规避了,不要在可能出现刘海切割的地方,设计可操作的区域,影响用户操作。三、技术适配刘海屏说那么多,最终我们还是需要用技术的方式来适配刘海屏。Android P 的刘海屏,是有标准的 Api 来进行适配,而对于一些厂商自己的刘海屏设备,例如:OPPO R15,就需要遵循它的开发文档进行单独适配。Android P 为最新的刘海屏,提供了专门的 Api 来支持:DisplayCutout。3.1 开启刘海屏我们在全屏的页面,需要单独开启支持刘海屏。而 Google 提供的适配方案,可以设置是否在全屏模式下,使用刘海屏的区域。WindowManager.LayoutParams lp =getWindow().getAttributes(); lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; getWindow().setAttributes(lp); 复制代码新的布局属性 layoutInDisplayCutoutMode 包含三种可选的模式,public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; 复制代码3.2 刘海屏的高度在全屏模式下,我们需要有办法获取到刘海屏凹槽的高度,才可以做到设计和布局的时候,留出安全距离。虽然 Google 要求,刘海屏的凹槽,必须和刘海的高度保持一致,而刘海屏又被隐藏在状态栏了,所以有一个思路是直接获取状态栏的高度,来判断刘海之外,可布局的安全区域。不过 Android P 已经预留出了标准的测量 刘海屏凹槽 的 Api:DisplayCutout。刘海屏的凹槽,就在屏幕的中间,所以只有 getSafeInsetTop() 方法返回的结果,是我们需要的,而其他的 getSafeInsetXxx() 方法,直接返回的是 0 。view.postDelayed(new Runnable() { @Override public void run() { DisplayCutout displayCutout = view.getRootWindowInsets().getDisplayCutout(); Log.i("cxmyDev", "SafeInsetBottom:" + displayCutout.getSafeInsetBottom()); Log.i("cxmyDev", "SafeInsetLeft:" + displayCutout.getSafeInsetLeft()); Log.i("cxmyDev", "SafeInsetRight:" + displayCutout.getSafeInsetRight()); Log.i("cxmyDev", "SafeInsetTop:" + displayCutout.getSafeInsetTop()); } }, 100); 复制代码得到的结果,也可以看一下:I/cxmyDev: SafeInsetBottom:0 I/cxmyDev: SafeInsetLeft:0 I/cxmyDev: SafeInsetRight:0 I/cxmyDev: SafeInsetTop:112 复制代码3.3 非标准 Api像 OPPO 这样的厂商,实现刘海屏的方式,也并不是按照 Android P 的标准做的,它完全是自己修改了刘海屏的实现方式。不过好在,都是会提供完备的适配文档,这就需要我们直接阅读他们提供的开发文档来进行适配。oppo 的刘海屏适配文档:https://open.oppomobile.com/wiki/doc#id=10139对于 OPPO 而言,它刘海的高度是固定的,就是 80px。判断当前设备是否是刘海屏,也提供了对应的 Api,可以用以下方法获取。context.getPackageManager().hasSystemFeature(“com.oppo.feature.screen.heteromorphism”) 复制代码返回 true 为刘海屏,但是这种方法只能识别 OPPO 品牌所支持的刘海屏。四、结语看完本篇文章,我想你对 Android 的刘海屏也有一定的认识了。这是一个全新的适配技术,现在还不确定不同厂商会不会对其微调,所以你要是碰到什么问题,不妨在留言区留言讨论。今天在公众号后台回复成长『成长』,将会得到我整理的一些学习资料,也能回复『加群』,一起学习进步。推荐阅读:漫画:程序员,你能“管理”好你的产品经理吗? App 多语言翻译,机器翻译也能快如闪电! 2017 最权威区块链报告(内含下载) Google 的 Flutter 学习资料! 远程控制智能电视,方案已开源!
2023年03月24日
5 阅读
0 评论
0 点赞
1
...
7
8
9
...
11