跳到主要内容

设计支付 webhook

· 阅读需 5 分钟

1. 澄清需求

  1. 一旦支付成功,webhook 将回调商家。
    1. 商家开发者向我们注册 webhook 信息。
    2. 可靠且安全地向 webhook 发起 POST HTTP 请求。
  2. 高可用性、错误处理和故障恢复。
    1. 异步设计。假设商家的服务器分布在全球,可能会有高达 15 秒的延迟。
    2. 至少一次交付。幂等密钥。
    3. 顺序无关。
    4. 强大且可预测的重试和短路机制。
  3. 安全性、可观察性和可扩展性。
    1. 防伪造。
    2. 当商家的接收器出现故障时通知商家。
    3. 易于扩展和规模化。

2. 概述高层设计

异步设计 + 重试 + 排队 + 可观察性 + 安全性

3. 功能和组件

核心功能

  1. 用户访问仪表板前端向我们注册 webhook 信息 - 例如要调用的 URL、他们希望订阅的事件范围,然后从我们这里获取 API 密钥。
  2. 当有新事件时,将其发布到队列中,然后被调用者消费。调用者获取注册信息并向外部服务发起 HTTP 调用。

webhook 调用者

  1. 订阅由支付状态机或其他服务发布的支付成功事件队列。

  2. 一旦调用者接受事件,从用户设置服务获取 webhook URI、密钥和设置。根据这些设置准备请求。为了安全...

  • 所有来自用户设置的 webhook 必须使用 HTTPS。

  • 如果负载很大,预期延迟很高,并且我们希望确保目标接收器是活跃的,我们可以通过携带挑战的 ping 验证其存在。例如,Dropbox 通过发送带有“challenge”参数(一个随机字符串)的 GET 请求来验证 webhook 端点,您的端点需要将其回显作为响应。

  • 所有回调请求都带有头部 x-webhook-signature。这样接收者可以验证请求。

    • 对于对称签名,我们可以使用 HMAC/SHA256 签名。其值为 HMAC(webhook secret, raw request payload); Telegram 使用此方法。
    • 对于非对称签名,我们可以使用 RSA/SHA256 签名。其值为 RSA(webhook private key, raw request payload); Stripe 使用此方法。
    • 如果是敏感信息,我们还可以考虑对负载进行加密,而不仅仅是签名。
  1. 向外部商家的端点发起带有事件负载和安全头的 HTTP POST 请求。

API 定义

// POST https://example.com/webhook/
{
"id": 1,
"scheduled_for": "2017-01-31T20:50:02Z",
"event": {
"id": "24934862-d980-46cb-9402-43c81b0cdba6",
"resource": "event",
"type": "charge:created",
"api_version": "2018-03-22",
"created_at": "2017-01-31T20:49:02Z",
"data": {
"code": "66BEOV2A", // 或用户需要履行的订单 ID
"name": "主权个体",
"description": "掌握信息时代的过渡",
"hosted_url": "https://commerce.coinbase.com/charges/66BEOV2A",
"created_at": "2017-01-31T20:49:02Z",
"expires_at": "2017-01-31T21:49:02Z",
"metadata": {},
"pricing_type": "CNY",
"payments": [
// ...
],
"addresses": {
// ...
}
}
}
}

商家服务器应以 200 HTTP 状态码响应以确认收到 webhook。

错误处理

如果没有收到确认,我们将使用幂等性密钥和指数退避重试,最长可达三天。最大重试间隔为 1 小时。 如果达到某个限制,则短路/标记为损坏。向商家发送电子邮件。

指标

Webhook 调用者服务将状态发射到时序数据库以获取指标。

使用 Statsd + Influx DB 还是 Prometheus?

  • InfluxDB:应用程序将数据推送到 InfluxDB。它有一个用于指标和索引的单体数据库。
  • Prometheus:Prometheus 服务器定期从运行的应用程序中拉取指标值。它使用 LevelDB 进行索引,但每个指标存储在自己的文件中。

或者如果您有宽裕的预算,可以使用昂贵的 DataDog 或其他 APM 服务。

小谈的艺术

· 阅读需 4 分钟
  • 在西方世界,除了公众演讲,最大的社交恐惧是与陌生人开始对话。为了克服被拒绝的恐惧,意识到在大多数情况下,当你努力与他们交谈时,人们会对此表示赞赏,这很有帮助。
  • 在某些情况下,不说话可能会让你显得傲慢或冷漠。开始对话可以很简单:首先,对某人微笑;其次,建立眼神接触;第三,主动自我介绍。
  • 接近一群人:1,远处表现出你对这个小组的兴趣,注意发言者。2,群体会注意到并为你腾出空间。3,在你表达任何强烈观点之前,让小组对你有好感。
  • 引导对话会唤起积极的情感,使人们愿意与你合作或社交。承担这一责任的一个简单方法是表现得像一个主人,问:“你叫什么名字?”强调“你”,让他们感到被重视。
  • 改善对话的最佳方法是提出开放式问题,这表明你真心关心他们想说的话。
  • 对话不可避免地会有尴尬的沉默。你可以通过询问与当前情境相关的开放式问题或使用FORM首字母缩略词(家庭、职业、休闲和其他)来恢复舒适的交流。
  • 成为一个积极的倾听者,肢体语言很重要:避免交叉双臂、耸肩或摆弄衣物、头发或珠宝。相反,向前倾身、点头、微笑并保持眼神接触。
  • 成为一个积极的倾听者,语音提示也很重要:通过询问关于细节的后续问题来参与,热情回应以表达你的兴趣,或对发言者所说的内容进行释义以澄清。
  • 优雅地结束对话的第一件事是回到你讨论的重点。如果你真心想在稍后继续讨论,交换联系方式,说明你接下来要做什么(如果是熟人)握手并道别。
  • 重要的是要遵循你所说的接下来要做的事情。否则,另一方可能会认为你根本不享受与他们的相处,这会伤害他们的感情。
  • 以介绍你的对话伙伴给新朋友的方式结束对话是一种礼貌的方式,这将扩大他的社交网络,并确保他不会觉得你在抛弃他。或者反过来,你可以请他们介绍你给其他人。

