The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/pow/api.go

132 lines
2.8 KiB

6 years ago
// Create and fulfill proof of work requests.
package pow
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
)
type Algorithm string
const (
Sha2BDay Algorithm = "sha2bday"
)
// Represents a proof-of-work request.
type Request struct {
// The requested algorithm
Alg Algorithm
// The requested difficulty
Difficulty uint32
// Nonce to diversify the request
Nonce []byte
}
// Represents a completed proof-of-work
type Proof struct {
buf []byte
}
// Convenience function to create a new sha3bday proof-of-work request
// as a string
func NewRequest(difficulty uint32, nonce []byte) string {
req := Request{
Difficulty: difficulty,
Nonce: nonce,
Alg: Sha2BDay,
}
s, _ := req.MarshalText()
return string(s)
}
func (proof Proof) MarshalText() ([]byte, error) {
return []byte(base64.RawStdEncoding.EncodeToString(proof.buf)), nil
}
func (proof *Proof) UnmarshalText(buf []byte) error {
var err error
proof.buf, err = base64.RawStdEncoding.DecodeString(string(buf))
return err
}
func (req Request) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%s-%d-%s",
req.Alg,
req.Difficulty,
string(base64.RawStdEncoding.EncodeToString(req.Nonce)))), nil
}
func (req *Request) UnmarshalText(buf []byte) error {
bits := strings.SplitN(string(buf), "-", 3)
if len(bits) != 3 {
return fmt.Errorf("There should be two dashes in a PoW request")
}
alg := Algorithm(bits[0])
if alg != Sha2BDay {
return fmt.Errorf("%s: unsupported algorithm", bits[0])
}
req.Alg = alg
diff, err := strconv.Atoi(bits[1])
if err != nil {
return err
}
req.Difficulty = uint32(diff)
req.Nonce, err = base64.RawStdEncoding.DecodeString(bits[2])
if err != nil {
return err
}
return nil
}
// Convenience function to check whether a proof of work is fulfilled
func Check(request, proof string, data []byte) (bool, error) {
var req Request
var prf Proof
err := req.UnmarshalText([]byte(request))
if err != nil {
return false, err
}
err = prf.UnmarshalText([]byte(proof))
if err != nil {
return false, err
}
return prf.Check(req, data), nil
}
// Fulfil the proof-of-work request.
func (req *Request) Fulfil(data []byte) Proof {
switch req.Alg {
case Sha2BDay:
return Proof{fulfilSha2BDay(req.Nonce, req.Difficulty, data)}
default:
panic("No such algorithm")
}
}
// Convenience function to fulfil the proof of work request
func Fulfil(request string, data []byte) (string, error) {
var req Request
err := req.UnmarshalText([]byte(request))
if err != nil {
return "", err
}
proof := req.Fulfil(data)
s, _ := proof.MarshalText()
return string(s), nil
}
// Check whether the proof is ok
func (proof *Proof) Check(req Request, data []byte) bool {
switch req.Alg {
case Sha2BDay:
return checkSha2BDay(proof.buf, req.Nonce, data, req.Difficulty)
default:
panic("No such algorithm")
}
}