Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Virtual channel watching and dispute test (Last part of large Virtual Channel PR) #83

Merged
merged 9 commits into from
Jul 8, 2021
5 changes: 5 additions & 0 deletions backend/ethereum/channel/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ var (
abiParams abi.Type
abiState abi.Type
abiProgress abi.Method
abiRegister abi.Method
)

func init() {
Expand All @@ -74,6 +75,10 @@ func init() {
if abiProgress, ok = adj.Methods["progress"]; !ok {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
panic("Could not find method progress in adjudicator contract.")
}

if abiRegister, ok = adj.Methods["register"]; !ok {
panic("Could not find method register in adjudicator contract.")
}
}

// Backend implements the interface defined in channel/Backend.go.
Expand Down
83 changes: 70 additions & 13 deletions backend/ethereum/channel/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"

Expand Down Expand Up @@ -104,6 +105,7 @@ evloop:

func (r *RegisteredSub) processNext(ctx context.Context, a *Adjudicator, _next *subscription.Event) (err error) {
next, ok := _next.Data.(*adjudicator.AdjudicatorChannelUpdate)
next.Raw = _next.Log
if !ok {
log.Panicf("unexpected event type: %T", _next.Data)
}
Expand All @@ -115,7 +117,7 @@ func (r *RegisteredSub) processNext(ctx context.Context, a *Adjudicator, _next *
// if newer version or same version and newer timeout, replace
if current.Version() < next.Version || current.Version() == next.Version && currentTimeout.Time < next.Timeout {
var e channel.AdjudicatorEvent
e, err = a.convertEvent(ctx, next, _next.Log.TxHash)
e, err = a.convertEvent(ctx, next)
if err != nil {
return
}
Expand All @@ -126,7 +128,7 @@ func (r *RegisteredSub) processNext(ctx context.Context, a *Adjudicator, _next *
}
default: // next-channel is empty
var e channel.AdjudicatorEvent
e, err = a.convertEvent(ctx, next, _next.Log.TxHash)
e, err = a.convertEvent(ctx, next)
if err != nil {
return
}
Expand Down Expand Up @@ -161,14 +163,40 @@ func (r *RegisteredSub) Err() error {
return <-r.err
}

func (a *Adjudicator) convertEvent(ctx context.Context, e *adjudicator.AdjudicatorChannelUpdate, txHash common.Hash) (channel.AdjudicatorEvent, error) {
func (a *Adjudicator) convertEvent(ctx context.Context, e *adjudicator.AdjudicatorChannelUpdate) (channel.AdjudicatorEvent, error) {
base := channel.NewAdjudicatorEventBase(e.ChannelID, NewBlockTimeout(a.ContractInterface, e.Timeout), e.Version)
switch e.Phase {
case phaseDispute:
return &channel.RegisteredEvent{AdjudicatorEventBase: *base}, nil
args, err := a.fetchRegisterCallData(ctx, e.Raw.TxHash)
if err != nil {
return nil, errors.WithMessage(err, "fetching call data")
}

ch, ok := args.get(e.ChannelID)
if !ok {
return nil, errors.Errorf("channel not found in calldata: %v", e.ChannelID)
}

var app channel.App
var zeroAddress common.Address
if ch.Params.App == zeroAddress {
matthiasgeihs marked this conversation as resolved.
Show resolved Hide resolved
app = channel.NoApp()
matthiasgeihs marked this conversation as resolved.
Show resolved Hide resolved
} else {
app, err = channel.Resolve(wallet.AsWalletAddr(ch.Params.App))
if err != nil {
return nil, err
}
}
state := FromEthState(app, &ch.State)

return &channel.RegisteredEvent{
AdjudicatorEventBase: *base,
State: &state,
Sigs: ch.Sigs,
}, nil

case phaseForceExec:
args, err := a.fetchProgressCallData(ctx, txHash)
args, err := a.fetchProgressCallData(ctx, e.Raw.TxHash)
if err != nil {
return nil, errors.WithMessage(err, "fetching call data")
}
Expand Down Expand Up @@ -200,24 +228,53 @@ type progressCallData struct {
}

func (a *Adjudicator) fetchProgressCallData(ctx context.Context, txHash common.Hash) (*progressCallData, error) {
var args progressCallData
err := a.fetchCallData(ctx, txHash, abiProgress, &args)
return &args, errors.WithMessage(err, "fetching call data")
}

type registerCallData struct {
Channel adjudicator.AdjudicatorSignedState
SubChannels []adjudicator.AdjudicatorSignedState
}

func (args *registerCallData) get(id channel.ID) (*adjudicator.AdjudicatorSignedState, bool) {
ch := &args.Channel
if ch.State.ChannelID == id {
return ch, true
}
for _, ch := range args.SubChannels {
if ch.State.ChannelID == id {
return &ch, true
}
}
return nil, false
}

func (a *Adjudicator) fetchRegisterCallData(ctx context.Context, txHash common.Hash) (*registerCallData, error) {
var args registerCallData
err := a.fetchCallData(ctx, txHash, abiRegister, &args)
return &args, errors.WithMessage(err, "fetching call data")
}

func (a *Adjudicator) fetchCallData(ctx context.Context, txHash common.Hash, method abi.Method, args interface{}) error {
tx, _, err := a.ContractBackend.TransactionByHash(ctx, txHash)
if err != nil {
err = cherrors.CheckIsChainNotReachableError(err)
return nil, errors.WithMessage(err, "getting transaction")
return errors.WithMessage(err, "getting transaction")
}

argsData := tx.Data()[len(abiProgress.ID):]
argsData := tx.Data()[len(method.ID):]
matthiasgeihs marked this conversation as resolved.
Show resolved Hide resolved

argsI, err := abiProgress.Inputs.UnpackValues(argsData)
argsI, err := method.Inputs.UnpackValues(argsData)
if err != nil {
return nil, errors.WithMessage(err, "unpacking")
return errors.WithMessage(err, "unpacking")
}

var args progressCallData
err = abiProgress.Inputs.Copy(&args, argsI)
err = method.Inputs.Copy(args, argsI)
if err != nil {
return nil, errors.WithMessage(err, "copying into struct")
return errors.WithMessage(err, "copying into struct")
}

return &args, nil
return nil
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
}
17 changes: 16 additions & 1 deletion channel/adjudicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ type (
// registration on the blockchain.
RegisteredEvent struct {
AdjudicatorEventBase // Channel ID and Refutation phase timeout
State *State
Sigs []wallet.Sig
}

// ConcludedEvent signals channel conclusion.
Expand Down Expand Up @@ -191,13 +193,15 @@ func (b AdjudicatorEventBase) Timeout() Timeout { return b.TimeoutV }
func (b AdjudicatorEventBase) Version() uint64 { return b.VersionV }

// NewRegisteredEvent creates a new RegisteredEvent.
func NewRegisteredEvent(id ID, timeout Timeout, version uint64) *RegisteredEvent {
func NewRegisteredEvent(id ID, timeout Timeout, version uint64, state *State, sigs []wallet.Sig) *RegisteredEvent {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
return &RegisteredEvent{
AdjudicatorEventBase: AdjudicatorEventBase{
IDV: id,
TimeoutV: timeout,
VersionV: version,
},
State: state,
Sigs: sigs,
}
}

Expand All @@ -214,6 +218,17 @@ func NewProgressedEvent(id ID, timeout Timeout, state *State, idx Index) *Progre
}
}

// NewConcludedEvent creates a new ConcludedEvent.
func NewConcludedEvent(id ID, timeout Timeout, version uint64) *ConcludedEvent {
return &ConcludedEvent{
AdjudicatorEventBase: AdjudicatorEventBase{
IDV: id,
TimeoutV: timeout,
VersionV: version,
},
}
}

// ElapsedTimeout is a Timeout that is always elapsed.
type ElapsedTimeout struct{}

Expand Down
Loading