移动分析指标

· 阅读需 3 分钟
名称定义评论
DAU(每日活跃用户)每日独立用户数量下载数据具有误导性,因为 80% 到 90% 的下载用户从未返回
MAU(每月活跃用户)每月独立用户数量下载数据具有误导性
粘性(DAU / MAU ) x 100粘性越高 = 投资回报率越高,移动粘性是移动/桌面的 20 倍
留存率((期末客户数量 – 期内获得客户数量) / 期初客户数量 ) x 100高留存率几乎总是好事。
流失率1- 客户留存率
CPA(每次获取成本)总营销成本 / 总用户获取数量越低越好
每 DAU 平均每日会话数用户每天登录应用的频率。并不总是好事。
LTV(生命周期价值)转化的平均价值 x 一段时间内的平均转化数量 x 平均客户价值亏损 = 布尔值(LTV < CPA)
ARPU(每用户平均收入)应用的生命周期收入 / 生命周期用户数量ARPU 说明你应该在每个用户身上赚取更多的收入
ARPPU(每付费用户平均收入)应用的生命周期收入 / 生命周期付费用户数量
ROI(投资回报率)回报 / 投资保持一致以衡量年度相对进展
应用加载时间应该 ≤ 2 秒
用户满意度通过 CSAT 和 NPS 测量更好的用户满意度 = 更多的用户留存 + 更多的 LTV
CSAT(客户满意度评分)(满意客户数量 / 调查响应者数量) x 100请客户在 1 到 5 的范围内评分他们的满意度。4 或 5 表示满意
NPS(净推荐值)((推荐者数量 – 贬低者数量) / 调查响应者数量) x 100请客户在 1 到 10 的范围内评分他们的满意度。回复 0 到 6 的用户是贬低者。回复 8 到 10 的用户是推荐者。
目标达成每个会话中实现目标的用户百分比目标可以是购买、注册、分享等。
营销获取%, $, 和来自顶级营销渠道的访客的美元价值百分比

Stratechery: 为什么亚马逊收购了全食超市?

· 阅读需 6 分钟

答案是:亚马逊想要买客户给自己的食品杂货服务。

背景

  • 亚马逊收购全食超市 = 苹果公司的 iPhone 击败了 Palm

    • 不要混淆目标(goals)、战略(strategies)和战术(tactics)—— 苹果公司的战略:
      • 不是要制造手机而是要生产个人电脑
      • 不是要为手机添加功能而是要将传统手机的功能压缩成一个app
      • 不是复制运营商的工作,而是利用其与客户之间的联系
    • iPhone 是有史以来最成功的产品 = 亚马逊是有史以来最具统治力的公司
  • 亚马逊的目标

    1. 起初,Amazon.com 的目标是成为基于信息化产品与服务的一流零售商,并且从卖书开始。
    2. 然后,亚马逊宣布“我们的愿景是成为地球上最以客户为中心的公司,要让每个人都能在我们的线上网站找到任何他们想要买的东西。”
    3. ==亚马逊的目标是从所有的经济活动中分一杯羹==。
  • 亚马逊的战略

    • 面向企业:AWS。假设所有商业交易不久之后都能使用互联网完成
    • 面向客户:Prime。假设高成本和多样的选择是不可持续的。有了 prime 客户就不会考虑其他替代方案。
      • 然而
        • 食品杂货业是最大的零售业类别
        • 食品杂货业最能够持续提醒消费者:除了亚马逊其实还有其他的选择
  • 亚马逊的战术:发展食品杂货服务

为什么亚马逊没有得出正确的战术?

书籍杂货
高存货单位=选品丰富低存货单位(30k - 50k)
标准化的良莠不齐的
不会腐烂容易腐烂

亚马逊生鲜的成本劣势

  1. 一旦规模不足,商品腐烂将会产生很高的成本
  2. 而规模取决于每个城市的具体情况

为什么收购全食超市(而非其他)可以解决商业规模问题?

==商业基础元件模型 + 两个基本点 1) 高固定成本 2) 高回报==

  • 将基础设施解构成最小可售单元(MSUs)
  • 这些业务本身就是这些最小可售单元的第一和最佳的客户
  • 将最小可售单元转售出去

AWS的三层架构

服务基础元件S3, EC2, RDS, SNS, ...
平台AWS高额的固定成本 + 规模回报
基础设施模块化组件数据中心,服务器,存储,交换机,带宽
  • MSUs 属于 S3, EC2, RDS, SNS等
  • 第一和最佳的客户是 amazon.com
  • 转售 MSUs 给非亚马逊开发者

Amazon.com 的三层架构

服务包裹FDA, Amazon Pay, ...
平台物流中心高额的固定成本 + 规模回报
基础设施模块化供应商制造商,第三方供应商等
  • MSUs 属于 FDA, Amazon Pay 等
  • 第一和最佳的客户是亚马逊第一方电子商务
  • 将 MSUs 转售给第三方供应商

这里的洞见是亚马逊现有的食品杂货并不存在第一和最佳供应商。

完美的客户

把全食超市放进这个版图中,我们可以看到, ==亚马逊所做的不仅仅是买到了一个零售商,更是买到了自己原有业务的一个客户==。

Amazon.com 的三层架构 + 客户

客户所有品类的食品,快递,餐厅
服务杂货肉,水果,蔬菜,干粮等
平台物流中心高额的固定成本 + 规模回报
基础设施模块化供应商商店品牌,名牌,本地供应商,区域供应商等

