这样,只要诚实的节点控制网络,验证是可靠的。但如果网络被攻击者控制,就很脆弱。因为网络节点可以自己核实交易,只要攻击者能够继续控制网络,交易者通过伪造交易就可以简单的实现欺骗。防止这种情况的一种策略是,当网络节点检测到无效块时,接受它们发出的警报,提示用户的软件下载完整块,并提醒确认交易的不一致。经常收到付款的企业可能仍希望运行自己的节点,以实现更独立的安全性和更快的验证。
- 合并与拆分
尽管可以单独处理每一个币,但是在一个交易中为每一个币进行转账并不明智。为允许组合或拆分,交易包含多个输入和输出。通常输入有一个大面值的币或者是多个小面额的币组成,输出则由一个给到收款方的,一个是找零的(要退还给付款方)。

需要注意的是,交易可能依赖几个其他的交易,以此类推,会依赖于更多其他的交易,这并不是一个问题。我们工作中并不需要一个完整的交易历史副本。
- 隐私
传统的银行模式通过限制相关方和受信任的第三方对信息的访问来实现一定程度的隐私。这里要求公开宣布所有交易放弃了此方案,但隐私仍然可以通过保持公钥匿名来维持。公众可以看到有人在向他人发送金额,但没有将交易与任何人联系起来的信息。这类似于证券交易所发布的信息,在证券交易所,个人交易的时间和规模被公开,但并不告知当事人是谁。

还可以增加另外一层防护,可以为每个交易生成新的秘钥对,来避免被联系到特定的所有人。但是必须的关联还是会有,这还是会识别出这些交易来自于同一个所有人。如果必要的所有人信息泄露,这些关联会泄露所有其相关的交易。
- 计算
这里考虑一个场景:攻击者视图生成另外一条比可信链更长的链。即时攻击者实现这点,他也不能任意修改系统数据,例如凭空发行货币或者获得部署于自己的货币。节点不会接受无效的交易,可信的节点不会接受包含他们信息的块。攻击者智能修改自己的交易,收回最近花出去的货币。
供给链和可信链的竞争可以描述为二项式随机游走。成功的事件时可信链增加一个块,优势领先1,失败的事件是攻击链增加一个块,差距减少1.
攻击者追赶给定差距的概率类似于赌徒破产问题。假设一个拥有无限信用的赌徒从一个亏损开始,并可能进行无限次尝试以达到盈亏平衡。我们可以计算他达到收支平衡的概率,就是攻击者追到诚实链的概率,如下所示:
p = 可信节点生成下一个块的概率
q = 攻击者生成下一个块的概率
qz = 攻击者从z块追赶的概率

假设p>q,攻击者追赶上的概率,随着块数量的增加呈现指数级下降。
考虑下心交易的接受者需要等待多长时间才能充分证明发送方不能更改交易。如果付款方是攻击者,他肯定希望收款方相信他已经支付,并在过一段时间之后将交易收款方发送给自己,当收款方收到告警时,付款方希望为时已晚。
接收方生成一个新的秘钥对,并在签名前不久才将公钥提供给发送方。这可以防止发送方提前准备一个块,一旦交易被发送,攻击者必须开始处理其新的交易版本。
接收方等待交易被添加到一个块,并且在z个块被连接在其后。他不知道攻击者的确切进展,但是可假设城市区块的平均时间可预期,攻击者的潜在进度符合Poisson分布:

为了得到攻击者成功的概率,需要将指定点的概率指导z个块的概率累加:

简化如下:

C代码如下:
#include
double AttackerSuccessProbability(double q, int z)
{
double p = 1.0 - q;
double lambda = z * (q / p);
double sum = 1.0;
int i, k;
for (k = 0; k <= z; k++)
{
double poisson = exp(-lambda);
for (i = 1; i <= k; i++)
poisson *= lambda / i;