2023年4月

以下是一些当前较为主流的加密货币:

比特币(Bitcoin, BTC):比特币是第一种加密货币,也是最普及的一种加密货币。它以去中心化为核心,使用点对点技术实现交易和发行新的货币单位。

以太坊(Ethereum, ETH):以太坊是最重要的加密货币之一,它不仅是数字货币也是一种智能合约平台。以太坊区块链使用自己的加密货币以太币,也是支持许多 ERC-20 代币和其他分叉硬币的平台。

瑞波币(Ripple, XRP):Ripple是一种实时的毫秒级交易的加密货币,它不同于比特币和以太坊的点对点虚拟货币,由一家叫 Ripple 的公司发行。

比特币现金(Bitcoin Cash, BCH):比特币现金是比特币的一个硬分叉,它的目标是提高区块大小限制,从而提高比特币的交易速度。

Litecoin(LTC):Litecoin是比特币的一个分叉,但独立发展自己的市场。与比特币相比,Litecoin的交易过程更加迅速、更便宜、更加去中心化等等。

PromQL 是 Prometheus Query Language 的缩写,是一种用于查询 Prometheus 监控数据的查询语言。以下是一些有用的示例:

显示某个指标的平均值:
avg(metric_name)
这将计算指定指标的所有采样值的平均值。

显示指标的最大值:
max(metric_name)
这会显示指定指标的最大值。

显示过去 5 分钟内某个指标的总和:
sum_over_time(metric_name[5m])
这将计算指定指标在过去 5 分钟内的所有采样值之和。

显示某个指标在某个时间范围内的百分比:
avg_over_time(metric_name[1h]) / ignoring (instance) group_left sum(avg_over_time(metric_name[1h])) * 100
这将计算在过去一小时内,指定指标的平均值与该指标所有实例的平均值之比,并将结果转换为百分比。

Prometheus 官方文档中的 PromQL 部分。

编程语言:Solidity
以太坊智能合约的 demo,实现了一个简单的投票系统,具体代码如下:

pragma solidity >=0.4.22 <0.7.0;