如今,亚马逊食品杂货可以服务于亚马逊生鲜和全食超市,未来,这个基础平台还可以为餐厅等需要食物的地方提供服务。

设计股票价格变动的智能通知

· 阅读需 16 分钟

需求

  • 300 万用户
  • 5000 支股票 + 250 支全球股票
  • 用户在以下情况下会收到价格变动通知:
    1. 订阅该股票
    2. 股票价格变动达到 5% 或 10%
    3. 自 a) 上周或 b) 昨天以来
  • 可扩展性。可能支持其他类型的通知,如突发新闻、财报电话会议等。

构建架构草图

上下文:

  • 什么是清算?清算是金融交易结算的程序——即资金及时准确地转移给卖方,证券转移给买方。通常,清算由一个称为清算所的专业组织作为中介。
  • 什么是证券交易所?一个股票经纪人和交易者可以买卖证券的场所。

苹果推送通知服务


(APNs)

苹果推送通知服务<br>(APNs)

Google Firebase 云消息传递


(FCM)

Google Firebase 云消息传递<br>(FCM)

电子邮件服务


AWS SES /sendgrid/etc

电子邮件服务<br>AWS SES /sendgrid/etc

通知者

通知者

外部供应商



市场价格

[不支持查看器]

Robinhood 应用

Robinhood 应用

API 网关

API 网关

反向代理

反向代理

批量写入

批量写入

价格


监测器

[不支持查看器]

时间序列数据库


influx 或 prometheus

时间序列数据库<br>influx 或 prometheus

每 5 分钟一次

[不支持查看器]

定期读取

定期读取

价格


监测器

价格<br>监测器

用户设置

用户设置

通知队列

通知队列

限流缓存

限流缓存

cronjob

cronjob

这些组件是什么,它们如何相互作用?

  • 价格监测器
    • 数据获取策略
      • 选项 1 初步:每 5 分钟获取一次数据,并批量写入时间序列数据库。
      • 选项 2 高级:如今外部系统通常直接推送数据,因此我们不必一直拉取。
    • 每次请求或每次价格变动约 6000 个点。
    • 数据保留 1 周,因为这只是 lambda 架构的加速层。
  • 价格观察者
    • 读取过去一周或过去 24 小时内每只股票的数据。
    • 计算波动是否超过 5% 或 10% 在这两个时间段内。我们得到的元组如 (股票, 上涨 5%, 1 周)。
      • 边缘情况:我们是否应该规范化价格数据?例如,某人错误地将 UBER 以 1 美元的价格出售。
    • 速率限制(因为 5% 或 10% 的变化可能在一天内发生多次),然后发出事件 PRICE_CHANGE(STOCK_CODE, timeSpan, percentage) 到通知队列。
  • 定期触发器是 cron 作业,例如 Airflow、Cadence。
  • 通知队列
    • 在用户和股票数量较少时,可能不一定会引入。
    • 可能接受通用消息事件,如 PRICE_CHANGEEARNINGS_CALLBREAKING_NEWS 等。
  • 通知者
    • 订阅通知队列以获取事件
    • 然后从用户设置服务中获取通知对象
    • 最后根据用户设置,通过 APNs、FCM 或 AWS SES 发送消息。

设计股票交易所

· 阅读需 17 分钟

需求

  • 买入卖出 订单的订单匹配系统。订单类型:
    • 市场订单
    • 限价订单
    • 止损订单
    • 完全成交或取消订单
    • 订单有效期
  • 为数百万用户提供高可用性和低延迟
    • 异步设计 - 广泛使用消息队列(顺便提一下,副作用:工程师在一个服务上发布到队列,不知道下游服务具体在哪里,因此无法做坏事。)

架构

反向代理

反向代理

API 网关

API 网关

订单匹配

订单匹配

用户存储

用户存储

结算

结算

订单

订单

股票元数据

股票元数据

认证

认证

缓存

缓存

余额与记账

余额与记账

外部定价

外部定价

清算


清算<br>所

银行,ACH,Visa 等

银行,ACH,Visa 等

支付

支付

审计与报告

审计与报告

组件及其相互作用

订单匹配系统

  • 按股票代码分片
  • 订单的基本数据模型(其他元数据省略):Order(id, stock, side, time, qty, price)
  • 订单簿的核心抽象是匹配算法。有许多匹配算法(参考 stackoverflow参考 medium
  • 示例 1:价格-时间 FIFO - 一种将二维向量投射或展平为一维向量的方式
    • x 轴是价格
    • y 轴是订单。价格/时间优先队列,FIFO。
      • 买方:按价格升序,按时间降序。
      • 卖方:按价格升序,按时间升序。
    • 换句话说
      • 买方:价格越高,订单越早,越接近匹配中心。
      • 卖方:价格越低,订单越早,越接近匹配中心。

x 轴

价格线

y 轴投射到 x 轴上

Id   Side    Time   Qty   Price   Qty    Time   Side
---+------+-------+-----+-------+-----+-------+------
#3 20.30 200 09:05 卖出
#1 20.30 100 09:01 卖出
#2 20.25 100 09:03 卖出
#5 买入 09:08 200 20.20
#4 买入 09:06 100 20.15
#6 买入 09:09 200 20.15

来自 Coinbase Pro 的订单簿

单一股票交易所模拟器

  • 示例 2:按比例分配

纯按比例分配

如何实现价格-时间 FIFO 匹配算法?

  • 按股票分片,CP 优于 AP:一股一个分区
  • 有状态的内存树图
    • 定期迭代树图以匹配订单
  • 使用 Cassandra 进行数据持久化
  • 订单匹配服务的进出请求通过消息队列进行
  • 故障转移
    • 内存树图快照到数据库
    • 在错误情况下,从快照恢复并与缓存去重

如何实时将订单簿数据传输到客户端?

  • websocket

如何支持不同类型的订单?

  • 在树图中使用相同的 卖出或买入:数量 @ 价格,但具有不同的创建设置和匹配条件
    • 市场订单:以最后市场价格下单。
    • 限价订单:以特定价格下单。
    • 止损订单:以特定价格下单,并在特定条件下匹配。
    • 完全成交或取消订单:以特定价格下单,但仅匹配一次。
    • 订单有效期:以特定价格下单,但仅在给定时间范围内匹配。

订单服务

  • 保留所有活动订单和订单历史。
  • 接收到新订单时写入订单匹配。
  • 接收匹配的订单并与外部清算所结算(异步外部网关调用 + 定时任务同步数据库)

参考文献

史蒂夫·乔布斯:管理者与傻瓜

· 阅读需 2 分钟

我在 Blind App 上遇到了“傻瓜管理”,发现这是一个非常有趣的概念。这个短语是史蒂夫·乔布斯创造的。

如果你无法观看视频,这里是他的话。

我们在苹果经历了一个阶段,我们认为,‘哦,我们要成为一家大公司,去招聘专业管理人员。’我们出去招聘了一堆专业管理人员;结果完全不奏效。他们大多数都是傻瓜。他们知道如何管理,但不知道如何做任何事情。

如果你是一个优秀的人,为什么要为一个你无法从中学习的人工作呢?你知道最有趣的是什么吗 - 你知道最好的经理人是什么样的吗?他们是那些从来不想成为经理的优秀个人贡献者,但决定必须成为经理,因为没有其他人能像他们一样做好工作。

理解去中心化身份 (DID 和 DIF)

· 阅读需 17 分钟

什么是 DIF?

去中心化身份基金会 构建去中心化身份的生态系统,并确保所有参与者之间的互操作性。

为什么?……问题是什么?

身份问题

将身份与个人可识别信息 (PII) 解耦的问题。身份由一组深具个人性的定义我们数据构成,您的身份只应对您自己负责。

具体来说,面临的挑战是

  1. 将身份与身份提供者解耦。 DIDs 应该是自我主权的,不应由中央权威拥有或控制。
  2. 将身份查找与集中系统解耦。 DIDs 和数据应该能够在去中心化系统中被找到,以便没有中央所有者可以做恶。
  3. 将身份数据与不明或未知存储解耦。 DIDs 应该能够精确控制与他人分享什么或不分享什么。

统一碎片化的格局

DIF 是一个组织,旨在统一碎片化的格局,共同解决 DID 问题并建立一个作为行业标准的生态系统。

他们如何组织这些努力?

  • 设计规范
  • 实施
  • 对齐行业参与者

人员和组织

工作组

  • 身份、名称、发现
  • 存储和计算
  • 声明和凭证

成员

  • Blockstack
  • Microsoft / IBM
  • HyperLedger
  • RSA
  • Ontology
  • Civic
  • iota

生态系统

DIF 生态系统

DID

身份是

  1. 全球唯一的
  2. 可解析的,且
  3. 具有加密验证的。

DID 格式:URN

URN 格式

DID 方法(在下面进一步解释)定义了 DIDs 如何与特定区块链一起工作。

DID 文档

  • DID 基础设施 = <DID, DID 文档> 的全球键值数据库
  • DID 文档 = 用于验证实体的公钥、认证协议和服务端点,并解释如何使用它。它可能包含三项内容:
    • 证明目的
    • 验证方法
    • 服务端点

DID 如何保护隐私?

  1. 成对伪匿名的 DIDs
  2. 链外私有数据
  3. 选择性披露

DID 方法规范 (DID <> 区块链)

定义如何在特定区块链上创建、解析和管理 (CRUD) DID 和 DID 文档。

如何加入 DID 方法注册?

https://w3c-ccg.github.io/did-method-registry/#the-registry

示例

通过示例学习:Blockstack DID 方法

  • Blockstack 如何利用 DID?
  • 如何创建一个 blockstack DID?Blockstack 如何作为身份提供者?
  • 如何解析一个 DID?

Blockstack 命名服务 (BNS)

  • 命名层 = 用户名 <> 公钥 & 指向存储的指针
  • BNS 是区块链无关的。 从 namecoint 迁移到比特币。
  • ==一个 Blockstack DID 被定义为指向由一个地址注册的第 n 个名称==。

两类

链上 DIDs

  • 两笔交易在链上注册一个名称 - 所有者地址 <> 名称
  • 一个所有者地址可以有多个链上名称和相应的 DIDs
    • 例如 did:stack:v0:15gxXgJyT5tM5A4Cbx99nwccynHYsBouzr-3 表示第四个链上名称被创建并最初分配给地址 15gxXgJyT5tM5A4Cbx99nwccynHYsBouzr

链外 DIDs,也称为子域

  • 批量编码,哈希,并稍后写入区块链。

  • 链外名称由链上名称实例化,由链外名称的后缀表示。 cicero.res_publica.idres_publica.id 的所有者处理,但并不归其所有。

Blockstack 作为身份提供者

演示: https://bitpatron.co/ 使用 Blockstack 登录

sequenceDiagram User ->> First Party: GET /login Note left of User: 登录 Note right of First Party: 存储 transitKey First Party ->> User: 重定向 User ->> Blockstack: GET /auth?authRequest=:authRequestJwt Blockstack ->> First Party: GET /manifest.json (CORS) Note left of User: 创建或选择 ID Blockstack ->> User: 重定向 User ->> First Party: GET /auth?authResponse=:authResponseJwt Note right of First Party: 用 transitKey 解密 Note left of First Party: 待处理登录 First Party ->> Blockstack: GET /v1/names/:acctName.id.blockstack Blockstack ->> First Party: 用户数据

// authRequestJwt
{
"typ": "JWT",
"alg": "ES256K"
}
{
"jti": "4d06f08b-67a7-4f7c-89fc-b8164b81f67a",
"iat": 1563432343,
"exp": 1566110743,
"iss": "did:btc-addr:19sxvnAxPXZYAEdpF7Tti6MSVhxA8PSdCT",
"public_keys": [
"03994ec7b23a8e11e40684c9b2d29febf103bd92c4bbd295f1e2537042c93ac977"
],
"domain_name": "http://localhost:4104",
"manifest_uri": "http://localhost:4104/manifest.json",
"redirect_uri": "http://localhost:4104/",
"version": "1.3.1",
"do_not_include_profile": true,
"supports_hub_url": true,
"scopes": [
"store_write"
]
}
// authResponse
{
"typ": "JWT",
"alg": "ES256K"
}
{
"jti": "30773b78-3595-499f-bbb3-d1e649470c70",
"iat": 1563432894,
"exp": 1566111294,
"iss": "did:btc-addr:1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"private_key": "已编辑 - 用 transitKey 加密",
"public_keys": [
"027c8547681cc27e27b73ee0f3c0534bdd38993dcb4c1934bf424f0b3a04dcad63"
],
"profile": null,
"username": "kirbystar.id.blockstack",
"core_token": null,
"email": null,
"profile_url": "https://gaia.blockstack.org/hub/1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH/profile.json",
"hubUrl": "https://hub.blockstack.org",
"blockstackAPIUrl": "https://core.blockstack.org",
"associationToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJjaGlsZFRvQXNzb2NpYXRlIjoiMDNhMTU5YzY4YWQ1ZjFkNzcxMWY2NjJmNThkNjdmMzZlNzY3ZTBjMDBhOTU4ZWY0NzljNzU3MzU0MGFkMzExZjk2IiwiaXNzIjoiMDI3Yzg1NDc2ODFjYzI3ZTI3YjczZWUwZjNjMDUzNGJkZDM4OTkzZGNiNGMxOTM0YmY0MjRmMGIzYTA0ZGNhZDYzIiwiZXhwIjoxNTk0OTY4ODk0LjcwNSwiaWF0IjoxNTYzNDMyODk0LjcwNSwic2FsdCI6IjE4NGVhMWQyMzM3MWQ1MmYyYzhmNTAyOGUwMWYxYmZiIn0.ZceaVcIK2Z8wu6KBYOHQaK7y6BI7NfxrixphOCPs1B4hZcGYDKsuf0anbm4CdAAJbKRifCm-MYHE6fjKD9E7GQ",
"version": "1.3.1"
}
// acctName response
{
"blockchain": "bitcoin",
"status": "submitted_subdomain",
"last_txid": "851ca5e6c06723e61037aa397966aafa1a6dd7159e9e31e53116106b87101886",
"zonefile": "$ORIGIN kirbystar.id.blockstack\n$TTL 3600\n_http._tcp\tIN\tURI\t10\t1\t\"https://gaia.blockstack.org/hub/1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH/profile.json\"\n\n",
"address": "1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"zonefile_hash": "a9c016921a9a60e04776251db53a8881e6d128ce"
}
// session
{
"version": "1.0.0",
"userData": {
"username": "kirbystar.id.blockstack",
"profile": {
"@type": "Person",
"@context": "http://schema.org",
"api": {
"gaiaHubConfig": {
"url_prefix": "https://gaia.blockstack.org/hub/"
},
"gaiaHubUrl": "https://hub.blockstack.org"
}
},
"email": null,
"decentralizedID": "did:btc-addr:1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"identityAddress": "1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"appPrivateKey": "已编辑",
"coreSessionToken": null,
"authResponseToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiIyNmM4ZGM2Ny1lNzEwLTRlZDUtYmIxYi0yY2I1ODY5YTRkMTEiLCJpYXQiOjE1NjM0MzU2NjEsImV4cCI6MTU2NjExNDA2MSwiaXNzIjoiZGlkOmJ0Yy1hZGRyOjFEcEtNcXhCbnVTU1FNTnVuMW9iY2lQU2ZEOXJEOEtOVUgiLCJwcml2YXRlX2tleSI6IjdiMjI2OTc2MjIzYTIyNjQzMDMzMzMzODMyNjYzNTYxNjIzNjM0Mzg2MTM1MzYzNTM2MzI2MzMzNjEzMTYyMzY2NTYzNjEzNzMzNjU2NjIyMmMyMjY1NzA2ODY1NmQ2NTcyNjE2YzUwNGIyMjNhMjIzMDMyNjEzMzY1NjEzMzY0NjMzNjMyMzgzODY2MzgzMTY2MzAzNDMwMzU2MzY1MzI2MzMzNjUzNjY0MzMzMzMxMzQzNDM0NjY2MTM4MzA2NTY1MzIzMzMyNjEzMjM2NjQzMzMwMzczMzM2MzY2NTMzMzkzNzM3MzczMjMxMzMzNzM5MzcyMjJjMjI2MzY5NzA2ODY1NzI1NDY1Nzg3NDIyM2EyMjM2MzMzOTYzNjMzMDM5MzQzOTYyMzMzNjY0NjI2NTM1MzIzMTM0MzIzMjM3MzA2MzY1NjIzMTM0MzEzNjY2MzA2MzM0NjYzNDM4MzgzMjY0MzUzOTM0MzMzNDM2NjM2NjYyNjEzNzMxNjM2MjM1MzYzMTM2MzczMDY0MzUzMzY0MzQzNTY1MzMzODYyNjIzNzM1NjMzMjMzMzYzNjMyMzUzODMxMzgzOTM3NjYzMjMwNjMzNTM4MzA2NTMyMzEzODM0MzMzNTMwMzMzNjM1NjE2NDM1NjEzMTM4NjY2MjMyNjY2NDM3MzQ2MzY1NjMzNDM0MzI2NTY0MzY2NTY2NjYzMjM5NjIzNjY2Mzk2MTMyMzgzMTM4MzEzMzYyMzMzMDYyMzkzMTYzMzE2MzM1Mzg2MTM4MzgzMTM5MzQ2MjYzMjIyYzIyNmQ2MTYzMjIzYTIyMzkzNzY0MzM2MzM4NjEzOTYxMzQ2NjMyMzkzNjM1MzM2MzM1MzQzNzY1MzIzNTYzMzMzMzM4MzIzMDYxMzczMjYyMzU2NjY0MzQ2NjM1NjE2NDYxNjY2NjMwMzQzNzM1Mzk2NDM0MzI2MTYxMzgzNDM1MzkzNzY2MzY2MjM5NjEyMjJjMjI3NzYxNzM1Mzc0NzI2OTZlNjcyMjNhNzQ3Mjc1NjU3ZCIsInB1YmxpY19rZXlzIjpbIjAyN2M4NTQ3NjgxY2MyN2UyN2I3M2VlMGYzYzA1MzRiZGQzODk5M2RjYjRjMTkzNGJmNDI0ZjBiM2EwNGRjYWQ2MyJdLCJwcm9maWxlIjpudWxsLCJ1c2VybmFtZSI6ImtpcmJ5c3Rhci5pZC5ibG9ja3N0YWNrIiwiY29yZV90b2tlbiI6bnVsbCwiZW1haWwiOm51bGwsInByb2ZpbGVfdXJsIjoiaHR0cHM6Ly9nYWlhLmJsb2Nrc3RhY2sub3JnL2h1Yi8xRHBLTXF4Qm51U1NRTU51bjFvYmNpUFNmRDlyRDhLTlVIL3Byb2ZpbGUuanNvbiIsImh1YlVybCI6Imh0dHBzOi8vaHViLmJsb2Nrc3RhY2sub3JnIiwiYmxvY2tzdGFja0FQSVVybCI6Imh0dHBzOi8vY29yZS5ibG9ja3N0YWNrLm9yZyIsImFzc29jaWF0aW9uVG9rZW4iOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5rc2lmUS5leUpqYUdsc1pGUnZRWE56YjJOcFlYUmxJam9pTUROaE1UVTVZelk0WVdRMVpqRmtOemN4TVdZMk5qSm1OVGhrTmpkbU16WmxOelkzWlRCak1EQmhPVFU0WldZME56bGpOelUzTXpVME1HRmtNekV4WmprMklpd2lhWE56SWpvaU1ESTNZemcxTkRjMk9ERmpZekkzWlRJM1lqY3paV1V3WmpOak1EVXpOR0prWkRNNE9Ua3paR05pTkdNeE9UTTBZbVkwTWpSbU1HSXpZVEEwWkdOaFpEWXpJaXdpWlhod0lqb3hOVGswT1RjeE5qWXhMak0yT1N3aWFXRjBJam94TlRZek5ETTFOall4TGpNMk9Td2ljMkZzZENJNklqVXhOMkZsWkdVd1ltVmpOMkpqTlRnek5qY3lOREkwT1RsaE1EVm1OVEEwSW4wLjlkY2VHX3I4OVdDSUVsTklseFNtUGxPblhiSVNsZEZDejJxOTJRMnpJSk9XXzhnTjVYT0xsZnNkREJVamlQZlU3eTNyRGFXSUxfTUJicVVnVnBFanhRIiwidmVyc2lvbiI6IjEuMy4xIn0.0Xqtw-71TJ9ybWx4Uxre0Gxkisay20xn1vqwr0WaKvVeCzwv_NO6YZnVOmGPM4cF4wex06yLYWasqQWgCi-m_g",
"hubUrl": "https://hub.blockstack.org",
"gaiaAssociationToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJjaGlsZFRvQXNzb2NpYXRlIjoiMDNhMTU5YzY4YWQ1ZjFkNzcxMWY2NjJmNThkNjdmMzZlNzY3ZTBjMDBhOTU4ZWY0NzljNzU3MzU0MGFkMzExZjk2IiwiaXNzIjoiMDI3Yzg1NDc2ODFjYzI3ZTI3YjczZWUwZjNjMDUzNGJkZDM4OTkzZGNiNGMxOTM0YmY0MjRmMGIzYTA0ZGNhZDYzIiwiZXhwIjoxNTk0OTcxNjYxLjM2OSwiaWF0IjoxNTYzNDM1NjYxLjM2OSwic2FsdCI6IjUxN2FlZGUwYmVjN2JjNTgzNjcyNDI0OTlhMDVmNTA0In0.9dceG_r89WCIElNIlxSmPlOnXbISldFCz2q92Q2zIJOW_8gN5XOLlfsdDBUjiPfU7y3rDaWIL_MBbqUgVpEjxQ"
},
"transitKey": "已编辑"
}

从 DID 获取实体 - 通用解析器

域名 <--DNS-->  IP
表示的实体 <--通用解析器--> 自主身份标识符
DID <--通用解析器--> DID 文档

通用解析器

示例驱动程序:

  • did:stack: 从 BlockStack 注册的 DID,例如 did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0
  • did:btcr: 从 BTC 注册的 DID
  • 等等。

运行解析器

git clone https://github.com/decentralized-identity/universal-resolver.git
cd universal-resolver/
docker-compose -f docker-compose.yml pull
docker-compose -f docker-compose.yml up
curl -X GET http://localhost:8080/1.0/identifiers/did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0 | jq .

{
"redirect": null,
"didDocument": {
"id": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"service": [
{
"type": "blockstack",
"serviceEndpoint": "https://core.blockstack.org"
}
],
"publicKey": [
{
"id": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"type": "Secp256k1VerificationKey2018",
"publicKeyHex": "0232131c807c4b184582280bca141f2583f6a1de2e0d3e6984cdb4724527f581fa"
}
],
"@context": "https://w3id.org/did/v0.11"
},
"resolverMetadata": {
"duration": 96,
"driverId": "did-stack",
"driver": "HttpDriver",
"didUrl": {
"didUrlString": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"did": {
"didString": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"method": "stack",
"methodSpecificId": "v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"parseTree": null,
"parseRuleCount": null
},
"parameters": null,
"parametersMap": {},
"path": "",
"query": null,
"fragment": null,
"parseTree": null,
"parseRuleCount": null
}
},
"methodMetadata": {}
}

或使用 Blockstack 的解析器

https://github.com/blockstack/blockstack-core/blob/master/docs/blockstack-did-spec.md#33--resolving-a-blockstack-did

DID <> 现实世界:可验证声明

现在我们知道如何识别和解析“谁是谁”,而不必携带个人可识别信息。然而,如果我们想让 DID 与现实世界实体关联呢?

想象一下,艾丽斯拥有一个国家颁发的 DID,并希望在不透露真实姓名和确切年龄的情况下购买一些酒。

饮酒

答案是使用“可验证声明”(也称:凭证、证明)。

  1. 声明 = 我们对实体所知的属性,采用主题-属性-值关系,例如姓名、电子邮件、年龄、会员资格等。
  2. 可验证 = 附加的证明(签名)

可验证声明数据模型

身份资料

类型:无序 URI 集合

签名:签名 [0..1]

实体凭证

id: URI

类型:无序 URI 集合

颁发者:URI

颁发:字符串形式的日期

声明:声明

声明

(至少一个自定义属性)

可验证声明

签名:签名

签名

(可能会有所不同,但预计包括

至少一个签名、一个对签署实体的引用,以及一个

签署日期的表示)

id

id

1

0..*

一个简单的身份资料

{
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"type": ["身份", "人"],
"name": "艾丽斯·博布曼",
"email": "[email protected]",
"birthDate": "1985-12-14",
"telephone": "12345678910"
}

一个简单的声明

{
"id": "http://example.gov/credentials/3732",
"type": ["凭证", "年龄证明凭证"],
"issuer": "https://dmv.example.gov",
"issued": "2010-01-01",
"claim": {
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"ageOver": 21
}
}

一个简单的可验证声明

{
"@context": "https://w3id.org/security/v1",
"id": "http://example.gov/credentials/3732",
"type": ["凭证", "年龄证明凭证"],
"issuer": "https://dmv.example.gov",
"issued": "2010-01-01",
"claim": {
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"ageOver": 21
},
"revocation": {
"id": "http://example.gov/revocations/738",
"type": "简单撤销列表2017"
},
"signature": {
"type": "链接数据签名2015",
"created": "2016-06-18T21:19:10Z",
"creator": "https://example.com/jdoe/keys/1",
"domain": "json-ld.org",
"nonce": "598c63d6",
"signatureValue": "BavEll0/I1zpYw8XNi1bgVg/sCneO4Jugez8RwDg/+
MCRVpjOboDoe4SxxKjkCOvKiCHGDvc4krqi6Z1n0UfqzxGfmatCuFibcC1wps
PRdW+gGsutPTLzvueMWmFhwYmfIFpbBu95t501+rSLHIEuujM/+PXr9Cky6Ed
+W3JT24="
}
}

这等同于一个 JOSE JWT 可验证声明

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2Rtdi
5leGFtcGxlLmdvdiIsImlhdCI6MTI2MjMwNDAwMCwiZXhwIjoxNDgzMjI4ODAwL
CJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJkaWQ6ZWJmZWIxZjcxMmVi
YzZmMWMyNzZlMTJlYzIxIiwiZW50aXR5Q3JlZGVudGlhbCI6eyJAY29udGV4dCI
6Imh0dHBzOi8vdzNpZC5vcmcvc2VjdXJpdHkvdjEiLCJpZCI6Imh0dHA6Ly9leG
FtcGxlLmdvdi9jcmVkZW50aWFscy8zNzMyIiwidHlwZSI6WyJDcmVkZW50aWFsI
iwiUHJvb2ZPZkFnZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9kbXYu
ZXhhbXBsZS5nb3YiLCJpc3N1ZWQiOiIyMDEwLTAxLTAxIiwiY2xhaW0iOnsiaWQ
iOiJkaWQ6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwiYWdlT3ZlciI6Mj
F9fX0.LwqH58NasGPeqtTxT632YznKDuxEeC59gMAe9uueb4pX_lDQd2_UyUcc6
NW1E3qxvYlps4hH_YzzTuXB_R1A9UHXq4zyiz2sMtZWyJkUL1FERclT2CypX5e1
fO4zVES_8uaNoinim6VtS76x_2VmOMQ_GcqXG3iaLGVJHCNlCu4

DID 和物联网

幻灯片

关键要点

DID

  • 可能是身份导向供应商的差异化因素,但对其他供应商来说是一个 中和器(在 MMRs、中和器和差异化特征中)。
  • 在大量产品中保护隐私,以便没有中央公司能够从各种产品的所有账户中了解您的所有信息。
  • 与可验证声明结合使用,它利用加密,但仍然需要在物理世界中建立信任。

区块链开发者可以做什么?

  • 加入 DIF。
  • 提出一种在其区块链上操作 DIDs 的 DID 方法。
  • 建立我们自己的去中心化身份提供者。

参考文献

Stratechery:为什么亚马逊收购全食超市?

· 阅读需 5 分钟

回答:亚马逊希望为其杂货服务购买一个客户。

背景

  • 亚马逊收购全食超市 = 苹果的 iPhone 击败 Palm

    • 不要误解目标与战略与战术 - 苹果的战略
      • 不是制造手机,而是构建个人电脑
      • 不是为手机增加功能,而是将手机简化为一个应用
      • 不是复制运营商,而是利用他们的客户关系
    • iPhone 是有史以来最成功的产品 = 亚马逊是有史以来最具主导地位的公司
  • 亚马逊的目标

    1. 最初,Amazon.com 的目标是成为信息类产品和服务的领先在线零售商,最初专注于书籍。
    2. 然后,它表示“我们的愿景是成为地球上最以客户为中心的公司;建立一个人们可以来寻找和发现他们可能想在线购买的任何东西的地方。”
    3. ==亚马逊的目标是从所有经济活动中分一杯羹。==
  • 亚马逊的战略

    • 对企业:AWS。假设所有企业很快都会成为互联网驱动的企业。
    • 对客户:Prime。假设优越的成本和优越的选择不是可持续的。通过 Prime,客户甚至不会考虑替代品。
      • 然而
        • 杂货是最大的零售类别。
        • 杂货是提醒用户还有其他替代品的最持久机会。
  • 战术:开发杂货服务

为什么亚马逊没有找到正确的战术?

书籍杂货
高 SKU = 大选择较少 SKU(30k - 50k)
标准化质量不一
不易腐烂易腐烂

亚马逊生鲜的成本劣势

  1. 如果不规模化,易腐烂商品的高成本
  2. 规模需要基于城市

为什么收购全食超市(而不是做其他事情)可以解决规模问题?

==具有 1) 高固定成本 2) 高规模收益的商业原始模型==

  • 将基础设施解耦为最小可销售单元(MSUs)
  • 业务本身是这些 MSUs 的 ==首个最佳客户==
  • 将 MSUs 转售给外部