contract Voting {

    mapping (bytes32 => uint8) public votesReceived;

    bytes32[] public candidateList;

    constructor(bytes32[] memory candidateNames) public {
        candidateList = candidateNames;
    }

    function totalVotesFor(bytes32 candidate) view public returns (uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    function validCandidate(bytes32 candidate) view public returns (bool) {
        for(uint i = 0; i < candidateList.length; i++) {
            if (candidateList[i] == candidate) {
                return true;
            }
        }
        return false;
    }
}

上述智能合约实现了一个简单的投票系统。构造函数用于初始化候选人列表,通过 mapping 映射将候选人名称与其得票数建立关联。通过函数 totalVotesFor 可以返回指定候选人的当选票数,函数 voteForCandidate 可以将某位候选人的得票数加一,函数 validCandidate 用于验证候选人名称是否在候选人列表中。

这只是一个简单的 demo,实际应用的智能合约需要更加完善的逻辑和安全性检查。同时实际开发中还需要考虑 gas 费用、合约存储空间等问题。

Gas费用是以太坊网络中用于支付交易费用的一种计量单位,类似于比特币网络中的交易手续费。Gas本质上是以太坊网络中的计算资源,每一个操作都需要消耗一定的Gas,不同的操作需要消耗不同数量的Gas。例如,一个简单的转账交易需要消耗的Gas费用相对较低,而部署智能合约或执行复杂的智能合约操作需要消耗更多的Gas费用。

以太坊网络中的Gas价格是动态的,由市场供需关系决定,通常以Gwei为单位。Gwei是一种以Ether为基础单位的十亿分之一,因此1 Gwei = 0.000000001 Ether。当用户发起一笔交易时,需要指定所愿意支付的Gas价格(Gwei/Gas),以及愿意支付的Gas数量,这两个参数决定了交易的总费用。如果交易费用太低,可能会导致交易长时间无法被确认;如果交易费用过高,则会浪费用户的资金。

Gas费用的收取主要是为了防止恶意用户利用以太坊网络的计算资源进行攻击,同时也是为了激励矿工验证和打包交易,维护以太坊网络的正常运转。

以太坊区块包含以下属性:

区块头(Block Header):区块头是一个包含区块元数据的数据结构,包括了区块的版本号、难度值、时间戳、区块奖励、上一个区块的哈希值、默克尔根等信息。

交易记录(Transactions):交易记录是指在以太坊网络中发生的所有交易,包括转账交易、部署智能合约、调用智能合约等操作。

祖先区块哈希值(Parent Block Hash):指当前区块的前一个区块的哈希值,用于链接区块链中的每个区块。

默克尔根(Merkle Root):指区块中所有交易记录的哈希值所构成的默克尔树的根节点哈希值,用于验证区块中交易的完整性。

随机数(Nonce):是一个32位的随机数,用于挖矿计算区块的哈希值。

区块哈希值(Block Hash):是指整个区块的哈希值,由区块头和交易记录共同组成,用于验证区块的唯一性和完整性。

总之,以太坊区块包含区块头、交易记录、祖先区块哈希值、默克尔根、随机数和区块哈希值等属性,这些属性共同构成了以太坊区块链的数据结构。

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将不兼容的接口转换为另一个接口,以满足客户端的需求。在 Golang 中实现适配器模式可以使用接口和组合来实现。

下面是一个使用 Golang 实现适配器模式的示例代码:

package main

import "fmt"

type Target interface {
    Request()
}

type Adaptee struct {}

func (a *Adaptee) SpecificRequest() {
    fmt.Println("Adaptee.SpecificRequest()")
}

type Adapter struct {
    adaptee *Adaptee
}

func (a *Adapter) Request() {
    a.adaptee.SpecificRequest()
}

func main() {
    adaptee := &Adaptee{}
    adapter := &Adapter{adaptee}

    adapter.Request()
}

在上面的代码中,我们定义了一个 Target 接口,它包含一个 Request 方法,用于执行请求。我们还定义了一个 Adaptee 结构体,它包含一个 SpecificRequest 方法,用于执行特定的请求。

接着,我们定义了一个 Adapter 结构体,它包含一个指向 Adaptee 的指针,并实现了 Target 接口的 Request 方法。该方法会调用 Adaptee 的 SpecificRequest 方法,将不兼容的接口转换为 Target 接口。

最后,在 main 函数中,我们创建了一个 Adaptee 实例,并将其传递给 Adapter 实例。我们调用 adapter.Request() 方法,实际上是调用了 Adaptee.SpecificRequest() 方法,但由于适配器的存在,客户端无需直接调用 Adaptee 的方法,从而实现了接口的兼容。

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许动态地给一个对象添加新的功能,而无需修改其源代码。在 Golang 中实现装饰模式可以使用接口和组合来实现。

下面是一个使用 Golang 实现装饰模式的示例代码:

package main

import "fmt"

type Component interface {
    Operation()
}

type ConcreteComponent struct{}

func (c *ConcreteComponent) Operation() {
    fmt.Println("ConcreteComponent.Operation()")
}

type Decorator interface {
    Component
}

type ConcreteDecoratorA struct {
    component Component
}

func (d *ConcreteDecoratorA) Operation() {
    d.component.Operation()
    fmt.Println("ConcreteDecoratorA.Operation()")
}

type ConcreteDecoratorB struct {
    component Component
}

func (d *ConcreteDecoratorB) Operation() {
    d.component.Operation()
    fmt.Println("ConcreteDecoratorB.Operation()")
}

func main() {
    component := &ConcreteComponent{}

    decoratorA := &ConcreteDecoratorA{component}
    decoratorB := &ConcreteDecoratorB{decoratorA}

    decoratorB.Operation()
}

在上面的代码中,我们定义了一个 Component 接口,它包含一个 Operation 方法,用于执行操作。我们还定义了一个 ConcreteComponent 结构体,它实现了 Component 接口的 Operation 方法。

接着,我们定义了一个 Decorator 接口,它继承了 Component 接口,并定义了两个具体的装饰器类:ConcreteDecoratorA 和 ConcreteDecoratorB。这两个装饰器类都包含一个 component 成员变量,用于存储被装饰的组件对象。它们也都实现了 Operation 方法,该方法会先调用被装饰的组件对象的 Operation 方法,然后再执行自己的操作。

最后,在 main 函数中,我们创建了一个 ConcreteComponent 实例,并分别用 ConcreteDecoratorA 和 ConcreteDecoratorB 对其进行装饰。由于 ConcreteDecoratorA 和 ConcreteDecoratorB 都实现了 Component 接口,因此它们可以像 ConcreteComponent 一样被传递和使用。最终,我们调用 decoratorB.Operation() 方法,会先调用 ConcreteComponent.Operation() 方法,然后依次执行 ConcreteDecoratorA.Operation() 和 ConcreteDecoratorB.Operation() 方法。通过这种方式,我们可以动态地给一个对象添加新的功能,而无需修改其源代码。

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,其所有依赖对象都会自动得到通知并更新。在 Golang 中实现观察者模式可以使用接口和函数来实现。

下面是一个使用 Golang 实现观察者模式的示例代码:

package main

import (
    "fmt"
    "sync"
)

type Observer interface {
    Update(msg string)
}

type Subject struct {
    observers []Observer
    mutex     sync.Mutex
}

func (s *Subject) RegisterObserver(observer Observer) {
    s.mutex.Lock()
    defer s.mutex.Unlock()
    s.observers = append(s.observers, observer)
}

func (s *Subject) RemoveObserver(observer Observer) {
    s.mutex.Lock()
    defer s.mutex.Unlock()
    for i, o := range s.observers {
        if o == observer {
            s.observers = append(s.observers[:i], s.observers[i+1:]...)
            break
        }
    }
}

func (s *Subject) NotifyObservers(msg string) {
    s.mutex.Lock()
    defer s.mutex.Unlock()
    for _, observer := range s.observers {
        observer.Update(msg)
    }
}

type ConcreteObserver1 struct{}

func (o *ConcreteObserver1) Update(msg string) {
    fmt.Println("ConcreteObserver1 received message:", msg)
}

type ConcreteObserver2 struct{}

func (o *ConcreteObserver2) Update(msg string) {
    fmt.Println("ConcreteObserver2 received message:", msg)
}

func main() {
    subject := &Subject{}
    observer1 := &ConcreteObserver1{}
    observer2 := &ConcreteObserver2{}

    subject.RegisterObserver(observer1)
    subject.RegisterObserver(observer2)

    subject.NotifyObservers("Hello World!")

    subject.RemoveObserver(observer2)

    subject.NotifyObservers("Goodbye World!")
}

在上面的代码中,我们定义了一个 Observer 接口,它包含一个 Update 方法,用于接收通知。我们还定义了一个 Subject 结构体,它包含一个 observers 切片用于存储观察者对象,并使用 sync.Mutex 来保证线程安全。

在 Subject 结构体中,我们定义了三个方法:RegisterObserver、RemoveObserver 和 NotifyObservers。RegisterObserver 方法用于注册观察者对象,RemoveObserver 方法用于移除观察者对象,NotifyObservers 方法用于通知所有观察者对象。

接下来,我们定义了两个具体的观察者类:ConcreteObserver1 和 ConcreteObserver2,它们实现了 Observer 接口的 Update 方法,用于接收通知并输出消息。

最后,在 main 函数中,我们创建了一个 Subject 实例和两个观察者实例,并分别调用 RegisterObserver 方法来注册观察者对象。然后,我们调用 NotifyObservers 方法来通知所有观察者对象,并输出相应的消息。接着,我们调用 RemoveObserver 方法来移除一个观察者对象,再次调用 NotifyObservers 方法来

工厂模式(Factory Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但将具体的对象创建延迟到子类中。在 Golang 中实现工厂模式通常使用函数来实现。

下面是一个使用 Golang 实现工厂模式的示例代码:

package main

import "fmt"

type Product interface {
    GetName() string
}

type ProductA struct{}

func (p *ProductA) GetName() string {
    return "Product A"
}

type ProductB struct{}

func (p *ProductB) GetName() string {
    return "Product B"
}

func CreateProduct(name string) Product {
    switch name {
    case "A":
        return &ProductA{}
    case "B":
        return &ProductB{}
    default:
        return nil
    }
}

func main() {
    productA := CreateProduct("A")
    fmt.Println(productA.GetName())

    productB := CreateProduct("B")
    fmt.Println(productB.GetName())
}

在上面的代码中,我们定义了一个 Product 接口,它包含一个 GetName 方法,用于获取产品名称。接下来,我们定义了两个具体的产品类:ProductA 和 ProductB,它们实现了 Product 接口的 GetName 方法。

我们还定义了一个 CreateProduct 函数,该函数根据传入的产品名称来创建具体的产品实例。在 CreateProduct 函数中,我们使用 switch 语句根据产品名称来创建相应的产品实例。

最后,在 main 函数中,我们分别使用 CreateProduct 函数来创建 ProductA 和 ProductB 实例,并输出它们的名称。可以看到,我们只需要传入相应的产品名称,就可以创建相应的产品实例,而无需关心具体的产品实现细节。这正是工厂模式的优势所在,它将对象的创建与使用代码分离开来,使得客户端代码更加简洁和易于维护。

单例模式(Singleton Pattern)是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在 Golang 中实现单例模式可以使用 sync 包提供的 Once 和 Mutex 来实现。

下面是一个使用 Golang 实现单例模式的示例代码:

package main

import (
    "fmt"
    "sync"
)

type Singleton struct {
    data string
}

var instance *Singleton
var once sync.Once

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{"Hello World!"}
    })
    return instance
}

func main() {
    s1 := GetInstance()
    s2 := GetInstance()

    if s1 == s2 {
        fmt.Println("Same instance")
    } else {
        fmt.Println("Different instance")
    }
}

在上面的代码中,我们定义了一个 Singleton 结构体,该结构体包含一个 data 字段。我们还定义了一个全局变量 instance,用于存储 Singleton 的唯一实例。

在 GetInstance 函数中,我们使用 sync.Once 来保证 instance 只被初始化一次。sync.Once 会在第一次调用 Do 方法时执行指定的函数,后续调用将被忽略。因此,只要我们通过 GetInstance 方法获取 instance,就可以保证 Singleton 的唯一性。

最后,在 main 函数中,我们分别使用 GetInstance 方法获取 Singleton 实例,并比较它们的地址是否相同。如果相同,则说明它们是同一个实例;否则,它们是不同的实例。