AWS 三层

服务原始组件S3, EC2, RDS, SNS, ...
平台AWS高固定成本 + 规模收益
基础设施模块化组件数据中心、服务器、存储、交换机、带宽
  • MSUs 是 S3、EC2、RDS、SNS 等
  • 首个最佳客户是 amazon.com
  • 将 MSUs 转售给非亚马逊开发者

Amazon.com 三层

服务套餐FDA, 亚马逊支付, ...
平台履行中心高固定成本 + 规模收益
基础设施模块化供应商制造商、第三方商家, ...
  • MSUs 是 FDA、亚马逊支付等。
  • 首个最佳客户是亚马逊第一方电子商务
  • 将 MSUs 转售给第三方商家

这里的洞察是,杂货业务没有首个最佳客户。

完美客户

将全食超市纳入大局后,我们可以看到 ==亚马逊购买的不仅仅是一个零售商——它购买的是一个客户==。

Amazon.com 三层 + 客户

客户全食超市、配送、餐厅
服务杂货肉类、水果、蔬菜、非易腐烂商品, ...
平台履行中心高固定成本 + 规模收益
基础设施模块化供应商自有品牌、品牌商品、本地供应商、区域供应商, ...

现在亚马逊杂货服务可以服务于亚马逊生鲜和全食超市,未来餐厅或其他任何业务也可以使用它。

代表性启发式 —— 在不确定时做判断

· 阅读需 4 分钟

面对不确定的事物,人们通常基于启发式来判断。启发式很有用,但是也会带来偏误:比如 看不清=距离远 这一判断在大多数情况下是正确的,但是如果你故意模糊某个东西,人们会错误地以为它更远。

人们在判断概率和估值时候,常常使用这样三个启发式:代表性 (representativeness) 启发式,易得性 (availability) 启发式,调整与锚定 (adjustment and anchoring) 启发式。

代表性 (representativeness) 启发式

  1. ==人们会错把代表性当概率==。邻居描述史蒂夫是一个羞涩寡言,乐于助人,但是对人和世界不感兴趣的人。让人们去判断他的职业是哪种职业的可能性更大:农民、推销员、机长、图书管理员、医生。人们会错认为史蒂夫是图书管理员,因为这符合他们对这个职业的刻板印象。
  2. 那么考虑到哪些因素就能够更好地帮助对概率的判断呢?
    1. 先验概率,又名==基础比率==。人们在考虑代表性的时候,尤其是得到了无意义的证据的时候,会下意识地忽略基础比率,使用代表性来错误的做判断。同样的是上面的史蒂夫问题,应用先验概率和贝叶斯才能得到正确的答案。
    2. 样本大小。相比于样本揭示的规律,样本大小有时候能够更好的解释问题。
    3. 对几率的正确理解。赌徒谬误,比如开大小的时候错误地以为概率会自我修正到中间,但是实际上只是自我稀释罢了,连开十次“大”和五五开的概率是一样的。
    4. 可预测性。可预测性越高,预估值的区间就越广。比如单凭一个对教师教学水平的简短的评测,是不应该能够判断出这个教师五年之后的教学水平的。
    5. 小心过度自信而对自己的预测产生的有效性幻觉 (illusion of validity) ,原因是确认偏误 (confirmation bias),即人们会倾向于寻找到能够支持自己观点的证据,对支持自己观点的信息更加关注,或者把信息往能支持自己观点的方向解释。从几个独立的事件来做判断的效果会比冗余的有相关性的事件来做判断效果好。
    6. 回归均值。人们往往忽略这一趋势的存在,即便意识到也很容易随意地解释其原因。例如,在飞行员的训练中,教官发现,在平稳着陆后给表扬,下一次就会表现得相对更差;在硬着陆后给批评,下一次就会表现得相对更好,然后教官会错误地以为,是表扬和批评导致了下一次的表现。而实际上只是下一次回归均值而已。因此,人们通常会高估批评的效果,低估表扬的效果。